2011-07-26 98 views
1

我的問題是玩!框架/ JPA特定。但我認爲它適用於一般的SQL語法。多個JOIN(SQL)

下面是一個簡單的示例查詢JOIN:

return Post.find(
    "select distinct p from Post p join p.tags as t where t.name = ?", tag 
).fetch(); 

它的簡單和行之有效的。

我的問題是:如果我想在同一個表中加入更多值,該怎麼辦?

(不工作,這是一個僞語法我創建):

return Post.find(
    "select distinct p from Post p join p.tags1 as t, p.tags2 as u, p.tags3 as v where t.name = ?, u.name = ?, v.name = ?", tag1, tag2, tag3, 
).fetch(); 
+1

您需要定義連接「在」某事。它看起來像只會以一切方式加入。 p.something = t.something – Narnian

+1

你在第一個查詢中加入了什麼?我只看到一張桌子? – Jacob

+1

@cularis這可能是一個自我加入,但我不知道爲什麼你想在這種情況下做到這一點。 –

回答

5

你的編程邏輯看起來不錯,但是SQL語句需要一些工作。看起來你是SQL新手,正如你所指出的,你似乎不明白JOIN是什麼。

您試圖從名爲POST,TAG1,TAG2和TAG3的4個表中選擇數據。

我不知道這些表中有什麼,並且很難給出沒有這些信息的示例SQL語句。所以,我打算做點什麼,只是爲了討論的目的。假設表POST有6列,並且其中有8行數據。

P Fname Lname Country Color Headgear 
- ----- ----- ------- ----- -------- 
1 Alex Andrews 1  1  0 
2 Bob Barker 2  3  0 
3 Chuck Conners 1  5  0 
4 Don Duck 3  6  1 
5 Ed Edwards 2  4  2 
6 Frank Farkle 4  2  1 
7 Geoff Good 1  1  0 
8 Hank Howard 1  3  0 

我們會說TAG1,TAG2和TAG3的查找表,每個只有2列。表TAG1有4個國家或地區代碼:

C Name 
- ------- 
1 USA 
2 France 
3 Germany 
4 Spain 

表TAG2有6個顏色代碼:

C Name 
- ------ 
1 Red 
2 Orange 
3 Yellow 
4 Green 
5 Blue 
6 Violet 

表TAG3有4個頭盔代碼:

C Name 
- ------- 
0 None 
1 Glasses 
2 Hat 
3 Monacle 

現在,當您選擇從這些數據4桌,對於P = 6,你試圖得到像這樣的東西:

Fname Lname Country Color Headgear 
----- ------ ------- ------ ------- 
Frank Farkle Spain Orange None 

第一件事情,讓我們看看你的WHERE子句:

where t.name = ?, u.name = ?, v.name = ? 

很抱歉,但使用逗號一樣,這是一個語法錯誤。通常情況下,您只想在所有3個條件都爲真的情況下查找數據;你用AND來做到這一點:

where t.name=? AND u.name=? AND v.name=? 

第二,你爲什麼要把表連接在一起?因爲你需要更多的信息。表POST表示Frank的COUNTRY值是4;表格TAG1說4表示西班牙。所以我們需要將這些表「加入」在一起。

古代(1980年以前,我認爲)連接表的方式是在FROM子句中列出多個表名,用逗號分隔。這給了我們:

SELECT P.FNAME, P.LNAME, T.NAME As Country, U.NAME As Color, V.NAME As Headgear 
FROM POST P, TAG1 T, TAG2 U, TAG3 V 

這個查詢的麻煩是你不告訴它你想要的行,或者它們如何相互關聯。所以數據庫產生一種叫做「笛卡兒積」的東西。你很想要一個Cartesian產品 - 這通常是一個巨大的錯誤。即使你的數據庫只中有22行,這個SELECT語句是要返回數據的768行:

Alex Andrews USA Red None 
Alex Andrews USA Red Glasses 
Alex Andrews USA Red Hat 
Alex Andrews USA Red Monacle 
Alex Andrews USA Orange None 
Alex Andrews USA Orange Glasses 
... 
Hank Howard Spain Violet Monacle 

這是正確的,它返回從4個表中的數據的每一個可能的組合。想象一下,POST表最終增長到20000行,而三個TAG表每個都有100行。整個數據庫將不到一兆字節,但笛卡爾積可能有20,000,000,000行數據 - 可能大約有120GB數據。任何數據庫引擎都會窒息而死。

所以,如果你想使用指定表的古代方式,確保你的WHERE子句顯示你查詢的每個表之間的關係是非常重要的。這使得更有意義:

SELECT P.FNAME, P.LNAME, T.NAME As Country, U.NAME As Color, V.NAME As Headgear 
FROM POST P, TAG1 T, TAG2 U, TAG3 V 
WHERE P.Country=T.C AND P.Color=U.C AND P.Headgear=V.C 

這隻返回8行數據。

使用古代的方式,很容易意外地創建笛卡爾產品,這幾乎總是不好的。所以他們修改了SQL,使其更難做到。這是JOIN關鍵字。現在,當您指定其他表格時,您可以指定它們同時如何關聯。新方法是:

SELECT P.FNAME, P.LNAME, T.NAME As Country, U.NAME As Color, V.NAME As Headgear 
FROM POST P 
INNER JOIN TAG1 T ON P.Country=T.C 
INNER JOIN TAG2 U ON P.Color=U.C 
INNER JOIN TAG3 V ON P.Headgear=V.C 

您仍然可以使用WHERE子句。

SELECT P.FNAME, P.LNAME, T.NAME As Country, U.NAME As Color, V.NAME As Headgear 
FROM POST P 
INNER JOIN TAG1 T ON P.Country=T.C 
INNER JOIN TAG2 U ON P.Color=U.C 
INNER JOIN TAG3 V ON P.Headgear=V.C 
WHERE P.P=? 

如果調用此並傳入值6,你只有一個行回:

Fname Lname Country Color Headgear 
----- ------ ------- ------ -------- 
Frank Farkle Spain Orange None 
+0

我應該提供更多關於我在做什麼的細節。無論如何,在這個時候,我不想再打擾你們了。你們每個人都真的幫助我理解。我可能誤解了JOIN背後的邏輯。真的很感謝你! – daliz

+0

這不是jpaq的工作原理。你剛剛做了一個sql示例。 – Gorky

3

正如在評論中提到的,你正在尋找一個ON條款。

SELECT * FROM TEST1 
     INNER JOIN TEST2 ON TEST1.A = TEST2.A AND TEST1.B = TEST2.B ... 
+0

你應該有一個內部連接的情況。 – HLGEM