Сортировка с управлением выбора поля
Постановка задачи
Есть следующий набор данных:
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 |
Комментарии:
- Выбор производим только по записям у которых tag_1 или tag_2 равны 1. Для этого было добавлено соответствующее условие в WHERE.
- 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.
- Порядок указания WHEN важен. Если первое выражение WHEN поставить последним, то порядок вывода записей изменится.
- Выражение id ASC было добавлено для уточнения порядка сортировки тех записей, у которых значения weight (tag_1_weight или tag_2_weight) совпадают (1-я и 3-я записи).
- Также в CASE можно добавить ELSE и соответственно обработать случаи не попавшие под условия WHEN. Т.к. все неподходящие записи в данном примере (4-я запись) были отсечены в WHERE, то ELSE не понадобился. Если ELSE не указать, то в случае его срабатывания будет возвращен NULL.