答案可以在抽象的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(未显示)之间的联接表
我需要返回:
所有(DISTINCT)FId,其中给定FId的RId集是(或“ IN”)角色的子集。 (我希望我将集合论与数据库术语混合在一起,但我只是希望更好地传达这个想法)。因此,在这种情况下应返回f1和f3,因为f1 {2,3}和f3 {6,7}的RId集是T_Roles的子集。
T_Roles中的RId列表在上面返回的任何函数中均未找到。 (T_Roles-(f1联合f3)),或在此示例中为{1,4,5}。
答案 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_Roles
在RID
表中有对应的@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])
);
这是执行查询的结果:
答案 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
)