2011-04-24 26 views
4

我試圖做出一個語句來從3個相關表中提取數據(因爲它們都共享一個公共字符串索引)。我無法阻止MySQL返回兩個表的結果,使得結果集比我想要的要大得多。每個表都有不同數量的列,我寧願不要使用UNION,因爲每個表中的數據是分開的。從MySQL中不同列的表上刪除多重連接結果中的重複項

下面是一個例子:

表X是主表,並具有字段甲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) 

-

我曾嘗試通過子句增加一組對Y和Z字段但是,如果我只按一列,它只返回與在該式柱的每個唯一值相匹配的第一結果n(即:A1 C1 E1,A1 C2 E1,A1 C3 E1)。如果我按兩列分組,它將再次返回兩個表的乘積。

我也試過在查詢中做多個select語句,然後加入結果表,但我再次收到表格的輸出結果作爲輸出。

基本上我想合併三個選擇語句的結果到一個單一的結果,沒有它給我所有的數據組合。如果我需要,我可以採取多重查詢。但是,由於它們都包含一個共同的索引,我覺得應該有一種方法可以在我缺少的一個查詢中執行。

感謝您的任何幫助。

+0

好吧,也許這將使它更容易理解我的問題。只需忽略表X並嘗試在字段A上連接表Y和Z. IE:SELECT * 從Y內部連接Z使用(A)。您會看到這將輸出兩個表的產品。 – Alfred 2011-04-24 02:33:26

回答

2

我不知道我是否理解你的問題,但你爲什麼使用左連接?這個故事聽起來更像是一個INNER 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在Y中有10個條目並且在Z中有7個條目,那麼我們得到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

我已經嘗試了內連接和左連接;兩種方式都可以得到y和z的乘積。 – Alfred 2011-04-24 02:25:55

+0

查看新答案! – 2011-04-25 20:41:47

+0

謝謝你的幫助,安德魯。我剛剛切換到PostgreSQL。但是,通過在on子句中添加另一個字段,我能夠在MySQL中獲得「足夠好」的結果。 (A,id)UNION DISTINCT選擇Y. *,Z. *從Y RIGHT OUTER JOIN Z使用(A,id)。 – Alfred 2011-04-26 03:30:57

0

沒錯,UNION不是答案。

我想你想:

SELECT * 
FROM x 
    JOIN y ON x.a = y.a 
    JOIN z ON x.a = z.a 
GROUB BY x.a; 
+0

這是錯誤的,因爲y和z中可能有多個記錄需要爲x中的每個記錄檢索。如果我通過x.a分組,我只能從每個表中獲取第一行。如果我按部分取出小組,我得到y和z的乘積。 – Alfred 2011-04-24 02:24:40

0

我發現了一種新的方式編輯這篇文章,這可以用來根據唯一的ID MERG兩條表 。
試試這個:

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

PostgreSQL是永遠正確的答案,大多數MySQL的問題,但你的問題可能已經解決了這個辦法:

您遇到的問題是,你有兩個左聯接,即

左連接X左加入Y,它必然會給你一個X X X Y其中你想(AXX)×(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

如果我理解正確的話,表XYZ一個1:n關係。所以,你看到的行爲是預期的。你得到的結果是一種交叉產品。

如果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