2016-08-13 132 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