2013-03-20 3 views
0

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

644432 738987 
738987 644432 
.. 
854313 871860 
854313 874411 
871860 854313 
871860 874411 
874411 854313 
874411 871860 

Для примера 644432 матчей с 738987 и 738987 матчами с 644432 (очевидно). Для меня они должны быть одинаковыми, и я должен получить один и только один (644432 или 738987).

другой пример 854313 соответствует 871860, который соответствует 874411 (вот почему у меня есть 6 записей).

Я должен получить только две записи в финале, как я могу это сделать?

Извините за мой английский и спасибо, если скажите мне, если мой вопрос не ясен.

Для примера есть код, чтобы заполнить таблицу, чтобы сделать, например:

DECLARE @DataTable TABLE (ColA INT, ColB INT) 
insert into @DataTable values 
(644432, 738987), 
(738987, 644432), 
(854313, 871860), 
(854313, 874411), 
(871860, 854313), 
(871860, 874411), 
(874411, 854313), 
(874411, 871860) 
select * from @DataTable 
+1

Добро пожаловать в переполнение стека!Укажите RDBMS, на которые вы нацеливаете, добавив соответствующий тег (Oracle, SQL Server, MySQL и т. Д.). Могут быть ответы, которые используют преимущества языка или функций продукта, которые не поддерживаются повсеместно. Кроме того, пометив его конкретными СУБД, ваш вопрос может привлечь внимание от людей, более подходящих для ответа на него. – Taryn

+0

Если у вас есть выбор, какой записи вы хотите? –

+0

Нет выбора, я хочу просто получить один в каждой группе и пойти на обед :) Спасибо заранее. – user2190624

ответ

0

ОК, в приведенном ниже примере будет следовать по ссылкам, которые на один уровень. Это можно было бы тщательно очистить хранимой процедурой или создать запрос из кода, что упростит добавление дополнительных уровней ссылки.

-- Set up an example table 
create table DataTable 
(
    A int, 
    B int 
) 
GO 

insert into DataTable values(644432,738987) 
insert into DataTable values(738987,644432) 
insert into DataTable values(854313,871860) 
insert into DataTable values(854313,874411) 
insert into DataTable values(871860,854313) 
insert into DataTable values(871860,874411) 
insert into DataTable values(874411,854313) 
insert into DataTable values(874411,871860) 
GO 

-- Strip out initial duplicates 
select distinct A,B into Pass1 
from 
(
    select case when A > B then B else A end as A, 
    case when A > B then A else B end as B 
    from DataTable 
) minmax 

-- Create a copy that we will update with links between values 
select * into Pass2 from Pass1 order by A 

update Pass2 set B=x.NewB from 
(
    select L.A as OldA,L.B as OldB, R.B as NewB 
    from Pass1 L 
    inner join Pass1 R on L.B = R.A 
) x 
where Pass2.A=x.OldA and Pass2.B=x.OldB 

update Pass2 set A=x.NewA from 
(
    select L.B as OldA, R.B as OldB, L.A as NewA 
    from Pass1 L 
    inner join Pass1 R on L.B = R.A 
) x 
where Pass2.A=x.OldA and Pass2.B=x.OldB 

-- Dedupe any newly created duplicates 
select distinct A,B 
from 
(
    select case when A > B then B else A end as A, 
    case when A > B then A else B end as B 
    from Pass2 
) minmax 
+0

Это LEGEN -wait for it-DARY !!! Большое спасибо вам Stony and thanx за все остальные :) – user2190624

+0

Спасибо! То, что я имел в виду под 1 уровнем связи, состоит в том, что если вы делаете 1 2, 2 3, 3 4, 4 5, это не будет работать полностью. – Richard

1

Если предположить, что это таблица с именем DataTable с двумя столбцами, колой и ColB, то вы можете сделать:

select distinct Smallest,Largest from 
(
    select case when ColA > ColB then ColB else ColA end as Smallest, 
    case when ColA > ColB then ColA else colB end as Largest 
    from DataTable 
) minmax 

Используется внутренний выбор, чтобы изменить значения таким образом, чтобы наименьшее значение всегда было первым столбцом, а наибольшее значение - во втором столбце. Затем внешний выбор просто вытаскивает отдельный набор значений.

+0

Для первой группы это работает, но не для второй группы записей:
Я получаю такой результат:
Самый маленький Самый большой 644432 738987 >> Хорошо, потому что (738987 644432) удален 854313 871860 >> 1/3 854313 874411 >> 2/3 871860 874411 >> 3/3 Я хочу один из 1/3 или 2/3 или 3/3 :) – user2190624

+0

Извините, что я написал, будет идентифицировать только прямые дубликаты, он не будет выполнять более сложный второй тип соответствия. – Richard

+0

ОК не извините, я объясню: записи 644432 и 738987 имеют что-то общее >> вот почему предыдущий код дает две записи. 871860, 854313 и 874411 имеют что-то общее, и поэтому у нас есть 6 записей, я хочу просто (644432 или 738987) в первом случае и (871860 или 854313 или 874411) >> так что в результате получается 2 записи, одна в каждой группе. – user2190624

0

Try This

выберите col1, col2 из (выберите col1 + col2 в качестве индикатора, col1, col2 из table1) группы по показателю

Refer sqlfiddle here

Примечание: Это не будет работать, если сумма одинакова для двух разных строк.

+0

Недопустимое имя столбца: «индикатор». :) Тем не менее +1 за «Выберите работу, которую вы любите, и вам никогда не придется работать день в вашей жизни» – user2190624

+0

@ user2190624 Спасибо за комментарий. Изменена группа. – Dhinakar

+0

Все еще не работает :) Я добавил код в поле вопроса, чтобы иметь пример. – user2190624

0
select n1,n2 from(select a.col1 col1,a.col2 col2,rownum rn from tbl a, tbl b 
where a.col1||a.col2=(b.col2||b.col1)) where mod(rn,2)<>0 
union 
select a.col1 col1,a.col2 col2 from tbl a left outer join tbl b on 
a.col1||a.col2=(b.col2||b.col1) where b.col1 is null 
+0

NOt работает, к сожалению, для меня, я добавил код в поле вопросов, чтобы иметь пример. – user2190624

+0

Я попробовал тот же запрос для ваших данных ... Это работает отлично для меня. BTW, какие СУБД вы используете Вышеприведенный запрос будет хорошо работать в Oracle – Aspirant

+0

Sql Server 2008, и вы получите две строки в результате? – user2190624

0

Рекурсивный запрос для поиска подключенных множеств. Для каждой цепочки элемент с наименьшим числом сообщается как «лидер группы».

Запрос работает, сначала упорядочивая члены пар, а затем находим цепи подключенных компонентов. Этот метод будет не работать, если имеется несколько стартовых точек для кластера. (Но он избегает циклов)

Этот синтаксис предназначен для Postgresql, для microsoft вы должны опустить ключевое слово RECURSIVE, а для Oracle вы должны использовать CONNECT BY, PRIOR. YMMV.

DROP SCHEMA tmp CASCADE; 
CREATE SCHEMA tmp ; 
SET search_path=tmp; 

CREATE TABLE pairs (ONE INTEGER NOT NULL, two INTEGER NOT NULL 
     , PRIMARY KEY (one, two) 
     ); 
INSERT INTO pairs(one, two) values 
(644432,738987) ,(738987,644432) 
,(854313,871860) ,(854313,874411) ,(871860,854313) ,(871860,874411) ,(874411,854313) ,(874411,871860) 
     ; 

WITH RECURSIVE rope AS (
     WITH opair AS (
       SELECT LEAST(one, two) AS one 
       , GREATEST(one, two) AS two 
       FROM pairs 
       ) 
     SELECT o.one AS top 
     , o.one AS one 
     , o.two AS two 
     FROM opair o 
     WHERE NOT EXISTS (SELECT * FROM opair x WHERE x.two=o.one) 
     UNION ALL 
     SELECT k.one AS top 
     , p.one AS one 
     , p.two AS two 
     FROM opair p 
     JOIN rope k ON k.two = p.one 
     ) 
SELECT DISTINCT top 
     , COUNT(*) AS N_members 
FROM rope 
GROUP BY top 
ORDER BY top 
     ; 

Результат:

CREATE TABLE 
INSERT 0 8 
    top | n_members 
--------+----------- 
644432 |   2 
854313 |   8 
(2 rows) 
+0

Это результат, который я хочу, НО Я работаю в SQL Server 2008 R2, если только я могу сказать моему боссу, чтобы изменить его сейчас :) Я пытаюсь понять алгоритм, который вы использовали. – user2190624

+0

Как я уже сказал, для microsoft вы должны удалить ключевое слово 'recursive'. ((Может быть, несколько других незначительных изменений тоже.) – wildplasser

+0

Да из-за результата я оммит, чтобы прочитать все ответы :) Извините, Ok, я постараюсь сделать эти изменения, надеюсь, что это сработает :) спасибо – user2190624

Смежные вопросы