SELEZIONARE più colonne tramite una sottoquery


18

Sto cercando di SELEZIONARE 2 colonne dalla sottoquery nella seguente query, ma non riesco a farlo. Ho provato a creare una tabella alias, ma non riuscivo ancora a ottenerli.

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);

Fondamentalmente, sto cercando di ottenere il lastComDate& lastPosterIDdalla stessa riga - la riga che è l'ultima nei commenti per l'animale specifico. Si prega di suggerire come posso ottenerli in modo efficiente.

La query sopra funziona, ma sembra eccessiva poiché la stessa riga viene recuperata due volte. Inoltre, la ORDER BYclausola è significativamente più lenta della funzione aggregata, come ho scoperto durante la profilazione della query. Pertanto, una soluzione che evita l'ordinamento sarebbe apprezzata.


1
Se nella tabella dei commenti fosse presente un indice (petid, id), l'ordine non sarà probabilmente lento, ma prima di tutto: sembra che la tua query richieda tutti gli animali domestici su cui userid userid 'ABC' negli ultimi due mesi, in cui deviceID non è "ABC" (sebbene non sia chiaro quale tabella deviceID sia una colonna, possibilmente animali domestici e possibilmente commenti) e chi fosse l'ultimo commentatore e la data dell'ultimo commento. È giusto?
Michael - sqlbot,

@ Michael-sqlbot - Sì, è esattamente quello che sto cercando di raccogliere. Il deviceIDda petstavolo - il che significa che proprio non mi scarica gli animali domestici che sono presentate da 'ABC' se stesso.
BufferStack

Risposte:


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)
;

Puoi anche estrarre la tua subquery in una tabella temporanea se le prestazioni vengono influenzate da qualche parte lungo la strada.


Ci avevo provato anche prima ... questo ritorna NULLper entrambi lastComDatee lastPosterIdper tutti i record.
BufferStack,

Hai qualche campione disponibile?
Valkyrie,

Come posso fornire i dati di esempio?
BufferStack,

Prova i suggerimenti in questo post: meta.stackexchange.com/questions/156729/…
Valkyrie

1
Va bene, ma SQLFiddle è meglio;). Vedi un esempio qui . Meglio vedere solo il codice e i dati seed, non alcune tabelle che dovrai formattare.
Marian,

6

Dato che i tuoi tavoli sono così:

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

Questa query dovrebbe fare il trucco:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.