Удаление дубликатов из результата множественного объединения таблиц с разными столбцами в MySQL - PullRequest
4 голосов
/ 24 апреля 2011

Я пытаюсь сделать одно утверждение, чтобы извлечь данные из 3 связанных таблиц (так как все они имеют общий строковый индекс).У меня возникли проблемы с тем, чтобы MySQL не возвращал продукт из двух таблиц, в результате чего набор результатов стал намного больше, чем мне бы хотелось.Каждая таблица имеет различное количество столбцов, и я предпочел бы не использовать UNION в любом случае, потому что данные в каждой таблице являются отдельными.

Вот пример:

Таблица X является основной таблицей и имеет поля A B.

Таблица Y имеет поля AC D.

Таблица Zимеет поля AEF G.

-

Мой идеальный результат будет иметь вид:

A1 B1 C1 D1 E1 F1 G1

A1 B2 C2 D2 00 00 00

A2 B3 C3 D3 E2 F2 G2

A2 B4 00 00 E3 F3 G3

и т. д. *

-

Вот самый простой SQL, который я пробовал, который показывает мою проблему (то есть он возвращает произведение Y * Z, проиндексированное данными из A:

SELECT DISTINCT *

FROM X

LEFT JOIN Y USING (A)

LEFT JOIN Z USING (A)

-

У меня естьпопытался добавить предложение group by к полям на Y и Z. Но, если я сгруппировал только по одному столбцу, он возвращает только первый результат, соответствующий каждому уникальному значению в этом столбце (то есть: A1 C1 E1, A1 C2 E1, A1 C3E1). И если я сгруппирую по двум столбцам, это снова возвращает произведение двух таблиц.

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

По сути, я хочу объединить результаты трех операторов выбора в один результат, сэто дает мне все комбинации данных.Если мне нужно, я могу сделать несколько запросов.Однако, поскольку все они содержат общий индекс, я считаю, что должен быть способ сделать это в одном пропущенном запросе.

Спасибо за любую помощь.

Ответы [ 5 ]

2 голосов
/ 24 апреля 2011

Не знаю, понимаю ли я вашу проблему, но почему вы используете LEFT JOIN? Эта история больше напоминает ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Ничто здесь не требует СОЮЗА.

[Изменить] Хорошо, я думаю, что я вижу, что вы хотите сейчас. Я никогда не пробовал то, что собираюсь предложить, и, более того, некоторые БД не поддерживают его (пока), но я думаю, что вам нужна оконная функция.

WITH Y2 AS (SELECT Y.*, ROW_NUMBER() OVER (PARTITION BY A) AS YROW FROM Y),
     Z2 AS (SELECT Z.*, ROW_NUMBER() OVER (PARTITION BY A) AS ZROW FROM Z)
SELECT COALESCE(Y2.A,Z2.A) AS A, Y2.C, Y2.D, Z2.E, Z2.F, Z2.G
FROM Y2 FULL OUTER JOIN Z2 ON Y2.A=Z2.A AND YROW=ZROW;

Идея состоит в том, чтобы напечатать список как можно меньше строк, верно? Таким образом, если у A1 есть 10 записей в Y и 7 в Z, то мы получим 10 строк с 3, имеющими NULL для полей Z. Это работает в Postgres. Я не верю, что этот синтаксис доступен в MySQL.

Y

 a | d | c  
---+---+----
 1 | 1 | -1
 1 | 2 | -1
 2 | 0 | -1

Z:

 a | f | g | e 
---+---+---+---
 1 | 9 | 9 | 0
 2 | 1 | 1 | 0
 3 | 0 | 1 | 0

Вывод вышеуказанного утверждения:

 a | c  | d | e | f | g 
---+----+---+---+---+---
 1 | -1 | 1 | 0 | 9 | 9
 1 | -1 | 2 |   |   |  
 2 | -1 | 0 | 0 | 1 | 1
 3 |    |   | 0 | 0 | 1
0 голосов
/ 22 сентября 2011

Если я правильно понимаю, таблица X имеет отношение 1:n с и таблицами Y и Z.Итак, поведение, которое вы видите, ожидается.Результат, который вы получаете, является своего рода перекрестным продуктом.

Если X имеет данные о персонале, Y имеет данные об адресе для этих людей, а Z имеет данные о телефоне для этих людей, то ваш запрос вполне естественпоказать все комбинации адресов и телефонов для каждого человека.Если у кого-то есть 3 адреса и 4 телефона в ваших таблицах, тогда запрос показывает 12 строк в результате.

Этого можно избежать, используя запрос UNION или выполнив два запроса:

SELECT X.*
     , Y.*

FROM X
  LEFT JOIN Y 
    ON Y.A = X.A

и:

SELECT X.*
     , Z.*

FROM X 
  LEFT JOIN Z 
    ON Z.A = X.A
0 голосов
/ 22 сентября 2011

PostgreSQL - это всегда правильный ответ на большинство проблем MySQL, но ваша проблема могла быть решена следующим образом:

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

Левое соединение X левое соединение Y, которое неизбежно дает вам A x X x Y, где вы хотели (AxX) x (AxY)

Простое решение может быть:

select x.A,x.B,x.C,x.D,y.E,y.F,y.G from (SELECT A.A,A.B,X.C,X.D FROM A LEFT JOIN X ON A.A=X.A) x INNER JOIN (SELECT A.A,Y.E,Y.F,Y.G FROM A LEFT JOIN Y ON A.A=Y.A) y ON x.A=y.A

Для деталей теста:

CREATE TABLE A (A varchar(3),B varchar(3));
CREATE TABLE X (A varchar(3),C varchar(3), D varchar(3));
CREATE TABLE Y (A varchar(3),E varchar(3), F varchar(3), G varchar(3));
INSERT INTO A(A,B) VALUES ('A1','B1'), ('A2','B2'), ('A3','B3'), ('A4','B4');
INSERT INTO X(A,C,D) VALUES ('A1','C1','D1'), ('A3','C3','D3'), ('A4','C4','D4');
INSERT INTO Y(A,E,F,G) VALUES ('A1','E1','F1','G1'), ('A2','E2','F2','G2'), ('A4','E4','F4','G4');
select x.A,x.B,x.C,x.D,y.E,y.F,y.G from (SELECT A.A,A.B,X.C,X.D FROM A LEFT JOIN X ON A.A=X.A) x INNER JOIN (SELECT A.A,Y.E,Y.F,Y.G FROM A LEFT JOIN Y ON A.A=Y.A) y ON x.A=y.A

Итак, да, MySQL имеет много-много проблем, но это не одна из них - большинство проблем касаются более сложных вещей.

0 голосов
/ 27 июля 2011

Я нашел новый способ редактирования этого поста, и его можно использовать для объединения двух таблиц в соответствии с уникальными идентификаторами.
Попробуйте это:

create table y
(
a int,
d int,
c int
)

create table z
(
a int,
f int,
g int,
e int
)

go

insert into y values(1,1,-1)
insert into y values(1,2,-1)
insert into y values(2,0,-1)

insert into z values(1,9,9,0)
insert into z values(2,1,1,0)
insert into z values(3,0,1,0)

go

select * from y
select * from z

WITH Y2 AS (SELECT Y.*, ROW_NUMBER()  OVER (ORDER BY A) AS YROW FROM Y where A = 3),
     Z2 AS (SELECT Z.*, ROW_NUMBER()  OVER (ORDER BY A) AS ZROW FROM Z where A = 3)
SELECT COALESCE(Y2.A,Z2.A) AS A, Y2.C, Y2.D, Z2.E, Z2.F, Z2.G
FROM Y2 FULL OUTER JOIN Z2 ON Y2.A=Z2.A AND YROW=ZROW;
0 голосов
/ 24 апреля 2011

Да, UNION - это не ответ.

Я думаю, ты хочешь:

SELECT *
FROM x
    JOIN y ON x.a = y.a
    JOIN z ON x.a = z.a
GROUB BY x.a;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...