我想选择同时满足同一列的两个条件的行。下面是表架构。
安全表
Id RoleId CompId SecurityToken Accesstype
1 1 10 abc 2
2 1 10 xyz 2
3 12 10 abc 2
4 16 12 abc 2
5 16 12 xyz 2
6 30 13 abc 2
7 1 10 efg 2
8 1 10 lmn 0
我想要“每种RoleID / CompID组合的所有行,其中accesstype = 2,并且对于该角色/ compID组合,既包含包含安全令牌“ abc”的行,又包含包含SecurityToken“ xyz”的行”
输出应为
Id RoleId CompId SecurityToken Accesstype
1 1 10 abc 2
2 1 10 xyz 2
4 16 12 abc 2
5 16 12 xyz 2
答案 0 :(得分:6)
我相信以下查询将产生所需的输出:
SELECT *
FROM testdata
WHERE Accesstype = 2
AND SecurityToken IN ('abc', 'xyz')
AND EXISTS (
SELECT 1
FROM testdata AS tmp
WHERE RoleId = testdata.RoleId
AND CompId = testdata.CompId
AND Accesstype = testdata.AccessType
AND SecurityToken IN ('abc', 'xyz')
HAVING COUNT(DISTINCT SecurityToken) = 2
)
为了消除包含额外安全性令牌(例如efg
和lmn
)的集合,请将WHERE和HAVING子句更改为:
WHERE RoleId = testdata.RoleId
AND CompId = testdata.CompId
AND Accesstype = testdata.AccessType
HAVING COUNT(DISTINCT SecurityToken) = 2
AND COUNT(DISTINCT SecurityToken) = COUNT(CASE WHEN SecurityToken IN ('abc', 'xyz') THEN 1 END)
答案 1 :(得分:0)
CREATE TABLE #Table1
([Id] int, [RoleId] int, [CompId] int, [SecurityToken] varchar(3), [Accesstype] int)
;
INSERT INTO #Table1
([Id], [RoleId], [CompId], [SecurityToken], [Accesstype])
VALUES
(1, 1, 10, 'abc', 2),
(2, 1, 10, 'xyz', 2),
(3, 12, 10, 'abc', 2),
(4, 16, 12, 'abc', 2),
(5, 16, 12, 'xyz', 2),
(6, 30, 13, 'abc', 2)
;
WITH cte AS (
SELECT *,ROW_NUMBER() OVER (PARTITION BY [ROLEID],[COMPID] ORDER BY ID) AS RN FROM #TABLE1
),
COUNTED AS (
SELECT
*,
COUNT(*) OVER (PARTITION BY [ROLEID],[COMPID]) AS CNT
FROM cte
)
SELECT
[ID], [ROLEID], [COMPID], [SECURITYTOKEN], [ACCESSTYPE]
FROM COUNTED
WHERE CNT >= 2
输出
ID ROLEID COMPID SECURITYTOKEN ACCESSTYPE
1 1 10 abc 2
2 1 10 xyz 2
4 16 12 abc 2
5 16 12 xyz 2
或
WITH CTE AS
(
SELECT
*,
COUNT(*) OVER (PARTITION BY [ROLEID],[COMPID]) AS CNT
FROM #TABLE1)
SELECT [ID], [ROLEID], [COMPID], [SECURITYTOKEN], [ACCESSTYPE] FROM CTE WHERE CNT>=2
答案 2 :(得分:0)
一种方法使用exists
:
select t.*
from t
where t.Accesstype = 2 and
t.securityToken in ('abc', 'xyz') and
exists (select 1
from t t2
where t2.RoleId = t.RoleId and
t2.CompId = t.CompId and
t2.Accesstype = t.AccessType and
t2.SecurityToken in ('abc', 'xyz') and
t2.SecrityToken <> t.SecurityToken
);
也许更简单的方法使用窗口函数:
select t.*
from (select t.*,
min(securitytoken) over (partition by roleid, compid) as min_st,
min(securitytoken) over (partition by roleid, compid) as max_st
from t
where t.Accesstype = 2 and
t.SecurityToken in ('abc', 'xyz')
) t
where minsecuritytoken = 'abc' and
maxsecuritytoken = 'xyz;