GROUP_CONCAT в подзапросе на основе указанных значений - PullRequest
0 голосов
/ 23 апреля 2019

Таблица пользователей:

ID       InstructionSets
 1        123,124

Таблица набора инструкций:

ID       Name
 123      Learning SQL
 124      Learning More SQL  

Желаемый результат запроса:

UserID    SetID             SetNames
 1         123,124           Learning SQL,Learning More SQL

Текущий SQL:

SELECT U1.ID AS UserID, U1.InstructionSets AS SetID, (
    SELECT GROUP_CONCAT(Name ORDER BY FIELD(I1.ID, U1.InstructionSets))
    FROM Instructions I1
    WHERE I1.ID IN (U1.InstructionSets)
) AS SetName
FROM Users U1
WHERE `ID` = 1

РЕЗУЛЬТАТ

UserID   SetID             SetNames
 1        123,124           Learning SQL

Как и ожидалось, если я удалю предложение WHERE в подзапросе, появятся все SetNames; но если я укажу необходимые идентификаторы, я получу только имя, связанное с первым идентификатором. Очевидно, мне также нужно получить SetNames в том же порядке, что и идентификаторы. Следовательно, ORDER BY в GROUP_CONCAT.

Также:

  • Есть ли лучший подход (кроме хранения назначений пользовательских команд в отдельной таблице - излишнее для этого приложения)? Не могу увидеть, как использовать JOIN в этом ситуация.
  • Есть ли лучшее название для этого вопроса?

Спасибо.

Ответы [ 2 ]

1 голос
/ 23 апреля 2019

Мы можем использовать FIND_IN_SET(). В этом контексте использование функции FIELD() не имеет смысла.

Мы также можем использовать FIND_IN_SET() в предложении WHERE. (Функция возвращает 0, если строка не найдена в списке строк.)

, например

SELECT u.id               AS userid
     , u.instructionsets  AS setid
     , ( SELECT GROUP_CONCAT(i.name ORDER BY FIND_IN_SET(i.id, u.instructionsets))
           FROM `Instructions` i
          WHERE FIND_IN_SET(i.id, u.instructionsets))
       ) AS setname
 FROM `Users` u
WHERE u.id = 1

Хранение разделенных запятыми списков - это anti-pattern ; отдельная таблица не излишняя.


Если предположить, что id уникален в таблице Users, мы можем выполнить операцию соединения с GROUP BY

SELECT u.id                   AS userid
     , MIN(u.instructionsets) AS setid
     , GROUP_CONCAT(i.name ORDER BY FIND_IN_SET(i.id, u.instructionsets))) AS setname
 FROM `Users` u
 LEFT
 JOIN `Instructions` i
   ON FIND_IN_SET(i.id, u.instructionsets)
WHERE u.id = 1
GROUP BY u.id 
1 голос
/ 23 апреля 2019

Вместо IN используйте оператор LIKE следующим образом:

SELECT U1.ID AS UserID, U1.InstructionSets AS SetID, (
    SELECT GROUP_CONCAT(Name ORDER BY (I1.ID))
    FROM Instructions I1
    WHERE CONCAT(',', U1.InstructionSets, ',') LIKE concat('%,', I1.ID, ',%')
) AS SetName
FROM Users U1
WHERE `ID` = 1

См. Демоверсию .Результаты:

| UserID | SetID   | SetName                        |
| ------ | ------- | ------------------------------ |
| 1      | 123,124 | Learning SQL,Learning More SQL |
...