SQL найти одинаковую группу - PullRequest
5 голосов
/ 01 августа 2011

Учитывая таблицу типа:

id    key   val
----  ----  -----
bob   hair  red
bob   eyes  green

И другую таблицу типа:

id    key   val
----  ----  -----
fred  hair  red
fred  eyes  green
fred  shoe  42
joe   hair  red 
joe   eyes  green
greg  eyes  blue
greg  hair  brown

Я хотел бы найти людей в таблице b, которые точно соответствуют людям в таблице a, вэто дело Боба и Джо.Фред не считается, потому что у него также есть размер обуви.Это в Sybase, поэтому нет полного внешнего соединения.Я придумала выбор из профсоюза, который возвращает людей, которые определенно не совпадают, но я не уверен, как эффективно выбирать людей, которые являются.

В качестве альтернативы, если это прощеКак я могу проверить, какие группы в a встречаются в b более одного раза?

Ответы [ 3 ]

2 голосов
/ 01 августа 2011

Попробуйте это

select a.id,b.id
from a 
join b on a.[key] = b.[key] and a.val = b.val -- match all rows
join (select id,count(*) total from a group by id) a2 on a.id = a2.id -- get the total keys for table a per id
join (select id,count(*) total from b group by id) b2 on b.id = b2.id -- get the total keys for table b per id
group by a.id,b.id,a2.total,b2.total
having count(*) = a2.total AND count(*) = b2.total -- the matching row's total should be equal with each tables keys per id

После комментариев @ t-clausen.dk я сделал ревизию исходного кода SQL.В этом случае я считаю каждую отличную пару / значение, которое соответствует обеим таблицам, с каждой таблицей отличную пару / значение.

select td.aid,td.bid
from (
select a.id as aid,b.id as bid, count(distinct a.[key]+' '+a.val) total
from a 
join b on a.[kry] = b.[key] and a.val = b.val
group by a.id,b.id
) td -- match all distinct attribute rows
join (select id,count(distinct [key]+' '+val) total from a group by id) a2 on td.aid = a2.id -- get the total distinct keys for table a per id
join (select id,count(distinct [key]+' '+val) total from b group by id) b2 on td.bid = b2.id -- get the total keys for table b per id
where td.total = a2.total AND td.total = b2.total -- the matching distinct attribute total should be equal with each tables distinct key-val pair

Tested on

Table a

bob     hair    red
bob     eyes    green
nick    hair    red
nick    eyes    green
nick    shoe    45

Table b

fred    hair    red
fred    eyes    green
joe     hair    red
joe     eyes    green
fred    shoe    42
2 голосов
/ 01 августа 2011

Вы можете эмулировать full outer join, захватывая все id s в подзапросе, а затем оставляя их соединенными в двух направлениях:

select  ids.id
from    (
        select  distinct id
        from    @a
        union
        select  id
        from    @b
        ) as ids
left join
        @a a1
on      a1.id = ids.id
left join
        @b b1
on      a1.id = b1.id
        and a1.[key] = b1.[key]
        and a1.val = b1.val
left join
        @b b2
on      b2.id = ids.id
left join
        @a a2
on      b2.id = a2.id
        and b2.[key] = a2.[key]
        and b2.val = a2.val
group by
        ids.id
having  sum(case when b1.id is null or a2.id is null then 1 else 0 end) = 0

Пример на SE DATA.

1 голос
/ 01 августа 2011

Этот синтаксис найдет точные совпадения для разных имен в @ t1 и @ t2.Я извиняюсь, потому что написано на MSSQL.Я надеюсь, что это может быть преобразовано в Sybase.Поработав с ним весь день, хочу поделиться этой красотой.Я знаю, что эти длинные сценарии непопулярны.Я надеюсь, что кто-нибудь все равно его оценит.

Этот выбор точно совпадет с @ t2 в @ t1.

Я заполнил таблицы по этой ссылке http://data.stackexchange.com/stackoverflow/q/108035/

DECLARE @t1 TABLE(id varchar(10), [key] varchar(10), val varchar(10))
DECLARE @t2 TABLE(id varchar(10), [key] varchar(10), val varchar(10))

;WITH t1 AS ( 
SELECT t1.id, t1.[key], t1.val, count(*) count1, sum(count(*)) OVER(PARTITION BY t1.id) sum1 FROM @t1 t1 
GROUP BY t1.id, t1.[key], t1.val
), t2 as (
SELECT t2.id, t2.[key], t2.val, count(*) count1, sum(count(*)) OVER(PARTITION BY t2.id) sum1 FROM @t2 t2 
GROUP BY t2.id, t2.[key], t2.val
), t3 AS ( 
SELECT t1.*, sum(t1.count1) OVER(PARTITION BY t1.id) sum2
FROM t1 
JOIN t2 on t1.val = t2.val AND t1.[key]=t2.[key]
AND t1.count1 = t2.count1 AND t1.sum1 = t2.sum1
)
SELECT t3.id, t3.[key], t3.val FROM t3
JOIN @t2 t ON t3.[key] = t.[key] AND t3.val = t.val
WHERE t3.sum2 = t3.sum1

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

...