分组依据,在 SQL 服务器中使用 where in 条件

Group by, having using where in condition in SQL Server

SeqNo   ProfileId   MenuId
--------------------------
 1      P1001        1001
 2      P1001        1002
 3      P1001        1004
 4      P1001        1005
 5      P1001        1006
 6      P1001        1007
 7      P1001        1008
 8      P1001        1009
 9      P1001        1010
10      P1002        1001
11      P1002        1002
12      P1002        1003
13      P1002        1004
14      P1002        1005

场景是检查给定的 ProfileId 是否存在于特定的 MenuId 集合。

假设我的输入MenuId集合是(1001, 1002, 1003, 1004, 1005),那么它必须return精确匹配条件即P1002

如果 MenuId 设置为 (1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010) 则它必须 return P1001.

但是如果我使用 group bywhere in 条件,它 return 都是 P1001, P1002

如何获取上述场景的精确匹配条件?

如果您想匹配 精确 匹配的配置文件,那么一种选择是聚合并断言非重复计数和总计数:

SELECT ProfileId
FROM yourTable
GROUP BY ProfileId
HAVING
    SUM(CASE WHEN MenuId NOT IN (1001, 1002, 1003, 1004, 1005)
             THEN 1 ELSE 0 END) = 0 AND
    COUNT(DISTINCT MenuId) = 5 AND
    COUNT(*) = 5;

Demo

HAVING 子句中的三个条件断言:

  • 除了 1001 到 1005(含)以外,没有菜单项 其他
  • 该配置文件有 5 个不同的菜单项
  • 该配置文件总共只有 5 个菜单项

我非常喜欢集合的字符串比较方法。如果你有 string_agg 那么你可以使用它,否则 stuff/xml 路径方法也很好

例如

drop table t
go
create table t(
SeqNo  int ,ProfileId  varchar(5),  MenuId varchar(4));
go
insert into t values
( 1  ,    'P1001'     ,   1001),
( 2  ,    'P1001'     ,   1002),
( 3  ,    'P1001'     ,   1004),
( 4  ,    'P1001'     ,   1005),
( 5  ,    'P1001'     ,   1006),
( 6  ,    'P1001'     ,   1007),
( 7  ,    'P1001'     ,   1008),
( 8  ,    'P1001'     ,   1009),
( 9  ,    'P1001'     ,   1010),
(10  ,    'P1002'     ,   1001),
(11  ,    'P1002'     ,   1002),
(12  ,    'P1002'     ,   1003),
(13  ,    'P1002'     ,   1004),
(14  ,    'P1002'     ,   1005);

select s.profileid
from
(
select  distinct t.profileid,
        maskdetail = STUFF((
          SELECT ',' + t1.menuid
          FROM t t1
          WHERE t1.profileid = t.profileid
          FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
from t

) s 
where s.maskdetail = concat('1001',',',1002,',',1003,',',1004,',','1005')

profileid
---------
P1002

(1 row(s) affected)

您必须确保您的集合和数据都是有序的。