简体   繁体   中英

Reuse result of a correlated subquery

I have a table media_tags containing two columns linking media to user defined tags. I want to do some queries selecting media with complicated conditions on the tags. My current solution is using the same correlated subquery multiple times.

Multiple SO answers have pointed me to CTEs but as far as i understand it those can only be used to replace uncorrelated subqueries.

SELECT outer.media_id
FROM media_tags AS outer
WHERE 1 IN (SELECT tag_id FROM media_tags AS inner WHERE outer.media_id = inner.media_id)
AND 2 NOT IN (SELECT tag_id FROM media_tags AS inner WHERE outer.media_id = inner.media_id)
AND (3 IN (SELECT tag_id FROM media_tags AS inner WHERE outer.media_id = inner.media_id)
OR 4 IN (SELECT tag_id FROM media_tags AS inner WHERE outer.media_id = inner.media_id));

How about using not exists ?

SELECT m2.media_id
FROM media_tags mt
WHERE NOT EXISTS (SELECT tag_id
                  FROM media_tags mt2
                  WHERE mt2.media_id = mt.media_id AND
                        mt2.tag_id IN (1, 2, 3, 4)
                 );

You can do a self join, GROUP BY media_id and set the conditions in the HAVING clause:

SELECT outer.media_id
FROM media_tags AS outer INNER JOIN media_tags AS inner
ON outer.media_id = inner.media_id
GROUP BY outer.media_id
HAVING 
  SUM(inner.tag_id = 1) > 0
  AND
  SUM(inner.tag_id = 2) = 0
  AND
  SUM(inner.tag_id IN (3, 4)) > 0

or even simpler without the self join check if this works also:

SELECT media_id
FROM media_tags
GROUP BY media_id
HAVING 
  SUM(tag_id = 1) > 0
  AND
  SUM(tag_id = 2) = 0
  AND
  SUM(tag_id IN (3, 4)) > 0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM