【问题标题】:Find all sets/entities that are in another set [duplicate]查找另一个集合中的所有集合/实体[重复]
【发布时间】:2018-11-02 14:54:02
【问题描述】:

答案在摘要 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 Union f3)),或在本例中为 {1,4,5}。

【问题讨论】:

  • 请确认(编辑您的问题):a) F 是未显示表格吗? b) F_Roles 是一个没有完整性的关联表 (F::Roles) [例如。 Roles] 中没有 RID 9 吗? c) 你试图确定的,以便纠正它。 ?我不会在这里使用“子集”这个词,只是IN
  • 在我的实际问题中,上面显示的角色数据集是Something-Else_Roles 多对多表/关系的子集。我试图在这里简化它。我不确定关联表的属性,但是是的,F_Roles 和 Roles 之间没有参照完整性。
  • 谢谢,你已经清理了这个问题。好的,你有两个关联文件。但仍有一些清理工作要做。在[1][2]中,请不要引用未显示的文件。

标签: sql sql-server tsql subset


【解决方案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 连接来检查@F_Roles 表中的哪个RID@Roles 表中有对应的RID。如果没有,则对应行的查询返回值为NULL。因此,我们只需计算每个FIDRIDs,并检查该计数是否等于第二个表返回的值的计数(NULL 值被忽略)。

后一个查询也很简单。有了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])
);

这是查询的执行结果:

【讨论】:

  • 精通解释!
  • 在我将问题更改为更清晰之后,此解决方案需要更新。抱歉,@gotqn
【解决方案2】:

对于查询 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
  )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-11
    • 2013-05-28
    • 1970-01-01
    • 2014-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多