Selecionando várias colunas através de uma subconsulta


18

Estou tentando selecionar 2 colunas da subconsulta na consulta a seguir, mas não é possível fazer isso. Tentei criar a tabela de alias, mas ainda não consegui obtê-los.

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

Basicamente, estou tentando obter o lastComDate& lastPosterIDda mesma linha - a linha que é a mais recente nos comentários para o animal de estimação específico. Por favor, sugira como posso obtê-los de maneira eficiente.

A consulta acima funciona, mas parece exagerada, pois a mesma linha é buscada duas vezes. Além disso, a ORDER BYcláusula é significativamente mais lenta que a função agregada - como eu encontrei ao criar uma consulta de perfil. Portanto, uma solução para evitar a classificação seria apreciada.


11
Se você tivesse um índice (petid, id) na tabela de comentários, a ordem de provavelmente não seria lenta, mas primeiro o primeiro: parece que sua consulta está solicitando todos os animais de estimação nos quais o userid 'ABC' comentou nos últimos dois meses, em que deviceID não é 'ABC' (embora não esteja claro em qual tabela o deviceID está em uma coluna, possivelmente animais de estimação e possivelmente comentários) e quem foi o último comentarista e a data do último comentário. Isso está certo?
— Michael - sqlbot

@ Michael-sqlbot - Sim, é exatamente isso que estou tentando reunir. O deviceIDé da petstabela - o que significa que simplesmente não me dão os animais de estimação enviados pelo próprio 'ABC'.
— BufferStack 14/02

Respostas:


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

Você também pode extrair sua subconsulta para uma tabela temporária se o desempenho for impactado em algum lugar no futuro.


Eu tinha tentado isso mais cedo também ... isso retorna NULLpara ambos lastComDatee lastPosterIdpara todos os registros.
— BufferStack

Você tem alguma amostra de dados disponível?
— Valkyrie

Como forneço os dados da amostra?
— BufferStack

Tente as dicas nesta publicação: meta.stackexchange.com/questions/156729/…
— Valkyrie

11
Isso é bom, mas o SQLFiddle é melhor;). Veja um exemplo aqui . É muito melhor ver apenas o código e os dados iniciais, e não alguma tabela que você precisará formatar.
— Marian

6

Dado que suas tabelas ficam assim:

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

Esta consulta deve fazer o truque:

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.