从 table 获取以逗号分隔的一组值,其中另一个 table 的另一个参考值出现两次(或更多)
Get comma-separated set of values from table where another reference value on another table appears twice (or more)
假设 SQL Server 2014 中的数据库设置如下:
DECLARE @MATERIAL TABLE (ID int, CODE varchar(30));
INSERT @MATERIAL (ID, CODE) VALUES
(1, 'D3033MBBY'),
(2, 'D3033MBTY'),
(3, '011130-01'),
(4, '011130-04C'),
(5, '021002'),
(6, '021017-B'),
(7, '021134-01'),
(8, '021135-01'),
(9, '021955-01'),
(10, '3LS91101-550'),
(11, 'D3049MBRB'),
(12, 'EF0118'),
(13, 'FV8130'),
(14, 'FY7009'),
(15, 'H05802'),
(16, 'D3033MRTE');
DECLARE @SUBSTITUTE TABLE (ID int, ITEID int, SUBSTITUTECODE varchar(100));
INSERT @SUBSTITUTE (ID, ITEID, SUBSTITUTECODE) VALUES
(5232, 1, '191045762418'),
(5442, 2, '191045762418'),
(6435, 3, '5206432380030'),
(6573, 4, '5206432380030'),
(6582, 5, '5206432357131'),
(6683, 6, '5206432369486'),
(7332, 7, '5206432380610'),
(7482, 8, '5206432380818'),
(7721, 9, '5206432346029'),
(7831, 10, '5205172116350'),
(8034, 11, '191045480992'),
(8184, 12, '4061622759543'),
(8284, 13, '4062058577497'),
(8573, 14, '4064039588089'),
(9438, 15, '4064048672519'),
(9746, 16, '191045762418');
SELECT sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
GROUP BY sub.SUBSTITUTECODE
HAVING COUNT(sub.SUBSTITUTECODE) > 1;
我想创建一个将产生以下结果集的查询:
CODES
SUBSTITUTECODE
D3033MBBY,D3033MBTY,D3033MRTE
191045762418
011130-01,011130-04C
5206432380030
换句话说,我想在 @MATERIAL
中获得一组以逗号分隔的 CODE
,其中 [=41] 中的那些记录有重复的 SUBSTITUTECODE
引用=] @SUBSTITUTE
间接地,我可以通过以下查询找到与那些重复的 SUBSTITUTECODE
相对应的 CODE
:
SELECT prod.CODE, sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
WHERE sub.SUBSTITUTECODE IN (SELECT sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
GROUP BY sub.SUBSTITUTECODE
HAVING COUNT(sub.SUBSTITUTECODE) > 1)
可以找到上述案例的工作 fiddle here。
请注意,此场景的完整案例在 SQL Server 2014 上运行。
TIA
由于您使用的是 SQL Server 2014,因此您无法使用 STRING_AGG()
这是使用FOR XML PATH
的解决方案
WITH CTE AS
(
SELECT prod.CODE, sub.SUBSTITUTECODE,
c = COUNT(*) OVER (PARTITION BY sub.SUBSTITUTECODE)
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
),
CTE2 AS
(
SELECT *
FROM CTE
WHERE c > 1
)
SELECT STUFF((SELECT ',' + CODE
FROM CTE2 x
WHERE x.SUBSTITUTECODE = c.SUBSTITUTECODE
FOR XML PATH('')), 1, 1, ''),
SUBSTITUTECODE
FROM CTE2 c
GROUP BY SUBSTITUTECODE
开局不错 fiddle,谢谢!如果我们只是把你已有的东西放在 CTE 中,我们可以围绕它编写一个标准的字符串聚合:
;WITH subs AS
(
SELECT prod.CODE, sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
WHERE sub.SUBSTITUTECODE IN (SELECT sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
GROUP BY sub.SUBSTITUTECODE
HAVING COUNT(sub.SUBSTITUTECODE) > 1)
)
SELECT CODES = STUFF((SELECT ',' + CODE
FROM subs AS s2 WHERE s2.SUBSTITUTECODE = subs.SUBSTITUTECODE
FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)'),1,1,''),
SUBSTITUTECODE FROM subs
GROUP BY SUBSTITUTECODE;
但是我们可以稍微简化这段代码,最重要的是避免引用两个表两次,像这样:
;WITH subs AS
(
SELECT s.ITEID, s.SUBSTITUTECODE, m.CODE,
c = COUNT(*) OVER (PARTITION BY s.SUBSTITUTECODE)
FROM @SUBSTITUTE AS s
INNER JOIN @MATERIAL AS m
ON m.ID = s.ITEID
)
SELECT CODES = STUFF((SELECT ',' + CODE
FROM subs AS s2 WHERE s2.SUBSTITUTECODE = subs.SUBSTITUTECODE
FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)'),1,1,''),
SUBSTITUTECODE
FROM subs
WHERE c > 1
GROUP BY SUBSTITUTECODE;
请注意,在更现代的 SQL Server (2017+) 版本中,STRING_AGG()
使这更容易:
SELECT CODES = STRING_AGG(m.CODE, ','), s.SUBSTITUTECODE
FROM @SUBSTITUTE AS s
INNER JOIN @MATERIAL AS m
ON m.ID = s.ITEID
GROUP BY s.SUBSTITUTECODE
HAVING COUNT(*) > 1;
假设 SQL Server 2014 中的数据库设置如下:
DECLARE @MATERIAL TABLE (ID int, CODE varchar(30));
INSERT @MATERIAL (ID, CODE) VALUES
(1, 'D3033MBBY'),
(2, 'D3033MBTY'),
(3, '011130-01'),
(4, '011130-04C'),
(5, '021002'),
(6, '021017-B'),
(7, '021134-01'),
(8, '021135-01'),
(9, '021955-01'),
(10, '3LS91101-550'),
(11, 'D3049MBRB'),
(12, 'EF0118'),
(13, 'FV8130'),
(14, 'FY7009'),
(15, 'H05802'),
(16, 'D3033MRTE');
DECLARE @SUBSTITUTE TABLE (ID int, ITEID int, SUBSTITUTECODE varchar(100));
INSERT @SUBSTITUTE (ID, ITEID, SUBSTITUTECODE) VALUES
(5232, 1, '191045762418'),
(5442, 2, '191045762418'),
(6435, 3, '5206432380030'),
(6573, 4, '5206432380030'),
(6582, 5, '5206432357131'),
(6683, 6, '5206432369486'),
(7332, 7, '5206432380610'),
(7482, 8, '5206432380818'),
(7721, 9, '5206432346029'),
(7831, 10, '5205172116350'),
(8034, 11, '191045480992'),
(8184, 12, '4061622759543'),
(8284, 13, '4062058577497'),
(8573, 14, '4064039588089'),
(9438, 15, '4064048672519'),
(9746, 16, '191045762418');
SELECT sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
GROUP BY sub.SUBSTITUTECODE
HAVING COUNT(sub.SUBSTITUTECODE) > 1;
我想创建一个将产生以下结果集的查询:
CODES | SUBSTITUTECODE |
---|---|
D3033MBBY,D3033MBTY,D3033MRTE | 191045762418 |
011130-01,011130-04C | 5206432380030 |
换句话说,我想在 @MATERIAL
中获得一组以逗号分隔的 CODE
,其中 [=41] 中的那些记录有重复的 SUBSTITUTECODE
引用=] @SUBSTITUTE
间接地,我可以通过以下查询找到与那些重复的 SUBSTITUTECODE
相对应的 CODE
:
SELECT prod.CODE, sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
WHERE sub.SUBSTITUTECODE IN (SELECT sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
GROUP BY sub.SUBSTITUTECODE
HAVING COUNT(sub.SUBSTITUTECODE) > 1)
可以找到上述案例的工作 fiddle here。
请注意,此场景的完整案例在 SQL Server 2014 上运行。
TIA
由于您使用的是 SQL Server 2014,因此您无法使用 STRING_AGG()
这是使用FOR XML PATH
WITH CTE AS
(
SELECT prod.CODE, sub.SUBSTITUTECODE,
c = COUNT(*) OVER (PARTITION BY sub.SUBSTITUTECODE)
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
),
CTE2 AS
(
SELECT *
FROM CTE
WHERE c > 1
)
SELECT STUFF((SELECT ',' + CODE
FROM CTE2 x
WHERE x.SUBSTITUTECODE = c.SUBSTITUTECODE
FOR XML PATH('')), 1, 1, ''),
SUBSTITUTECODE
FROM CTE2 c
GROUP BY SUBSTITUTECODE
开局不错 fiddle,谢谢!如果我们只是把你已有的东西放在 CTE 中,我们可以围绕它编写一个标准的字符串聚合:
;WITH subs AS
(
SELECT prod.CODE, sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
WHERE sub.SUBSTITUTECODE IN (SELECT sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
GROUP BY sub.SUBSTITUTECODE
HAVING COUNT(sub.SUBSTITUTECODE) > 1)
)
SELECT CODES = STUFF((SELECT ',' + CODE
FROM subs AS s2 WHERE s2.SUBSTITUTECODE = subs.SUBSTITUTECODE
FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)'),1,1,''),
SUBSTITUTECODE FROM subs
GROUP BY SUBSTITUTECODE;
但是我们可以稍微简化这段代码,最重要的是避免引用两个表两次,像这样:
;WITH subs AS
(
SELECT s.ITEID, s.SUBSTITUTECODE, m.CODE,
c = COUNT(*) OVER (PARTITION BY s.SUBSTITUTECODE)
FROM @SUBSTITUTE AS s
INNER JOIN @MATERIAL AS m
ON m.ID = s.ITEID
)
SELECT CODES = STUFF((SELECT ',' + CODE
FROM subs AS s2 WHERE s2.SUBSTITUTECODE = subs.SUBSTITUTECODE
FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)'),1,1,''),
SUBSTITUTECODE
FROM subs
WHERE c > 1
GROUP BY SUBSTITUTECODE;
请注意,在更现代的 SQL Server (2017+) 版本中,STRING_AGG()
使这更容易:
SELECT CODES = STRING_AGG(m.CODE, ','), s.SUBSTITUTECODE
FROM @SUBSTITUTE AS s
INNER JOIN @MATERIAL AS m
ON m.ID = s.ITEID
GROUP BY s.SUBSTITUTECODE
HAVING COUNT(*) > 1;