2010-11-11 82 views
0

我一直在以高效的方式從MySQL數據庫中檢索數據。MySQL:在HAVING子句之前限制結果集的問題

我有一個很多項目的表。每個項目可以具有狀態1,2或3.我想選擇具有特定狀態的項目,具體取決於其他表格中這些記錄的鏈接。

例子:

  • 的表items與字段:ID,名稱,狀態,...
  • 的表bought與字段:的itemId,用戶id
  • 的表rented與字段:的itemId,用戶id

說,我想這對於用戶id 123

  1. 所購買的全部記錄,具有都是租的狀態1
  2. 所有的記錄,具有狀態1或2
  3. 未購買或租借的所有記錄,其狀態3

我的選擇查詢現在看起來是這樣的:

SELECT 
    i.id, 
    i.name, 
    i.status, 
    // bought by this user? 
    SUM(IF(b.userId = 123, 1, 0)) AS bought, 
    // rented by this user? 
    SUM(IF(r.userId = 123, 1, 0)) AS rented, 

FROM items i 

LEFT JOIN bought b 
    ON b.itemId = i.id 

LEFT JOIN rented r 
    ON r.itemId = r.id 

GROUP BY i.id 

HAVING 
    // bought and status 1 
    (bought > 0 AND status = 1) 
    // rented and status 1 or 2 
    OR (rented > 0 AND status IN (1, 2) 
    // not bought or rented and status 3 
    OR (bougth = 0 AND rented = 0 AND status = 3) 

ORDER BY i.name ASC 

問題1
SELECT子句中的SUM部分是確定是否有鏈接到某個項目的其他表中的條目的好方法?假設每個用戶只有一個條目,總和將爲1或0,爲我提供所需的信息。但它似乎......不知何故怪異。

問題2
儘管這個作品,有一個很大的問題:它基本上檢索所有項目,然後使用HAVING條款過濾它們。由於有很多條目,查詢速度太慢了。我試圖找出如何解決這個問題。

我第一次嘗試WHERE條款..但如何?

... 
WHERE 
    // only items with status 1 if bought or rented 
    (t.status = 1 AND (bought > 0 OR rented > 0)) 
    // only items with status 2 if rented 
    OR (t.status = 2 AND rented > 0) 
    // only items with status 3 if not bought or rented 
    OR (t.status = 3 AND bought = 0 AND rented = 0) 
...

但是,您不能使用SELECT子句中的變量。並且由於項目表中沒有列rentedbought,所以這將不起作用。

我也嘗試使用用戶定義的變量,但這並沒有工作,要麼:

SELECT 
    ... 
    @bought := SUM(IF(b.userId = 123, 1, 0)) AS bought, 
... 
WHERE @bought = ... // does not work

然後我試圖一個子查詢,但我不能得到它使用的主要的查詢項目ID :

... 
WHERE 
    ... 
    // only items with status 2 if rented 
    OR (
    t.status = 2 
    AND (
     SELECT COUNT(r2.userId) 
     FROM rented r2 
     WHERE r2.userId = 123 
     AND r2.itemId = i.itemId // it doesn't recognize i.itemId 
    ) > 0 
) 
    ...

任何想法?我還想將所有內容都保存在一個查詢中。這只是一個簡單的例子,但實際的一個比較大。我敢肯定,我可以將所有事情分開,並使用各種查詢分別收集所有內容,但這隻會增加很多的代碼,並且不會使維護更容易。

+0

是最終的結果集輸出'bought'和'rented'列必要的,或者是他們那裏只是爲了利用列別名? – 2010-11-11 02:55:43

+0

他們也有必要以後區分項目。 – Alec 2010-11-11 03:44:52

回答

1

使用兩個子查詢(一個用於購買,一個用於租用),然後將它們連接到主查詢中的用戶表。

編輯:原諒我的MySQL,它已經有一段時間,但我腦子裏想的是這樣的:

select i.id, i.name, i.status, ifnull(b.TotalBought,0) AS ItemsBought, ifnull(r.TotalRented,0) AS ItemsRented 
FROM items i 
LEFT JOIN (select itemid, COUNT(*) AS TotalBought FROM bought WHERE userid=123 GROUP BY itemid) AS b ON b.itemid=i.itemid 
LEFT JOIN (select itemid, COUNT(*) AS TotalRented FROM rented WHERE userid=123 GROUP BY itemid) AS r ON r.itemid=i.itemid 
WHERE (i.status=1 AND ifnull(b.TotalBought,0)>0) 
OR (ifnull(r.TotalRented,0) >0 AND i.status in(1,2) 
OR (ifnull(b.TotalBought,0)=0 AND ifnull(r.TotalRented,0) =0 AND i.status=3) 
ORDER BY i.name ASC 
+0

這些子查詢應該放在哪裏?並且查詢中沒有用戶表,只是對特定用戶ID的引用。以及LEFT JOIN將如何限制結果集? – Alec 2010-11-11 03:47:39

+0

啊,檢查!我明白你的意思了。玩了一段時間,它似乎工作!謝謝。 – Alec 2010-11-11 16:53:34