我有一个包含许多集合的表(@ t1)。我想在@ t1中找到@ t2的完美匹配。
在此示例中,所需结果为1.
(Set 1匹配完美,set 2包含三个元素,而@ t2只包含两个元素,set 3包含的元素少于@ t2,set 4包含@ t2中不允许的NULL元素,set 5包含正确的数字但元素之一并不相等。)
DECLARE @t1 TABLE (id INT, data INT);
DECLARE @t2 TABLE (data INT PRIMARY KEY);
INSERT INTO @t1 (id, data)
VALUES
(1, 1),
(1, 2),
(2, 1),
(2, 2),
(2, 3),
(3, 1),
(4, NULL),
(4, NULL),
(5, 1),
(5, 3);
INSERT @t2 (data)
VALUES
(1),
(2);
我有一个可能正在完成工作的查询,但它看起来有点可怜我。
WITH t1 AS
(
SELECT id, data
FROM @t1
WHERE data IS NOT NULL
),
t1_count AS
(
SELECT id, RCount = COUNT(*)
FROM @t1
WHERE data IS NOT NULL
GROUP BY id
)
SELECT t1.id
FROM t1
JOIN t1_count ON t1.id = t1_count.id
FULL JOIN @t2 t2 ON t1.data = t2.data
WHERE t1_count.RCount = (SELECT RCount = COUNT(*) FROM @t2)
GROUP BY t1.id
HAVING COUNT(t1.data) = COUNT(t2.data);
编辑(GarethD'评论):
WITH t1 AS
(
SELECT
id,
data,
RCount = COUNT(*) OVER(PARTITION BY id)
FROM @t1
WHERE data IS NOT NULL
)
SELECT t1.id
FROM t1
FULL JOIN @t2 t2 ON t1.data = t2.data
WHERE t1.RCount = (SELECT RCount = COUNT(*) FROM @t2)
GROUP BY t1.id
HAVING COUNT(t1.data) = COUNT(t2.data);
答案 0 :(得分:4)
您想要的是完全Relational Division 。遗憾的是,SQL Server没有本机运算符,但它是一个记录良好的问题。一个可能的解决方案(来自an article by Joe Celko的想法)是比较计数,类似于您已经在做的事情:
SELECT t1.id
FROM @t1 AS t1 LEFT JOIN @t2 AS t2 ON t1.data = t2.data
GROUP BY t1.id
HAVING COUNT(t1.data) = (SELECT COUNT(data) FROM @t2)
AND COUNT(t2.data) = (SELECT COUNT(data) FROM @t2);
请注意,两个HAVING
比较都是必要的:
t2.data
将通过LEFT JOIN为NULL。回想一下,COUNT(x)只计算x的非空值。答案 1 :(得分:0)
解决此问题的一种方法是连接每个ID
的值和第二个表中的值并进行比较。您也可以应用连接的顺序。
例如,以下代码将连接第二个表中的值:
DECLARE @Test VARCHAR(MAX) = (
SELECT ',' + data
FROM @t2
ORDER BY data
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)')
SELECT @test -- 12
以下将对第一个表执行此操作:
SELECT id
,(
SELECT ',' + data
FROM @t1
WHERE id = t1.id
ORDER BY data
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)')
FROM @t1 t1
GROUP BY id
您可以使用where
子句轻松过滤值:
SELECT *
FROM
(
SELECT id
,(
SELECT ',' + data
FROM @t1
WHERE id = t1.id
ORDER BY data
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)') data
FROM @t1 t1
GROUP BY id
) DS
WHERE data = @test
T-SQL
中的连接值看起来不nice
,但您可以使用SQL CLR
应用聚合并置函数(请查看此article),您将得到类似的内容然后:
DECLARE @Test VARCHAR(MAX);
SELECT @Test = [dbo].[Concatenate] (data)
FROM @t2
SELECT id
FROM @t1
GROUP BY id
HAVING [dbo].[Concatenate] (data) = @Test
答案 2 :(得分:0)
也许这对你来说似乎更简单?
SELECT dat.id
FROM (
SELECT t1.id as id, t2.data as data2, sourcecount.cnt as scnt, dataCount.cnt as dcnt, COUNT(*) OVER(PARTITION BY t1.id) as mcnt
FROM @t1 as t1
INNER JOIN (SELECT t.id, COUNT(*) as cnt FROM @t1 as t GROUP BY t.id) as sourceCount
ON t1.id = sourceCount.id
INNER JOIN @t2 as t2
ON t1.data = t2.data
CROSS JOIN (SELECT COUNT(*) as cnt FROM @t2) as dataCount
) as dat
WHERE dat.scnt = dat.dcnt AND dat.mcnt = dat.dcnt
GROUP BY dat.id
通过与您相同的执行计划产生,但可能更具可读性。
最好的问候,离子