分组依据,在 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 by
和 where 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;
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)
您必须确保您的集合和数据都是有序的。
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 by
和 where 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;
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)
您必须确保您的集合和数据都是有序的。