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

MYSQL - Ordenar por Id na Ordem DESC, Agrupar por X


Você não entendeu como o GROUP BY funciona no SQL, devido a um recurso do MySQL. No SQL padrão, toda coluna não agregada na instrução SELECT DEVE estar na cláusula GROUP BY (há uma exceção para colunas cujos valores são 100% dependentes de uma coluna já na cláusula GROUP BY, embora poucos tipos de SQL suportem essa isenção) .

O MySQL não impõe isso por padrão, mas quais valores de linhas são usados ​​para essas colunas não são definidos. Embora você possa obter o que deseja, também pode não conseguir. E mesmo se você fizer isso, há uma chance de que isso mude no futuro.

A ordenação é independente do GROUP BY normalmente, embora se você não especificar uma cláusula ORDER, os resultados serão ordenados com base no que foi necessário para executar o GROUPing (ou seja, se ajudar a ordenar as linhas em uma ordem para fazer o GROUP BY então o MySQL não se incomodará em reordenar os registros posteriormente, a menos que você o diga especificamente com uma cláusula ORDER BY).

Assim, com seus dados atuais, agrupando por ads_post_id, o valor de id que é retornado pode ser 22, 23, 24, 104, 250, 253 ou 767. Qual MySQL escolhe usar não está definido.

Com sua correção de dados atual, isso é trivial, pois você pode obter o ID MAX:-
SELECT ads_post_id, MAX(id) 
FROM fb_ads 
GROUP BY ads_post_id 
LIMIT 6

MAX retornará 1 linha para cada valor GROUPed.

O problema normal é que as pessoas querem outra coluna para essa linha. Por exemplo, digamos que cada uma das linhas em seus dados de exemplo também tenha um endereço IP e você queira aquele que equivale ao id mais alto para ads_post_id:-
id   | ads_post_id         ip_address
---------------------------------------------------------------------------
22   | 983314845117571     192.168.0.0
23   | 983314845117571     192.168.0.5
24   | 983314845117571     192.168.0.7    
104  | 983314845117571     192.168.0.0
250  | 983314845117571     192.168.0.4
253  | 983314845117571     192.168.0.6
767  | 983314845117571     192.168.0.1     
---------------------------------------------------------------------------

Neste caso, você não pode simplesmente usar MAX. Por exemplo, se você tentou:-
SELECT ads_post_id, MAX(id), MAX(ip_address) 
FROM fb_ads 
GROUP BY ads_post_id 
LIMIT 6

Você obteria os seguintes dados retornados
id   | ads_post_id         ip_address
---------------------------------------------------------------------------
767  | 983314845117571     192.168.0.7     
---------------------------------------------------------------------------

Se você tentasse o seguinte na maioria dos tipos de SQL, obteria um erro. No MySQL com as configurações padrão, você obteria um resultado, mas qual endereço IP é retornado não é definido (e, na verdade, aleatório).
SELECT ads_post_id, MAX(id), ip_address 
FROM fb_ads 
GROUP BY ads_post_id 
LIMIT 6

As soluções para isso são obter o id máximo para cada ads_post_id em uma subconsulta e, em seguida, juntá-lo de volta à tabela para obter o restante dos valores:-
SELECT a.ads_post_id,
        a.id,
        a.ip_address
FROM fb_ads a
INNER JOIN
(
    SELECT ads_post_id, MAX(id) AS max_id 
    FROM fb_ads 
    GROUP BY ads_post_id 
) sub0
ON a.ads_post_id = sub0.ads_post_id
AND a.id = sub0.max_id

Uma alternativa é (ab) usar a função agregada GROUP_CONCAT. GROUP_CONCAT trará de volta todos os valores concatenados em 1 campo, cada um separado por um , (por padrão). Você pode adicionar uma cláusula ORDER BY para forçar a ordem em que são concatenados. Você pode usar SUBSTRING_INDEX para retornar tudo até a primeira vírgula.

Isso pode ser útil para dados simples, mas se torna problemático com dados de texto ou campos que podem ser NULL no máximo.
SELECT a.ads_post_id,
        SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY id DESC), ',', 1),
        SUBSTRING_INDEX(GROUP_CONCAT(ip_address ORDER BY id DESC), ',', 1)
FROM fb_ads 
GROUP BY ads_post_id