TSQL Сравнение двух множеств - PullRequest
       0

TSQL Сравнение двух множеств

7 голосов
/ 07 сентября 2010

Когда заданы два набора

s1 = {a, b, c, d} s2 = {b, c, d, a}

(т.е.)

TableA

Item
a
b
c
d

TableB

Item
b
c
d
a

Как написать запрос Sql для отображения «Элементы в таблице A и таблице B равны».[Без использования SP или UDF]

Вывод

Elements in TableA and TableB contains identical sets

Ответы [ 6 ]

9 голосов
/ 07 сентября 2010

Использование:

SELECT CASE 
         WHEN   COUNT(*) = (SELECT COUNT(*) FROM a) 
            AND COUNT(*) = (SELECT COUNT(*) FROM b) THEN 'Elements in TableA and TableB contains identical sets'
         ELSE 'TableA and TableB do NOT contain identical sets'
       END
  FROM (SELECT a.col
          FROM a
        INTERSECT
        SELECT b.col
          FROM b) x 

Тест с:

WITH a AS (
  SELECT 'a' AS col
  UNION ALL
  SELECT 'b'
  UNION ALL
  SELECT 'c'
  UNION ALL
  SELECT 'd'),
     b AS (
  SELECT 'b' AS col
  UNION ALL
  SELECT 'c'
  UNION ALL
  SELECT 'd'
  UNION ALL
  SELECT 'a')
SELECT CASE 
         WHEN   COUNT(*) = (SELECT COUNT(*) FROM a) 
            AND COUNT(*) = (SELECT COUNT(*) FROM b) THEN 'yes'
         ELSE 'no'
       END
  FROM (SELECT a.col
          FROM a
        INTERSECT
        SELECT b.col
          FROM b) x 
5 голосов
/ 07 сентября 2010

Примерно так: FULL JOIN:

SELECT
  CASE 
    WHEN EXISTS (
      SELECT * FROM s1 FULL JOIN s2 ON s1.Item = s2.Item
      WHERE s1.Item IS NULL OR s2.Item IS NULL
      )
    THEN 'Elements in tableA and tableB are not equal'
    ELSE 'Elements in tableA and tableB are equal'
  END

Это дает преимущество короткого замыкания при первом несовпадении, в отличие от других решений, требующих 2 полных сканирования каждой таблицы (один раз дляCOUNT (*), один раз для JOIN / INTERSECT).

Ориентировочная стоимость значительно меньше, чем у других решений.

3 голосов
/ 07 сентября 2010

Осторожно, я собираюсь использовать Cross Join.

Declare @t1 table(val varchar(20))
Declare @t2 table(val varchar(20))


insert into @t1 values ('a')
insert into @t1 values ('b')
insert into @t1 values ('c')
insert into @t1 values ('d')


insert into @t2 values ('c')
insert into @t2 values ('d')
insert into @t2 values ('b')
insert into @t2 values ('a')

select 
    case when 
    count(1) = 
    (((Select count(1) from @t1) 
    + (Select count(1) from @t2)) / 2.0) 
    then 1 else 0 end as SetsMatch  from 
@t1 t1 cross join @t2 t2 
where t1.val = t2.val
3 голосов
/ 07 сентября 2010

Мое чудовище:

;with SetA as
(select 'a' c union
select 'b' union
select 'c') 
, SetB as 
(select 'b' c union
select 'c' union
select 'a' union 
select 'd'
) 
select case (select count(*) from (
select * from SetA except select * from SetB
union 
select * from SetB except select * from SetA
)t)
when 0 then 'Equal' else 'NotEqual' end 'Equality'
2 голосов
/ 07 сентября 2010

Может сделать это с ИСКЛЮЧЕНИЕМ и случаем

select 
   case 
     when count (1)=0 
        then 'Elements in TableA and TableB contains identical sets' 
     else 'Nope' end from (
       select item from s1
      EXCEPT 
       select item from s2
) b
1 голос
/ 17 января 2013

Так как эта тема была очень полезна для меня, я решил поделиться своим решением.

У меня была похожая проблема, возможно, более общая, чем это конкретное сравнение с одним набором. Я пытался найти идентификатор элемента, который имел набор многоэлементных дочерних элементов, которые соответствовали набору запросов многоэлементных элементов.

Соответствующая информация о схеме:

table events, pk id
table solutions, pk id, fk event_id -> events
table solution_sources, fk solutionid -> solutions
   columns unitsourceid, alpha

Запрос: найдите решение для события с идентификатором 110, у которого есть набор solution_sources, который соответствует набору (unitsourceid, alpha) в ss_tmp. (Полагаю, это можно сделать и без таблицы tmp.)

Решение:

with solutionids as (
  select y.solutionid from (
     select ss.solutionid, count(ss.solutionid) x 
        from solutions s, solution_sources ss 
        where s.event_id = 110 and ss.solutionid = s.id 
        group by ss.solutionid
  ) y where y.x = ( select count(*) from ss_tmp )
) 
select solutionids.solutionid  from solutionids where
(
select case
   when count(*) = ( select count(*) from ss_tmp ) then true
   else false
   end
    from 
       ( SELECT unitsourceid, alpha FROM solution_sources 
            where solutionid = solutionids.solutionid
          INTERSECT
         SELECT unitsourceid, alpha FROM ss_tmp ) x
)

Проверено на соответствие тестового запроса из 4 элементов и тестовой базы данных, в которой было найдено соответствующее решение (одинаковое количество дочерних элементов, каждый из которых соответствует), нескольких полностью несовпадающих решений и 1 решения, которое имело 3 совпадающих дочерних элемента, 1 решение, которое имело все 4 совпадающих дочерних элемента, плюс дополнительный дочерний элемент, и 1 решение, которое имело 4 дочерних элемента, из которых 3 из 4 соответствовали запросу. Был возвращен только идентификатор истинного соответствия.

спасибо большое -Linus

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...