2016-08-13 130 views
0

我正在測驗網站上工作,需要基於他們剛剛進行的測驗來建議用戶可能會喜歡的測驗。基本上,如果他們剛剛參加的測驗有一個標籤,我需要使用相同的標籤再抽取一次測驗。否則,請從同一類別中抽取另一個測驗。MySQL根據多個表條件選擇

我的工作方式是按照我希望的方式工作90%,但對我來說這似乎很笨重。不工作的10%是我忘了添加一個條件,它只提取活動的測驗。就像WHERE q.active = 1,但無論我在哪裏或如何添加該條件,它都無法按計劃運行。我要麼獲得一個空集或者在條件被添加之前得到的結果相同。

編輯:

爲了澄清,讀取由@RiggsFolly評論後...

如果我添加AND q.active = 1給我的第一WHERE條款,只有一個其他測驗同一個標籤,它是不活躍我收到一個空集,而不是從類別選擇語句接收結果。將AND q.active = 1僅添加到類別選擇語句,而不是標記選擇語句返回適當的結果,如果沒有使用相同標記的測驗。

SELECT 
    IFNULL(q.meta_title, q.title) AS title, 
    IFNULL(url, title) AS url, 
    1 istag 
FROM tag_index t 
LEFT JOIN tag_index ti 
    ON ti.tag_id = t.tag_id 
LEFT JOIN quizzes q 
    ON q.id = ti.quiz_id 
WHERE t.quiz_id = :quiz_id 
    AND ti.quiz_id != t.quiz_id 

UNION ALL 

SELECT 
    IFNULL(q.meta_title, q.title) AS title, 
    IFNULL(url, title) AS url, 
    0 istag 
FROM category_index c 
LEFT JOIN category_index ci 
    ON ci.category_id = c.category_id 
LEFT JOIN quizzes q 
    ON q.id = ci.quiz_id 
WHERE c.quiz_id = :quiz_id 
    AND ci.quiz_id != c.quiz_id 
    AND NOT EXISTS 
     (SELECT 1 FROM tag_index WHERE quiz_id = :quiz_id) 
ORDER BY RAND() LIMIT 1 

任何幫助或建議將不勝感激!

+0

您應該多加一點美化這個SQL,多行,空行和縮進。 –

+1

那麼,在你的where子句中加上'AND q.active = 1' – RiggsFolly

+0

@ Tiberiu-IonuţStan讓SQL語句變得很漂亮絕對不是我的強項之一。我編輯了我的帖子,使其更清晰易讀。感謝您的建議! – Jay

回答

0

您還需要添加active = 1條件到您的子查詢:

SELECT 
    IFNULL(q.meta_title, q.title) AS title, 
    IFNULL(url, title) AS url, 
    1 istag 
FROM tag_index t 
LEFT JOIN tag_index ti 
    ON ti.tag_id = t.tag_id 
LEFT JOIN quizzes q 
    ON q.id = ti.quiz_id 
WHERE t.quiz_id = :quiz_id 
    AND ti.quiz_id != t.quiz_id 
    AND q.active = 1 

UNION ALL 

SELECT 
    IFNULL(q.meta_title, q.title) AS title, 
    IFNULL(url, title) AS url, 
    0 istag 
FROM category_index c 
LEFT JOIN category_index ci 
    ON ci.category_id = c.category_id 
LEFT JOIN quizzes q 
    ON q.id = ci.quiz_id 
WHERE c.quiz_id = :quiz_id 
    AND ci.quiz_id != c.quiz_id 
    AND q.active = 1 
    AND NOT EXISTS 
     (SELECT 1 
     FROM tag_index t 
     JOIN tag_index ON ti.tag_id = t.tag_id 
     JOIN quizzes ON q.id = ti.quiz_id 
     WHERE t.quiz_id = :quiz_id 
      AND ti.quiz_id != t.quiz_id 
      AND q.active = 1) 
ORDER BY RAND() LIMIT 1 

但是你不需要那麼再選擇在所有你可以通過istag第一順序:

SELECT 
    IFNULL(q.meta_title, q.title) AS title, 
    IFNULL(url, title) AS url, 
    1 istag 
FROM tag_index t 
LEFT JOIN tag_index ti 
    ON ti.tag_id = t.tag_id 
LEFT JOIN quizzes q 
    ON q.id = ti.quiz_id 
WHERE t.quiz_id = :quiz_id 
    AND ti.quiz_id != t.quiz_id 
    AND q.active = 1 

UNION ALL 

SELECT 
    IFNULL(q.meta_title, q.title) AS title, 
    IFNULL(url, title) AS url, 
    0 istag 
FROM category_index c 
LEFT JOIN category_index ci 
    ON ci.category_id = c.category_id 
LEFT JOIN quizzes q 
    ON q.id = ci.quiz_id 
WHERE c.quiz_id = :quiz_id 
    AND ci.quiz_id != c.quiz_id 
    AND q.active = 1 
ORDER BY istag DESC, RAND() LIMIT 1 
+0

謝謝你的回覆。不幸的是,如果只有1個測試具有相同的標籤並且它不是活動的,那麼仍會返回一個空集。 – Jay

+0

錯過了第二次加入。您的原始狀況沒有變化,可以理解爲「不存在任何**標籤:qiuz_id」。 –

0

簡易解決方案

在我看來,加載有問題的測驗的tag_id和category_id。然後像你嘗試一樣使用UNION運行一個簡單的查詢。這將簡化很多事情並減少連接數量。

要與大的查詢

SELECT 
    quiz_pool.quiz_id id, 
    IFNULL(q.meta_title, q.title) AS title, 
    IFNULL(q.url, q.title) AS url 
FROM (

    /* IDs of all quizzes with same tag */ 
    SELECT ti.quiz_id, istag = 1 
    FROM tag_index ti 
    WHERE ti.tag_id IN(SELECT tag_id FROM tag_index WHERE quiz_id = :quiz_id) 
     AND ti.quiz_id <> :quiz_id 
    LIMIT 0, :quiz_count 

    UNION ALL 

    /* IDs of all quizzes with same category */ 
    SELECT ci.quiz_id, istag = 0 
    FROM category_index ci 
    WHERE ci.category_id IN(SELECT category_id FROM category_index WHERE quiz_id = :quiz_id) 
     AND ci.quiz_id <> :quiz_id 
    LIMIT 0, :quiz_count 

) quiz_pool 
INNER JOIN quizzes q ON q.id = quiz_pool.quiz_id AND q.active = 1 
ORDER BY quiz_pool.istag DESC, RAND() 
LIMIT 0, :quiz_count 

這裏做這一切,你可以設置:quiz_count,你想取回按你的邏輯測驗的次數。它將首先查找具有相同標籤的測驗,然後從同一類別進行測驗,並將測驗隨機化。

希望它有幫助。

+0

謝謝你的回覆!我希望這種方法能夠解決問題,因爲它似乎這樣做會使添加附加條件變得更容易,但是如果標籤中沒有測驗是活動的,我仍會收到一個空集。 – Jay