我有两个关系,a
和b
,其属性由
CREATE TABLE a (id int, b_id int)
CREATE TABLE b (id int)
我可以假设a
中的所有值对和b
中的所有值都是唯一的,并且它们将基于SQL Server 2016数据库。
b
的给定元素定义了a.id
的子集,这些元素由相应的a.b_id
为给定值的元素给出,我的目标是生成所有这些元素的交集子集。
例如,假设a
包含六个值,
INSERT INTO a VALUES (1, 1), (1, 2), (1, 3), (2, 2), (3, 2), (3, 3)
然后预期结果将包括以下内容:
b: (1), (2), (3). Expected result: (1)
b: (1), (2). Expected result: (1)
b: (2). Expected result: (1), (2), (3)
b: (2), (3). Expected result: (1), (3)
b: [Empty]. Expected result: (1), (2), (3)
使用唯一性,对于非空b
,可以通过
SELECT a.id FROM a
JOIN b on a.b_id = b.id
GROUP BY a.id
HAVING COUNT(a.id) = (SELECT COUNT(*) FROM b)
但是这感觉很笨,因为SQL有一个INTERSECT
运算符随时可用,并且我要在LINQ中编写相同的查询,我只是简单地聚合交叉点。在空b
的情况下,如果没有将其视为特殊情况,它也无法产生所需的结果。
所以,问题变成:是否有一种更惯用的方式来执行上述查询,这也适用于琐碎的b
?
答案 0 :(得分:1)
您可以使用以下方法扩展您处理空集案例的方法:
SELECT a.id
FROM a
LEFT JOIN b on a.b_id = b.id
GROUP BY a.id
HAVING COUNT(b.id) = (SELECT COUNT(*) FROM b);
DBFiddle Demo |的 DBFiddle Demo - all test cases 强>
额外:Transient Data(在第二个演示中使用)
修改强>
另一种处理空集并离开INNER JOIN
的方法:
SELECT a.id FROM a
JOIN b on a.b_id = b.id
GROUP BY a.id
HAVING COUNT(a.id) = (SELECT COUNT(*) FROM b)
UNION
SELECT a.id
FROM a
WHERE NOT EXISTS (SELECT 1 FROM b);
<强> DBFiddle Demo 3 强>
答案 1 :(得分:1)
CREATE TABLE a (id INT, b_id INT);
CREATE TABLE b (id INT);
INSERT INTO a VALUES
(1, 1), (1, 2), (1, 3),
(2, 2), (3, 2), (3, 3);
DECLARE @i INT = 0;
WHILE @i < 5 BEGIN
TRUNCATE TABLE b;
IF @i = 0 INSERT b VALUES (1), (2), (3);
IF @i = 1 INSERT b VALUES (1), (2);
IF @i = 2 INSERT b VALUES (2);
IF @i = 3 INSERT b VALUES (2), (3);
SELECT DISTINCT x.id
FROM a AS x
WHERE NOT EXISTS (
SELECT *
FROM b AS y
WHERE NOT EXISTS (
SELECT *
FROM a AS z
WHERE z.id = x.id AND z.b_id=y.id
)
)
SET @i = @i + 1;
END;