Узнайте, содержит ли столбец два разных значения для каждой группы - PullRequest
0 голосов
/ 03 сентября 2018

Я хочу выбрать строки, которые удовлетворяют обоим условиям одного и того же столбца. Ниже приведена схема таблицы.

Таблица безопасности

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, и есть как строка, содержащая токен безопасности" abc ", так и строка, содержащая SecurityToken" xyz "для этой комбинации роли / compID"

Вывод должен быть

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

Ответы [ 3 ]

0 голосов
/ 03 сентября 2018
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
0 голосов
/ 03 сентября 2018

Один метод использует 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;
0 голосов
/ 03 сентября 2018

Я считаю, что следующий запрос даст желаемый результат:

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
)

SQL Fiddle

Чтобы исключить наборы, содержащие дополнительные токены безопасности (например, 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)
...