相交动态数量的表

时间:2018-05-05 06:15:21

标签: sql sql-server tsql sql-server-2016

我有两个关系,ab,其属性由

提供
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

2 个答案:

答案 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)

您要做的事情称为关系部门[12]。

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;

Test it online