【问题标题】:Help combining these two queries帮助合并这两个查询
【发布时间】:2010-05-03 01:59:36
【问题描述】:

我需要一个返回与以下 SQL 查询中的任何一个匹配的结果的 SQL 查询:

查询 1:

SELECT "annotations".* FROM "annotations" INNER JOIN "votes" ON "votes".voteable_id = "annotations".id AND "votes".voteable_type = 'Annotation'
WHERE (votes.vote = 't' AND votes.voter_id = 78)

查询 2:

SELECT "annotations".* FROM "annotations" INNER JOIN "songs" ON "songs".id = "annotations".song_id INNER JOIN "songs" songs_annotations ON "songs_annotations".id = "annotations".song_id INNER JOIN "users" ON "users".id = "songs_annotations".state_last_updated_by_id
WHERE (annotations.referent IS NOT NULL AND annotations.updated_at < '2010-04-05 01:51:24' AND (body = '?' OR body LIKE '%[?]%') AND ((users.id = songs.state_last_updated_by_id and users.needs_edit = 'f' and songs.state != 'work_in_progress') OR (songs.state = 'published'))

这是我尝试过的,但它不起作用:

SELECT "annotations".* FROM "annotations" INNER JOIN "songs" ON "songs".id = "annotations".song_id INNER JOIN "songs" songs_annotations ON  "songs_annotations".id = "annotations".song_id INNER JOIN "users" ON "users".id = "songs_annotations".state_last_updated_by_id  INNER JOIN "votes" ON "votes".voteable_id = "annotations".id AND "votes".voteable_type = 'Annotation' WHERE ((votes.vote = 't' and votes.voter_id = 78) OR (annotations.referent IS NOT NULL and annotations.updated_at < '2010-04-05 01:43:52' and (annotations.body = '?' OR annotations.body LIKE '%[?]%') and ((users.id = songs.state_last_updated_by_id and users.needs_edit = 'f') OR songs.state = 'published')))

【问题讨论】:

    标签: sql mysql ruby-on-rails


    【解决方案1】:

    UNION 是最简单的。如果您的引擎的优化器不能有效地完成这项工作,我可能会更深入地研究(但其他任何事情都可能涉及大量 LEFT JOIN,因为看起来您正在加入注释的两种不同用途):

    SELECT "annotations".*
    FROM "annotations"
    INNER JOIN "votes"
        ON "votes".voteable_id = "annotations".id 
        AND "votes".voteable_type = 'Annotation'
    WHERE (votes.vote = 't' AND votes.voter_id = 78)
    UNION
    SELECT "annotations".*
    FROM "annotations"
    INNER JOIN "songs"
         ON "songs".id = "annotations".song_id
    INNER JOIN "songs" songs_annotations
         ON "songs_annotations".id = "annotations".song_id
    INNER JOIN "users"
         ON "users".id = "songs_annotations".state_last_updated_by_id
    WHERE (annotations.referent IS NOT NULL 
         AND annotations.updated_at < '2010-04-05 01:51:24' 
         AND (body = '?' OR body LIKE '%[?]%')
         AND ((users.id = songs.state_last_updated_by_id and users.needs_edit = 'f' and songs.state != 'work_in_progress') OR (songs.state = 'published'))
    

    出于同样的原因,您的 INNER JOIN 尝试失败(必须满足所有连接条件),您必须将几乎所有内容更改为 LEFT JOIN(或将 LEFT JOIN 更改为嵌套的 INNER JOIN) - 我认为 UNION 是最简单的。

    SELECT "annotations".*
    FROM "annotations"
    LEFT JOIN "votes"
        ON "votes".voteable_id = "annotations".id 
        AND "votes".voteable_type = 'Annotation'
    LEFT JOIN "songs"
         ON "songs".id = "annotations".song_id
    LEFT JOIN "songs" songs_annotations
         ON "songs_annotations".id = "annotations".song_id
    LEFT JOIN "users"
         ON "users".id = "songs_annotations".state_last_updated_by_id
    WHERE (votes.vote = 't' AND votes.voter_id = 78)
         OR
         (annotations.referent IS NOT NULL 
         AND annotations.updated_at < '2010-04-05 01:51:24' 
         AND (body = '?' OR body LIKE '%[?]%')
         AND ((users.id = songs.state_last_updated_by_id and users.needs_edit = 'f' and songs.state != 'work_in_progress') OR (songs.state = 'published'))
    

    【讨论】:

    • 这是一个好方法——不幸的是我试图把它放在 Rails 中的 named_scope 中,而 named_scopess 不支持 UNION
    • @Horace Loeb - 查看所有 LEFT JOIN 解决方案。优化器通常不能很好地处理这个问题 - 不仅 LEFT JOIN 会阻碍重新排序过滤器操作,WHERE 中的 OR 子句也可能会进行更多的扫描。
    • @Horace Loeb - 当然,对于您的模型,所有 LEFT JOIN 解决方案可能(很可能)在语义上不正确......
    • 注意事项不谈,看起来这行得通!你是个天才,凯德! (查询rapgenius.com,喜欢说唱的可以去看看)
    猜你喜欢
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 2016-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-06
    相关资源
    最近更新 更多