2011-08-16 4 views
3

다음 테이블SQL에서 여러 줄 일치를 찾으려면 어떻게합니까?

CREATE TABLE T1 (
    A varchar(2), 
    B varchar(2) 
); 

INSERT INTO T1 VALUES 
    ('aa', 'm'), ('aa', 'n'), 
    ('bb', 'n'), ('bb', 'o'), 
    ('cc', 'n'), ('cc', 'o'), 
    ('dd', 'c'), ('dd', 'a'), ('dd', 'r'), 
    ('ee', 'a'), ('ee', 'c'), ('ee', 'r') 

A | B 
----+---- 
aa | m 
aa | n 
bb | n 
bb | o 
cc | n 
cc | o 
dd | c 
dd | a 
dd | r 
ee | a 
ee | c 
ee | r 

B의 모든 해당 값과 일치하는 A에서 값을 선택하고 그룹화하는 방법은? 예를 들어 bb와 cc는 모두 'n'과 'o'를 포함하기 때문에 그룹을 구성합니다 '.

그러면 결과는

Group | A 
---------- 
1  | bb 
1  | cc 
2  | dd 
2  | ee 
이됩니다.
+0

그룹의 최대 크기가 있습니까 (예를 들어 2,3 가지가 있습니다) –

+0

최대 크기가 없습니다 – Josh

답변

2

하나의 접근법은 일치하는 "집합"을 먼저 계산합니다. 여기서 집합은 일치하는 두 개의 A의 그룹입니다. 그런 다음 동일한 그룹의 집합에 대해 "머리"또는 가장 낮은 숫자 인 A을 계산합니다. dense_rank을 사용하여 머리에 번호를 매기고 세트 목록에서 다시 결합하여 모든 세트 멤버 목록을 작성할 수 있습니다.

SE Data에 대한 질의

; with groups as 
     (
     select distinct A 
     from @t 
     ) 
,  vals as 
     (
     select distinct B 
     from @t 
     ) 
,  sets as 
     (
     select g1.A as g1 
     ,  g2.A as g2 
     from groups g1 
     join groups g2 
     on  g1.A < g2.A 
     cross join 
       vals v 
     left join 
       @t v1 
     on  g1.A = v1.A 
       and v.B = v1.B 
     left join 
       @t v2 
     on  g2.A = v2.A 
       and v.B = v2.B 
     group by 
       g1.A 
     ,  g2.A 
     having count(case when isnull(v1.B,'') <> isnull(v2.B,'') then 1 end) = 0 
     ) 
,  heads as 
     (
     select s1.g1 
     ,  s1.g2 
     ,  head.head 
     from sets s1 
     cross apply 
       (
       select min(g1) as head 
       from sets s2 
       where s1.g2 = s2.g2 
       ) head 
     ) 
select distinct dense_rank() over (order by h.head) 
,  g.g 
from (
     select distinct head 
     from heads 
     ) h 
left join 
     (
     select g1 as g 
     ,  head 
     from heads 
     union all 
     select g2 
     ,  head 
     from heads 
     ) g 
on  h.head = g.head 
+0

감사합니다. 이 작품을하지만 성능이 내가 원하는만큼 좋지 않습니다. 그것은 나에게 시작하기에 좋은 장소를 줄 것이다. – Josh

1

SQL 서버 2008을 사용할 수있는 EXCEPTINTERSECT 기능을 가지고있을 것이다. 이것은 정확히 원하는 형식이 아니며 대용량 데이터 세트에 대해 성능에 대해 말할 수는 없지만 아마도 시작점을 제공 할 것입니다.

SELECT DISTINCT 
    T1.A, 
    T2.A 
FROM 
    T1 AS T1 
INNER JOIN T1 AS T2 ON T2.A > T1.A 
WHERE 
    NOT EXISTS 
    (
    SELECT 
     B 
    FROM 
     T1 AS T3 
    WHERE 
     T3.A = T1.A 
    EXCEPT 
    SELECT 
     B 
    FROM 
     T1 AS T4 
    WHERE 
     T4.A = T2.A 
    ) AND 
    NOT EXISTS 
    (
    SELECT 
     B 
    FROM 
     T1 AS T3 
    WHERE 
     T3.A = T2.A 
    EXCEPT 
    SELECT 
     B 
    FROM 
     T1 AS T4 
    WHERE 
     T4.A = T1.A 
    ) 

데이터에 따라 문자열 내에 구분 기호와 특정 순서가있는 연결 문자열을 생성 한 다음 비교할 수도 있습니다.

+0

+1 연결 방법이 더 재미 있지만 더 잘 수행 할 수 있습니다. – Andomar

0

당신이 필요로하는 관계 연산자는 널리 "the supplier who supplies all parts"로 알려진 division입니다.

실제로 부문은 약 8 가지의 맛을 지니고 있으며 SQL 언어는 그 중 아무 것도 직접 구현하지 않았습니다. 그러나 기존의 SQL 구문을 사용하여 모두 다시 만들 수 있습니다. 더 많은 인기를 얻으려면 this article을 참조하십시오. 고려해야 할 사항은 정확한 구분 또는 나머지; 빈 제수를 다루는 법.

관련 문제