James Moriarty: UNION in IN() als Teil einer WHERE-Klausel?

Beitrag lesen

Sehr subtiler Fehler :)

Das geht:

(SELECT id FROM entries WHERE spam = 0 ORDER BY time DESC LIMIT 6)
UNION
(SELECT id FROM entries WHERE spam = 0 ORDER BY edited DESC LIMIT 6)

Aber das nicht:

SELECT * FROM
(SELECT id FROM entries WHERE spam = 0 ORDER BY time DESC LIMIT 6)
UNION
(SELECT id FROM entries WHERE spam = 0 ORDER BY edited DESC LIMIT 6)

Und die Meldung lautet hier: #1248 - Every derived table must have its own alias !

Mit einem Alias geht der Fehler weg:

SELECT * FROM
(SELECT id FROM entries WHERE spam = 0 ORDER BY time DESC LIMIT 6) E
UNION
(SELECT id FROM entries WHERE spam = 0 ORDER BY edited DESC LIMIT 6)

Aber das ist ja für die IN-Klausel nicht das, was Du willst. Und einen Alias-Namen DIREKT innerhalb einer IN Klausel nimmt der Bursche auch nicht.

Das Problem sind die Klammern um die beiden Subselects, die sind nicht nötig und führen nur dazu, dass sie als namenspflichtige Subselects behandelt werden. Das brauchst Du aber gar nicht.

SELECT  id, user_id, name, time, subject, category
FROM entries LEFT JOIN userdata ON userdata.user_id = entries.user_id
WHERE entries.id IN (SELECT id FROM entries WHERE spam = 0 ORDER BY time DESC UNION SELECT id FROM entries WHERE spam = 0 ORDER BY edited DESC)

behebt das Alias-Problem, aber leider muss man die LIMITs weglassen, sonst liefert MySQL 5.6.33 diese Meldung:

This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'

Welche MySQL Version das unterstützt, habe ich nicht wirklich herausgefunden, aber wir haben Glück, es gibt einen Workaround (Quelle). Man tarnt die LIMITs durch einen dazwischengeschobenen Subselect:

SELECT  id, user_id, name, time, subject, category
FROM entries LEFT JOIN userdata ON userdata.user_id = entries.user_id
WHERE entries.id IN (
   SELECT id 
   FROM (SELECT id FROM entries WHERE spam = 0 ORDER BY time DESC LIMIT 6
         UNION
         SELECT id FROM entries WHERE spam = 0 ORDER BY edited DESC LIMIT 6) X )

Beachte das X zwischen den beiden letzten Klammern, sonst kommt wieder die Meldung mit dem fehlenden Alias.

Getestet auf MySQL 5.6.33.

J