2010-01-25 22 views
2

非耦合的產品清單。我不是在SQL好,我碰到過,我不知道如何解決的一個問題。我已經閱讀並重新閱讀了一本關於SQL的書(O'Reilly的Learning SQL),希望它能包含我需要的信息,但我還沒有找到它。SQL:獲取使用MySQL 4

我的問題如下。我將用一個簡化的例子來使討論更容易。

我有三個表,汽車,RIM和兩個組合:carRim。

car 
    carId 
    description 

rim 
    rimId 
    description 

carRim 
    carRimId 
    carId 
    rimId 
    price 

在表carRim我有價格的一個額外的屬性,因爲輪輞的價格是每個型號的車可能不同。我有一個限制,就是每種類型的輪輞只能與每種類型的汽車配對一次。所以所有的車圈組合都應該是獨一無二的。

如果我想的邊緣添加到車,我需要一個尚未耦合到汽車輪的列表。爲此,我認爲我需要輪輞表和carRim表,分別​​列出輪輞的總列表和已經連接到我想要添加輪輞的車的carRim的列表。

我寫的(簡單)查詢,使輪輞是連接到特定的汽車名單,在下面的例子中車carId 9

SELECT 
    * 
FROM 
    rims 
INNER JOIN 
    carRims 
ON 
    carRims.rimId = rim.rimId 
WHERE 
    carRims.carId = 9 

但現在我需要還沒有連接到特定汽車的輪輞清單。問題是,如果我做一個左外部連接,我得到的列表是「污染」了其他車的輪輞耦合,所以「WHERE carRims.carId IS NULL」的過濾條件不起作用。

SELECT 
    * 
FROM 
    rims 
LEFT OUTER JOIN 
    carRims 
ON 
    carRims.rimId = rim.rimId 
WHERE 
    carRims.carId IS NULL 

另一個挑戰是,我不能使用任何新的語法與MySQL 5,如子查詢,因爲我的客戶是使用MySQL 4此時無法升級。

可以爲這個問題的查詢在MySQL 4寫的,我懷疑它可以。

謝謝!

+0

對於「污染」與其他車輛的輪輞聯軸器。在這個例子中,我看不到任何主信息,它定義了哪些輪輞可以與哪些汽車相關聯。現在它只被定義爲輪輞,汽車和輪輞汽車關係中的價格。你能解釋一下,你想如何保存這些信息,以保證你的結果不被污染。 –

+0

任何車輪都可以連接到任何車輛,但只能連接一次。 carRim表中的連接(自然)。 –

+0

您的查詢將受益於鏈接表上的'(carId,rimID)''PRIMARY KEY'。 – Quassnoi

回答

1

你可以把多餘的條件在左外連接ON表達式中。你需要的是從carRims符合您rims行,屬於車牌號碼9,右行?

SELECT 
    * 
FROM 
    rims 
LEFT OUTER JOIN 
    carRims 
ON 
    carRims.rimId = rim.rimId 
    AND carRims.carId = 9 
WHERE 
    carRims.carId IS NULL 

如果有其他車輛其他carRims,他們將通過ON子句中的額外條件過濾掉。


回覆您的問題在哪裏放條件,在JOINWHERE子句中:

對於連接,它很重要,你把比較。 JOIN子句中的條件用於測試一個表中的行是否與另一個表中的行匹配。在我們測試比賽之後,我們如何處理來自各個表格的行取決於連接的類型。

對於外部聯接,我們希望從rims開始的行即使在carRims中沒有匹配的行。如果我們將carID = 9條件放在WHERE條款中,該怎麼辦?

FROM rims r LEFT OUTER JOIN carRims c ON r.rimId = c.rimID 
WHERE c.carID = 9 

這裏發生了什麼:在外部聯接返回的所有行rims,從carRims行相匹配的rimID包括有虛假carID值的行。只有的汽車匹配給定的輪輞,它是否使用NULL作爲c.*列。

但隨後WHERE條款消除了加入產生的所有行,除非carID是這意味着它也消除了其中carID爲NULL值9,這是它消除了任何RIM行匹配沒有汽車。因此結果等於INNER JOIN的結果。

所以我們需要在行加入rims之前排除carRims行中錯誤的carID行。

FROM rims r LEFT OUTER JOIN carRims c ON r.rimId = c.rimID AND c.carID = 9 

這是一個條件,該單獨表中的行可以匹配另一個連接表中的行。

很多書說你可以自由混合條款ON條款和WHERE條款。但是在所有情況下都不是這樣。它適用於INNER JOIN,因爲最終結果是相同的。這也適用於只適用於左表中左連接的條件,例如:

FROM rims r LEFT OUTER JOIN carRims c ON r.rimId = c.rimID AND r.make = 'ABC Rims' 

FROM rims r LEFT OUTER JOIN carRims c ON r.rimId = c.rimID 
WHERE r.make = 'ABC Rims' 

對於一個左外上表的條件加入,它確實無論你在哪裏把條件。東西


還有一個評論對你說:

約束我是,每一種類型的邊緣時,才應一次連接到每一個類型的車。所以所有的車圈組合都應該是獨一無二的。

那麼你有沒有聲明UNIQUE約束carRims(carId,rimId)

+0

對於我的完整答案,請參閱我自己的答案。 我還沒有宣佈UNIQUE約束,但這是一個好主意。 –

+0

感謝您的更新和非常完整的答案。這本書確實沒有說清楚。我已經向該書的網站提交了一份勘誤表。 –

2
SELECT * 
FROM rims r 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM carRims cr 
     WHERE cr.rimId = r.RimId 
       AND cr.carID = 9 
     ) 

更新:

要改寫NOT EXISTSLEFT JOIN/IS NULL,你需要把所有的條件進入的ON子句聯接:

SELECT r.* 
FROM rims r 
LEFT OUTER JOIN 
     carRims cr 
ON  cr.rimId = r.rimId 
     AND cr.crID = 9 
WHERE cr.carId IS NULL 
+0

正如我的問題所述,我使用MySQL 4,所以我不能使用子查詢。 –

+0

'@Niels Bom':據我所知,MySQL 4.1'支持'EXISTS'。你有'4.0'嗎? – Quassnoi

+0

我正在使用MySQL 4.1.16,並且已經在我的數據庫上測試過您的查詢,它確實運行,但它不會返回正確的結果集。即使輪輞沒有連接到我想連接新輪輞的汽車,但如果該輪輞與任何其他車輛相連,它也不會返回輪輞。 另外,顯然我不明白子查詢,爲什麼這個查詢之間的括號不是一個子查詢的一部分? –

0

(我需要一些更多的空間來闡述,評論沒有足夠的字符)

@Bill Karwin 您所提供的查詢是正確的答案,我的問題。謝謝!

我想要的是連接到特定汽車的而不是的行(輪輞)列表。

在「Learning SQL」一書中,我讀到查詢中過濾器和連接條件的位置並不重要。他們給出了一個內部連接的例子,其中有1個連接條件(在ON子句之後)和1個過濾條件(在WHERE子句之後)。他們表明,不管你在ON子句之後還是在WHERE子句之後放置這兩個條件都無關緊要。

考慮到這一點,我不明白你的解決方案的一部分。如果條件

carRims.carId = 9 

和條件

carRims.carId IS NULL 

都存在,那豈不是導致空結果?因爲沒有字段可以同時爲9和NULL嗎?然後

我的懷疑是:JOIN子句在條件位置的約束,你不能只是把他們的WHERE子句。

這是正確的嗎?

+0

我會用一些解釋來編輯我的答案。 –