В MySQL, скажем, у меня есть следующая таблица (называемая workers
):
| id | specialty | status | name
| :- | :-------- | :--------- | :--- |
| 1 | Bricks | Unemployed | Joe
| 2 | Bricks | Employed | Eric
| 3 | Bricks | Contracted | Bob
| 4 | Tiles | Employed | Dylan
| 5 | Tiles | Contracted | James
В моем запросе, скажем, я хочу найти потенциального человека на новую работу. Таким образом, я хотел бы сначала найти, кто является Unemployed
, если никто не является Unemployed
, то кто является только Contracted
, и если никто не является Contracted
, то, по крайней мере, кто является Employed
.
Это будет GROUP BY
specialty
. Единственные методы, которые я мог выяснить, это либо сложные подзапросы, либо наборы UNION
s (или оба). Я также попытался GROUP_CONCAT
, однако это не сработало (или я сделал это неправильно). Поиск в Google не дал никаких результатов.
Другая идея - присвоить значение каждой категории, а затем выполнить подзапрос group-wise max/min
. Я пилотировал это, и это работает, однако кажется довольно грязным и определенно не нормализованным:
SELECT
`id`,
`name`,
`status`,
-- I haven't been able to figure out how to get rid of MIN from the actual select
-- statement except by wrapping this in another sub-query, which I'm not keen on
MIN(`priority`) AS `priority`
FROM workers
INNER JOIN (
SELECT 'Unemployed' AS `status`, 0 AS `priority` FROM dual UNION
SELECT 'Contracted' AS `status`, 1 AS `priority` FROM dual UNION
SELECT 'Employed' AS `status`, 2 AS `priority` FROM dual
) AS priorities USING (`status`)
GROUP BY `specialty`;
Я ищу более стандартный, эффективный, нормализованный или универсальный способ сделать это.
Обновление :
Дополнительным методом, который я мог бы использовать, является выражение CASE
в предложении SELECT
оператора. Это было бы, если бы мне пришлось нормализовать столбец status
, используя отношение внешнего ключа или другую связанную таблицу:
Новая таблица с именем statuses
| id | status |
| :- | :------------- |
| 1 | Employed |
| 2 | Contracted |
| 3 | Unemployed |
| 4 | Not contracted |
Различия: 'Not Contracted'
- это новый статус, и моя таблица workers
теперь сохраняет внешний ключ для новой таблицы статусов.
Тогда мой SQL будет:
SELECT
`id`,
`name`,
statuses.status,
MIN(`priority`) AS `priority`
FROM workers
INNER JOIN (
SELECT
`id`,
`status`,
CASE
-- currently uses text in `status`,
-- could also explicitly use `id`
WHEN `status` IN ('Unemployed', 'Not Contracted') THEN 0
WHEN `status` = 'Contracted' THEN 1
WHEN `status` = 'Employed' THEN 2
ELSE 3
END AS `priority`
FROM statuses
) AS statuses ON workers.status = statuses.id
GROUP BY `specialty`;
Примечание: Вы можете подумать - почему бы не поместить priority
в таблицу статусов? Причина, по которой я этого не делаю, заключается в том, что приоритет меняется в зависимости от необходимых данных / цели создаваемого отчета.
Потенциально это более чистое решение (для тех времен, когда связанные данные расставить приоритеты против находится в другой таблице). Опять же, я ищу более стандартный, эффективный, нормализованный или универсальный способ сделать это. Кроме того, если есть больше способов, это можно настроить для пользовательского ввода / переменных.