2012-03-28 36 views
5

我正在嘗試學習ansi-92 SQL標準,但我似乎並沒有完全理解它(我對ansi-89標準以及數據庫一般都不熟悉)。我誤解了聯結嗎?

在我的例子中,我有三個錶王國 - <家族 - <種(生物分類)。

  • 有可能是沒有物種和家庭的王國。
  • 可能有家庭沒有物種也沒有kindgoms。
  • 有可能是沒有王國或家庭的物種。

爲什麼會發生這種情況?

說的生物學家發現一個新物種,但他並沒有分爲王國或家庭這一點,創建一個新的家族,有沒有種,是不知道什麼王國它應該屬於等

這裏是一個小提琴(看最後一個查詢):http://sqlfiddle.com/#!4/015d1/3

我想做一個查詢,檢索我的每個王國,每個物種,但沒有那些沒有物種的家庭,所以我做這個。

select * 
    from reino r 
     left join (
      familia f    
      right join especie e 
       on f.fnombre = e.efamilia 
       and f.freino = e.ereino 
     ) on r.rnombre = f.freino 
      and r.rnombre = e.ereino; 

我認爲這會做的是:

  1. 家人團聚和物種右連接,所以它帶來的每一個物種,但不是那些沒有種家庭。所以,如果一個物種沒有被分類到一個家庭中,它就會在家庭中顯得無效。

  2. 然後,加入王國,結果作爲左連接,因此它帶來了每個王國,即使沒有家族或物種歸於該王國。

我錯了嗎?這不應該顯示那些未被分類的物種嗎?如果我做內部查詢它會帶來我想要的。我在分組的東西有問題嗎?

+0

這是否混亂與Oracle不?我的查詢中的查詢優化,是括號不必要的?我得到相同的結果嗎? oracle的命令是什麼? – Roger 2012-03-28 05:41:15

+0

@outis我必須恭敬地不同意這種連接語法不能嵌套。 [我相信,這篇文章討論這個話題(http://tonyhasler.wordpress.com/2009/02/22/parentheses-in-ansi-join-syntax/),並得出結論:可以使用括號明確的順序連接多個表時的操作。 – 2012-03-28 05:55:05

+0

@MichaelFredrickson:我糾正了。它就是SQL/Foundation§7.6。 – outis 2012-03-28 07:38:41

回答

2

你對#1的描述是正確的#你的查詢的問題在步驟#2。

當你從王國做一個left join到(家庭&種),你的要求每一個王國,即使沒有匹配(家庭&種)......然而,這將不會返回任何你(家庭&物種)組合沒有一個匹配的王國。

仔細查詢是:

select * 
    from reino r 
     full join (
      familia f    
      right join especie e 
       on f.fnombre = e.efamilia 
       and f.freino = e.ereino 
     ) on r.rnombre = f.freino 
      and r.rnombre = e.ereino; 

注意,left joinfull join取代...

然而,與某個物種有關這隻回報家人......它不會返回與王國但不種相關的任何家庭。

後重新閱讀你的問題,這其實是想你想......


編輯:在進一步的思考,你可以重新寫你的查詢,像這樣:

select * 
from 
    especie e 
    left join familia f 
     on f.fnombre = e.efamilia 
     and f.freino = e.ereino 
    full join reino r 
     on r.rnombre = f.freino 
     and r.rnombre = e.ereino; 

我認爲這將是preferrable,因爲你消除RIGHT JOIN,通常在爲是風格差皺起了眉頭......和括號,這可能會非常棘手,爲人們正確分析判斷的結果會是什麼。

+0

非常感謝,現在事情更清楚了。感謝您抽出時間:) – Roger 2012-03-28 05:33:16

+0

儘管還有一個問題;閱讀我對外部問題的評論。括號是否不必要?這是否與Oracle優化器混淆? – Roger 2012-03-28 05:36:33

+0

我不同意@outis ...但我主要在SQL Server中工作,所以這在Oracle中可能會有所不同。但是,根據我的經驗,括號可以影響結果以及執行計劃。 [這裏有一個我相信在Oracle中證實了這一點的源代碼。](http://tonyhasler.wordpress.com/2009/02/22/parentheses-in-ansi-join-syntax/)...我不確定如何在不使用括號的情況下重組查詢(可能必須將其更改爲子選擇),但如果可以,您可以比較兩種方法之間的執行計劃以確保您的原始方法是可以接受的 – 2012-03-28 05:51:04

0

嘗試使用此:

select * 
from reino r 
join especie e on (r.rnombre = e.ereino) 
join familia f on (f.freino = e.ereino and f.fnombre = e.efamilia) 

莫非,你互換表especie efamilia和enombre?

+0

我不是在尋找內部連接,無論如何謝謝。 – Roger 2012-03-28 05:37:32

2

如果這有助於:

相關地講,[OUTER JOIN是]一種奉子成婚的:它 力表成一種工會是的,我的意思是工會,沒有參加,甚至 當有問題的表不符合通常要求 聯合。它這樣做,實際上做了工會,從而使它們 符合這些要求通常畢竟之前填充一個或兩個 用空值表。但是,沒有任何 理由是填充不應該與正確的價值觀,而不是空的 來完成,如本例:

SELECT SNO , PNO 
FROM SP 
UNION 
SELECT SNO , 'nil' AS PNO 
FROM S 
WHERE SNO NOT IN (SELECT SNO FROM SP) 

以上等同於:

SELECT SNO , COALESCE (PNO , 'nil') AS PNO 
FROM S NATURAL LEFT OUTER JOIN SP 

來源: SQL and Relational Theory: How to Write Accurate SQL Code By C. J. Date

1

如果你想查詢重寫只有你所擁有的最輕微的變化,你可以改變LEFT加入到FULL加入。您可以進一步去除多餘的括號和r.rnombre = f.freinoON條件:

select * 
from reino r 
    full join      --- instead of LEFT JOIN 
     familia f    
     right join especie e 
      on f.fnombre = e.efamilia 
      and f.freino = e.ereino 
     on r.rnombre = e.ereino; 
           ---removed the: r.rnombre = f.freino  
+0

我想要最好的結果,我不在乎是否需要重新編寫它;什麼是最好的數據庫,爲什麼? – Roger 2012-03-28 15:37:45

+0

既然你只想要擁有物種的家庭,那麼就不需要'r.rnombre = f.freino'。從Join結構中刪除括號可能有或沒有任何作用,這取決於DBMS(並且我不是Oracle的專家,對此有任何意見)。 – 2012-03-28 15:50:37

+0

只是未成年人而已。這個查詢(以及邁克爾接受的查詢)將不包括具有王國(但沒有物種)的家族。 – 2012-03-28 15:53:19