查找另一个集合中的所有集合/实体

时间:2018-10-29 18:32:48

标签: sql sql-server tsql subset

答案可以在抽象的here中找到,但我正在寻找具体的SQL解决方案。

给出下表:

   ------------     -----------
   |  F_Roles |     | T_Roles | 
   ------+-----     -----+-----
   | FId | RId|     |TId | RId|
   ------+------    -----+-----
   |  f1 |  2 |     | t1 | 1  |
   |  f1 |  3 |     | t1 | 2  |
   |  f2 |  2 |     | t1 | 3  |
   |  f2 |  4 |     | t1 | 4  |
   |  f2 |  9 |     | t1 | 5  |
   |  f3 |  6 |     | t1 | 6  |
   |  f3 |  7 |     | t1 | 7  |
   ------------     ----------

(F_Roles)是F(未显示)和Roles(也未显示)之间的联接表 (T_Roles)是T(未显示)和Roles(未显示)之间的联接表

我需要返回:

  1. 所有(DISTINCT)FId,其中给定FId的RId集是(或“ IN”)角色的子集。 (我希望我将集合论与数据库术语混合在一起,但我只是希望更好地传达这个想法)。因此,在这种情况下应返回f1和f3,因为f1 {2,3}和f3 {6,7}的RId集是T_Roles的子集。

  2. T_Roles中的RId列表在上面返回的任何函数中均未找到。 (T_Roles-(f1联合f3)),或在此示例中为{1,4,5}。

2 个答案:

答案 0 :(得分:1)

让我们定义以下示例数据:

DECLARE @F_Roles TABLE
(
    [FID] CHAR(2)
   ,[RID] TINYINT
);

DECLARE @Roles TABLE
(
    [RID] TINYINT
);

INSERT INTO @F_Roles ([FID], [RID])
VALUES ('f1', 2)
      ,('f1', 3)
      ,('f2', 2)
      ,('f2', 4)
      ,('f2', 9)
      ,('f3', 6)
      ,('f3', 7);

INSERT INTO @Roles ([RID])
VALUES (1), (2), (3), (4), (5), (6), (7);

否,可以使用以下T-SQL语句解决第一个查询:

SELECT F.[FID] 
FROM @F_Roles F
LEFT JOIN @Roles R
    ON F.[RID] = R.[RID]
GROUP BY F.[FID]
HAVING SUM(CASE WHEN R.[RID] IS NULL THEN 0 ELSE 1 END) = COUNT(F.[RID]);

这个想法很简单。我们使用LEFT联接来检查RID表中的哪个@F_RolesRID表中有对应的@Roles。如果还没有,则查询返回的对应行的值为NULL。因此,我们只需要为每个RIDs计算FID并检查此计数是否等于第二个表返回的值计数(NULL值将被忽略)。 / p>

后一个查询也很简单。从一开始就有FID,我们就可以使用EXCEPT来找到不匹配的RIDs

SELECT [RID]
FROM @Roles
EXCEPT
SELECT [RID]
FROM @F_Roles
WHERE [FID] IN
(
    SELECT F.[FID] 
    FROM @F_Roles F
    LEFT JOIN @Roles R
        ON F.[RID] = R.[RID]
    GROUP BY F.[FID]
    HAVING SUM(CASE WHEN R.[RID] IS NULL THEN 0 ELSE 1 END) = COUNT(F.[RID])
);

这是执行查询的结果:

enter image description here

答案 1 :(得分:0)

对于查询1:

with x as (
select f.fid, sum(case when r.rid is null then 1 end) as missing
  from f_roles f
  left join roles r on r.rid = r.rid
  group by f.fid
)
select distinct f.fid
  from f_roles f
  join x on f.fid = x.fid
  where x.missing = 0

对于查询2:

with x as (
select f.fid, sum(case when r.rid is null then 1 end) as missing
  from f_roles f
  left join roles r on r.rid = r.rid
  group by f.fid
),
y as (
select distinct f.fid
  from f_roles f
  join x on f.fid = x.fid
  where x.missing = 0
)
select r.rid
  from roles r 
  where r.rid not in (
    select f.rid from y join f_roles f on f.rid = y.rid
  )