How to replace OR operator with UNION operator?

前端 未结 3 2039
孤街浪徒
孤街浪徒 2021-01-22 12:02

Here is my query:

SELECT 
    h.id,
    h.subject,
    h.body matnF,
    h.amount,
    h.keywords tags,
    h.closed,
    h.author_id author,
    h.AcceptedAnswe         


        
相关标签:
3条回答
  • 2021-01-22 12:37

    If you are going to get any advantage from using a UNION instead of an OR then make that portion of the query as tiny as it can be, in particular keep the number of columns to a minimum. Do the union before any other joins. I suggest this:

    SELECT
          h.id
        , h.subject
        , h.body      AS matnF
        , h.amount
        , h.keywords  AS tags
        , h.closed
        , h.author_id AS author
        , h.AcceptedAnswer
        , h.type
        , h.visibility
        , h.date_time
        , v.value     AS vote_value
        , u.reputation
        , u.user_fname
        , u.user_lname
        , u.avatar
        , h.author_id AS hasUserId
        , (     SELECT COALESCE(SUM(vv.value), 0)
                FROM votes vv
                WHERE h.id = vv.post_id
                      AND vv.table_code = '$this->table_code'
          )  AS total_votes
        , (     SELECT COUNT(1)
                FROM favorites ff
                WHERE h.type = 0 AND h.id = ff.post_id
                      AND ff.table_code = '$this- >table_code'
          ) AS total_favorites
        , CASE
                WHEN h.type = 0 AND f.id IS NOT NULL THEN '2'
                ELSE '3'
          END  AS favorite
        , CASE
                WHEN h.type = 1 THEN '0'
                WHEN h.amount IS NULL OR h.author_id = :user_id2 THEN '1'
                ELSE EXISTS( select 1
                    from money m
                    where m.user_id = :user_id3 and m.post_id = h.id
                   )
          END paid
    FROM (
          SELECT q.id , q.author_id , q.visibility , q.type FROM quanda q WHERE q.id = :id1
          UNION
          SELECT q.id , q.author_id , q.visibility , q.type FROM quanda q WHERE q.related = :id2
          ) h
          LEFT JOIN votes v ON h.id = v.post_id
                      AND v.user_id = :user_id4
                      AND v.table_code = '$this->table_code'
          LEFT JOIN favorites f ON h.type = 0
                      AND h.id = f.post_id
                      AND f.user_id = :user_id5
                      AND f.table_code = '$this->table_code'
          LEFT JOIN users u ON h.author_id = u.id
                      AND h.visibility = 1
    
    0 讨论(0)
  • 2021-01-22 12:57

    The first thing I would try is a subquery:

    from ((select q.* from quanda q where q.id = :id1) union
          (select q.* from quanda q where q.related = :id2)
         ) left join
         . . .
    

    Note: This really wants indexes on quanda(id) and quanda(related) for performance.

    If few rows are selected, then this might be much faster.

    0 讨论(0)
  • 2021-01-22 12:59

    You may give it a try:

    SELECT h.id, h.subject, h.body matnF, h.amount, h.keywords tags, h.closed, h.author_id author, h.AcceptedAnswer, h.type, h.visibility, h.date_time, v.value AS vote_value, u.reputation, u.user_fname, u.user_lname, u.avatar, (h.author_id = :user_id1) as hasUserId,
    (select COALESCE(sum(vv.value),0) from votes vv where h.id = vv.post_id and vv.table_code = '$this->table_code') as total_votes,
    (select count(1) from favorites ff where h.type = 0 and h.id = ff.post_id and ff.table_code = '$this->table_code') as total_favorites,
    CASE WHEN h.type = 1 THEN '0'
    WHEN h.amount IS NULL OR h.author_id = :user_id2 THEN '1'
    ELSE EXISTS (select 1 from money m where m.user_id = :user_id3 and m.post_id = h.id) END paid,
    CASE WHEN h.type = 0 AND f.id IS NOT NULL THEN '2' ELSE '3' END AS favorite
    FROM qanda h
    LEFT JOIN votes v ON h.id = v.post_id AND v.user_id = :user_id4 AND v.table_code = '$this->table_code'
    LEFT JOIN favorites f ON h.type = 0 AND h.id = f.post_id AND f.user_id = :user_id5 AND f.table_code = '$this->table_code'
    LEFT JOIN users u ON h.author_id = u.id and h.visibility = 1
    WHERE h.id = :id1 
    ORDER BY h.type, /*(tans.id IS NOT NULL) DESC,*/ h.AcceptedAnswer DESC, h.date_time
    LIMIT 20
    
    UNION 
    
    SELECT 
    *
    FROM 
    (SELECT h.id, h.subject, h.body matnF, h.amount, h.keywords tags, h.closed, h.author_id author, h.AcceptedAnswer, h.type, h.visibility, h.date_time, v.value AS vote_value, u.reputation, u.user_fname, u.user_lname, u.avatar, (h.author_id = :user_id1) as hasUserId,
    (select COALESCE(sum(vv.value),0) from votes vv where h.id = vv.post_id and vv.table_code = '$this->table_code') as total_votes,
    (select count(1) from favorites ff where h.type = 0 and h.id = ff.post_id and ff.table_code = '$this->table_code') as total_favorites,
    CASE WHEN h.type = 1 THEN '0'
    WHEN h.amount IS NULL OR h.author_id = :user_id2 THEN '1'
    ELSE EXISTS (select 1 from money m where m.user_id = :user_id3 and m.post_id = h.id) END paid,
    CASE WHEN h.type = 0 AND f.id IS NOT NULL THEN '2' ELSE '3' END AS favorite
    FROM qanda h
    LEFT JOIN votes v ON h.id = v.post_id AND v.user_id = :user_id4 AND v.table_code = '$this->table_code'
    LEFT JOIN favorites f ON h.type = 0 AND h.id = f.post_id AND f.user_id = :user_id5 AND f.table_code = '$this->table_code'
    LEFT JOIN users u ON h.author_id = u.id and h.visibility = 1
    WHERE h.id = :id2 
    ORDER BY h.type, /*(tans.id IS NOT NULL) DESC,*/ h.AcceptedAnswer DESC, h.date_time
    LIMIT 20) t;
    

    Note: Replace UNION by UNION ALL if you want to allow duplicates in your final result set.

    0 讨论(0)
提交回复
热议问题