GROUP_CONCAT in sub-query 基于指定值
GROUP_CONCAT in sub-query based on specified values
用户Table:
ID InstructionSets
1 123,124
指令集Table:
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
正如预期的那样,如果我删除 sub-query 中的 WHERE 子句,所有的 SetNames 都会出现;但是如果我指定所需的 ID,我只会得到与第一个 ID 关联的名称。显然,我还需要按照与 ID 相同的顺序获取 SetNames。因此 ORDER BY 在 GROUP_CONCAT.
另外:
- 是否有更好的方法(除了将用户指令集分配存储在单独的 table 中——对于此应用程序来说太过分了)?看不到如何在此使用 JOIN
情况。
- 这个问题有更好的标题吗?
谢谢。
像这样使用 LIKE 运算符而不是 IN:
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
参见demo。
结果:
| UserID | SetID | SetName |
| ------ | ------- | ------------------------------ |
| 1 | 123,124 | Learning SQL,Learning More SQL |
我们可以使用FIND_IN_SET()
。在这种情况下,使用 FIELD()
函数没有意义。
我们也可以在WHERE
子句中使用FIND_IN_SET()
。 (当在字符串列表中找不到该字符串时,函数 returns 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
存储逗号分隔列表是一种反模式;一个单独的 table 并不过分。
假设 id
在 Users
table 中是唯一的,我们可以使用 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
用户Table:
ID InstructionSets
1 123,124
指令集Table:
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
正如预期的那样,如果我删除 sub-query 中的 WHERE 子句,所有的 SetNames 都会出现;但是如果我指定所需的 ID,我只会得到与第一个 ID 关联的名称。显然,我还需要按照与 ID 相同的顺序获取 SetNames。因此 ORDER BY 在 GROUP_CONCAT.
另外:
- 是否有更好的方法(除了将用户指令集分配存储在单独的 table 中——对于此应用程序来说太过分了)?看不到如何在此使用 JOIN 情况。
- 这个问题有更好的标题吗?
谢谢。
像这样使用 LIKE 运算符而不是 IN:
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
参见demo。
结果:
| UserID | SetID | SetName |
| ------ | ------- | ------------------------------ |
| 1 | 123,124 | Learning SQL,Learning More SQL |
我们可以使用FIND_IN_SET()
。在这种情况下,使用 FIELD()
函数没有意义。
我们也可以在WHERE
子句中使用FIND_IN_SET()
。 (当在字符串列表中找不到该字符串时,函数 returns 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
存储逗号分隔列表是一种反模式;一个单独的 table 并不过分。
假设 id
在 Users
table 中是唯一的,我们可以使用 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