Как я могу найти совпадения нескольких строк в SQL? - PullRequest
3 голосов
/ 16 августа 2011

Со следующей таблицей

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

Как я могу выбрать и сгруппировать значения в A, которые соответствуют всем базовым значениям в B. Например, bb и cc составляют группу, потому что они оба содержат 'n' и 'o'.

Таким образом, результат будет

Group | A
----------
1     | bb
1     | cc
2     | dd
2     | ee

Ответы [ 3 ]

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

Вот один из подходов: сначала он вычисляет совпадающие «наборы», где набор представляет собой группу из двух A, которые совпадают. Затем вычисляется «голова», или самая низкая A для наборов в той же группе. Используя dense_rank, вы можете нумеровать головы, а затем снова присоединиться к списку наборов, чтобы создать список всех членов набора.

Запрос на Данные SE .

; 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
1 голос
/ 17 августа 2011

SQL Server 2008 имеет функции EXCEPT и INTERSECT, которые можно использовать.Это не совсем тот формат, который вы хотели, и я не могу говорить о производительности с большими наборами данных, но, возможно, это даст вам отправную точку.

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 голосов
/ 17 августа 2011

Требуемый вам оператор связи - деление , широко известный как «поставщик, поставляющий все детали» .

На самом деле, разделение включает около восьми разновидностей, и язык SQL не реализовал ни один из них напрямую. Однако все они могут быть воссозданы с использованием существующих конструкций SQL: более популярные из них см. в этой статье . Вещи, чтобы рассмотреть, включают: точное разделение или с остатком; как обращаться с пустым делителем.

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