SÉLECTIONNER plusieurs colonnes via une sous-requête


18

J'essaie de sélectionner 2 colonnes de la sous-requête dans la requête suivante, mais je ne peux pas le faire. J'ai essayé de créer une table d'alias, mais je n'ai toujours pas pu les obtenir.

SELECT
  DISTINCT petid,
  userid,
  (SELECT MAX(comDate) FROM comments WHERE petid=pet.id) AS lastComDate,
  (SELECT userid FROM comments WHERE petid=pet.id ORDER BY id DESC LIMIT 1) AS lastPosterID
FROM 
  pet LEFT JOIN comments ON pet.id = comments.petid
WHERE 
  userid='ABC'      AND 
  deviceID!='ABC'   AND 
  comDate>=DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 2 MONTH);

Fondamentalement, j'essaye d'obtenir le lastComDate& à lastPosterIDpartir de la même ligne - la ligne qui est la dernière dans les commentaires pour l'animal spécifique. Veuillez suggérer comment puis-je les obtenir de manière efficace.

La requête ci-dessus fonctionne, mais semble excessive car la même ligne est récupérée deux fois. De plus, la ORDER BYclause est beaucoup plus lente que la fonction d'agrégation - comme je l'ai trouvé lors du profilage de la requête. Une solution évitant le tri serait donc appréciée.


1
Si vous aviez un index (petid, id) sur la table des commentaires, l'ordre par ne serait probablement pas lent, mais d'abord, il semble que votre requête demande tous les animaux de compagnie sur lesquels l'ID utilisateur 'ABC' a commenté au cours des deux derniers mois, où deviceID n'est pas `` ABC '' (bien qu'il ne soit pas clair dans quelle table deviceID est une colonne, éventuellement des animaux de compagnie et éventuellement des commentaires) et qui était le dernier commentateur et la dernière date de commentaire. Est-ce correct?
Michael - sqlbot

@ Michael-sqlbot - Oui, c'est exactement ce que j'essaie de rassembler. C'est deviceIDde la petstable - ce qui signifie que je ne reçois pas les animaux de compagnie qui sont soumis par 'ABC' lui-même.
BufferStack

Réponses:


13
SELECT DISTINCT petid, userid, lastComDate, lastPosterId
FROM 
    pet 
    LEFT JOIN comments ON pet.id = comments.petid 
    LEFT JOIN (
        SELECT MAX(comDate), userid, petid FROM comments GROUP BY userid
    ) a ON a.petid = pet.id
WHERE 
    userid='ABC' 
    AND deviceID!='ABC' 
    AND comDate>=DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 2 MONTH)
;

Vous pouvez également extraire votre sous-requête dans une table temporaire si les performances sont affectées quelque part en cours de route.


J'avais essayé ça plus tôt aussi ... ça revient NULLpour les deux lastComDateet lastPosterIdpour tous les disques.
BufferStack

Avez-vous des exemples de données disponibles?
Valkyrie

Comment puis-je fournir les exemples de données?
BufferStack

Essayez les astuces dans cet article: meta.stackexchange.com/questions/156729/…
Valkyrie

1
C'est bien, mais SQLFiddle est mieux;). Voir un exemple ici . Bien mieux que de simplement voir le code et les données de départ, pas une table que vous devrez formater.
Marian

6

Étant donné que vos tables ressemblent à ceci:

create table pet (id int, userid int, deviceid int);
create table comments (id int, petid int, comdate date);

Cette requête devrait faire l'affaire:

SELECT 
        p.id, 
        p.userid,
        (SELECT MAX(comDate)
         FROM comments
         WHERE petid = p.id
         AND comDate >= DATE_SUB(
                 CURRENT_TIMESTAMP, INTERVAL 2 MONTH)
               ) AS lastComDate,
        (SELECT userid
         FROM comments
         WHERE petid = p.id
         AND comDate >= DATE_SUB(
              CURRENT_TIMESTAMP, INTERVAL 2 MONTH
         ) ORDER BY id DESC LIMIT 1) AS lastPosterID
    FROM 
        pet p

    WHERE 
        p.userid=1
        AND p.deviceID!=1
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.