Сортировка с управлением выбора поля

Постановка задачи

Есть следующий набор данных:

id tag_1 tag_1_weight tag_2 tag_2_weight
1 1 100 2 150
2 2 400 1 200
3 2 200 1 100
4 3 600 2 500
5 1 300 1 125

Требуется выбрать все записи с tag_1 или tag_2 равными 1, но при этом данные должны быть отсортированы выборочно по полям tag_1_weight или tag_2_weight по возрастанию (или убыванию). Поле tag_1_weight соответствует полю tag_1, а tag_2_weight — tag_2.

Подготовка

DROP TABLE IF EXISTS `table`;

CREATE TABLE `table` (
	id INT,
	tag_1 INT,
	tag_1_weight INT,
	tag_2 INT,
	tag_2_weight INT
);

INSERT INTO `table` VALUES
(1, 1, 100, 2, 150),
(2, 2, 400, 1, 200),
(3, 2, 200, 1, 100),
(4, 3, 600, 2, 500),
(5, 1, 300, 1, 125);

Решение

Для решения данной задачи воспользуемся выражением CASE. Будем использовать второй вариант синтаксиса.

CASE
	WHEN condition THEN statement
	[WHEN condition THEN statement]
	[ELSE statement]
END
SELECT *
FROM `table`
WHERE tag_1 = 1 OR tag_2 = 1
ORDER BY
	CASE
		WHEN tag_1 = tag_2 THEN IF(tag_1_weight > tag_2_weight, tag_2_weight, tag_1_weight)
		WHEN tag_1 = 1 THEN tag_1_weight
		WHEN tag_2 = 1 THEN tag_2_weight
	END ASC,
	id ASC;

Результат запроса:

id tag_1 tag_1_weight tag_2 tag_2_weight
1 1 100 2 150
3 2 200 1 100
5 1 300 1 125
2 2 400 1 200

Комментарии:

  1. Выбор производим только по записям у которых tag_1 или tag_2 равны 1. Для этого было добавлено соответствующее условие в WHERE.
  2. tag_1 и tag_2 могут быть одновременно равны 1 (5-я запись). Этот случай нужно обработать дополнительно. Если требуется отсортировать CASE по возрастанию (CASE … END ASC), то из двух значений tag_1_weight и tag_2_weight надо выбрать минимальное, т.е. IF(tag_1_weight > tag_2_weight, tag_2_weight, tag_1_weight). Если требуется сортировка по убыванию (CASE ... END DESC), то надо выбирать максимальное, т.е. IF(tag_1_weight > tag_2_weight, tag_1_weight, tag_2_weight). Эта обработка была добавлена в первый WHEN.
  3. Порядок указания WHEN важен. Если первое выражение WHEN поставить последним, то порядок вывода записей изменится.
  4. Выражение id ASC было добавлено для уточнения порядка сортировки тех записей, у которых значения weight (tag_1_weight или tag_2_weight) совпадают (1-я и 3-я записи).
  5. Также в CASE можно добавить ELSE и соответственно обработать случаи не попавшие под условия WHEN. Т.к. все неподходящие записи в данном примере (4-я запись) были отсечены в WHERE, то ELSE не понадобился. Если ELSE не указать, то в случае его срабатывания будет возвращен NULL.
Похожие записи