Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MYSQL mostra linhas incorretas ao usar GROUP BY


Este é um obstáculo clássico que a maioria dos programadores MySQL encontra.
  • Você tem uma coluna ticket_id esse é o argumento para GROUP BY . Valores distintos nesta coluna definem os grupos.
  • Você tem uma coluna incoming_time esse é o argumento para MAX() . O maior valor nesta coluna sobre as linhas em cada grupo é retornado como o valor de MAX() .
  • Você tem todas as outras colunas do artigo da tabela. Os valores retornados para essas colunas são arbitrários, não da mesma linha em que MAX() valor ocorre.

O banco de dados não pode inferir que você deseja valores da mesma linha em que ocorre o valor máximo.

Pense nos seguintes casos:

  • Existem várias linhas em que ocorre o mesmo valor máximo. Qual linha deve ser usada para mostrar as colunas de article.* ?

  • Você escreve uma consulta que retorna tanto o MIN() e o MAX() . Isso é legal, mas qual linha deve article.* exposição?
    SELECT article.* , MIN(article.incoming_time), MAX(article.incoming_time)
    FROM ticket, article
    WHERE ticket.id = article.ticket_id
    AND ticket.queue_id = 1
    GROUP BY article.ticket_id
    

  • Você usa uma função agregada como AVG() ou SUM() , onde nenhuma linha tem esse valor. Como o banco de dados adivinha qual linha exibir?
    SELECT article.* , AVG(article.incoming_time)
    FROM ticket, article
    WHERE ticket.id = article.ticket_id
    AND ticket.queue_id = 1
    GROUP BY article.ticket_id
    

Na maioria das marcas de banco de dados -- assim como no próprio padrão SQL -- você não tem permissão escrever uma consulta como esta, por causa da ambiguidade. Você não pode incluir nenhuma coluna na lista de seleção que não esteja dentro de uma função agregada ou nomeada no GROUP BY cláusula.

MySQL é mais permissivo. Ele permite que você faça isso e deixa para você escrever consultas sem ambiguidade. Se você tiver ambiguidade, ele selecionará valores da linha que está fisicamente primeiro no grupo (mas isso depende do mecanismo de armazenamento).

Vale a pena, o SQLite também tem esse comportamento, mas escolhe o último linha no grupo para resolver a ambiguidade. Vai saber. Se o padrão SQL não diz o que fazer, cabe à implementação do fornecedor.

Aqui está uma consulta que pode resolver seu problema para você:
SELECT a1.* , a1.incoming_time AS maxtime
FROM ticket t JOIN article a1 ON (t.id = a1.ticket_id)
LEFT OUTER JOIN article a2 ON (t.id = a2.ticket_id 
  AND a1.incoming_time < a2.incoming_time)
WHERE t.queue_id = 1
  AND a2.ticket_id IS NULL;

Em outras palavras, procure por uma linha (a1 ) para a qual não há outra linha (a2 ) com o mesmo ticket_id e um incoming_time maior . Se não houver mais incoming_time for encontrado, LEFT OUTER JOIN retornará NULL em vez de uma correspondência.