PILIH beberapa kolom melalui subquery

18

Saya mencoba untuk MEMILIH 2 kolom dari subquery dalam permintaan berikut, tetapi tidak dapat melakukannya. Sudah mencoba membuat tabel alias, tetapi masih belum bisa mendapatkannya.

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

Pada dasarnya, saya mencoba untuk mendapatkan lastComDate& lastPosterIDdari baris yang sama - baris yang terbaru dalam komentar untuk hewan peliharaan tertentu. Tolong sarankan bagaimana saya bisa mendapatkannya dengan cara yang efisien.

Kueri di atas berfungsi, tetapi tampaknya berlebihan karena baris yang sama diambil dua kali. Selain itu, ORDER BYklausa secara signifikan lebih lambat daripada fungsi agregat - seperti yang saya temukan saat membuat profil kueri. Jadi, solusi menghindari penyortiran akan dihargai.

BufferStack
sumber
1
Jika Anda memiliki indeks (petid, id) di tabel komentar, urutan dengan tidak akan cenderung lambat, tetapi hal pertama yang pertama: Tampaknya seolah-olah permintaan Anda meminta semua hewan peliharaan di mana userid 'ABC' telah mengomentari mereka dalam dua bulan terakhir, di mana deviceID bukan 'ABC' (meskipun tidak jelas tabel mana deviceID adalah kolom, mungkin hewan peliharaan dan mungkin komentar) dan siapa komentator terakhir, dan tanggal komentar terakhir. Apakah itu benar?
Michael - sqlbot
@ Michael-sqlbot - Ya, itulah yang ingin saya kumpulkan. The deviceIDadalah dari petsmeja - yang berarti bahwa hanya tidak mendapatkan saya hewan peliharaan yang disampaikan oleh 'ABC' dirinya.
BufferStack

Jawaban:

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

Anda juga dapat menarik subquery Anda ke tabel temp jika kinerja menjadi terpengaruh di suatu tempat.

Valkyrie
sumber
Saya telah mencoba ini sebelumnya juga ... ini mengembalikan NULLuntuk kedua lastComDate& lastPosterIduntuk semua catatan.
BufferStack
Apakah Anda memiliki data sampel yang tersedia?
Valkyrie
Bagaimana cara saya memberikan data sampel?
BufferStack
Cobalah petunjuk di pos ini: meta.stackexchange.com/questions/156729/…
Valkyrie
1
Itu bagus, tapi SQLFiddle lebih baik;). Lihat contoh di sini . Cara yang lebih baik untuk hanya melihat kode dan data seed, bukan tabel yang perlu Anda format.
Marian
6

Mengingat bahwa tabel Anda terlihat seperti ini:

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

Kueri ini harus melakukan trik:

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
druzin
sumber