sql >> Base de Datos >  >> RDS >> Mysql

MYSQL - Ordenar por Id en orden DESC, agrupar por X

Ha entendido mal cómo funciona GROUP BY en SQL, debido a una característica de MySQL. En SQL estándar, cada columna no agregada en la declaración SELECT DEBE estar en la cláusula GROUP BY (hay una excepción para las columnas cuyos valores dependen al 100% de una columna que ya está en la cláusula GROUP BY, aunque algunas versiones de SQL admiten esta exención) .

MySQL no impone esto de forma predeterminada, pero no se define qué valores de filas se usan para esas columnas. Si bien es posible que obtenga el que desea, también es posible que no. E incluso si lo hace, existe la posibilidad de que cambie en el futuro.

El orden es independiente de GROUP BY normalmente, aunque si no especifica una cláusula ORDER, los resultados se ordenarán en función de lo que se requirió para realizar el GROUPing (es decir, si ayuda a ordenar las filas en un orden para hacer el GROUP BY, MySQL no se molestará en reordenar los registros después, a menos que se lo indique específicamente con una cláusula ORDER BY).

Entonces, con sus datos actuales, agrupando por ads_post_id, el valor de id que se devuelve podría ser 22, 23, 24, 104, 250, 253 o 767. No se define cuál elige usar MySQL.

Con la corrección de sus datos actuales, esto es trivial, ya que puede obtener la identificación MAX:-

SELECT ads_post_id, MAX(id) 
FROM fb_ads 
GROUP BY ads_post_id 
LIMIT 6

MAX devolverá 1 fila por cada valor GROUPed.

El problema normal es que la gente quiera otra columna para esa fila. Por ejemplo, supongamos que cada una de las filas en sus datos de muestra también tenía una dirección IP, y quería la que equivalía a la identificación más alta 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     
---------------------------------------------------------------------------

En este caso, no puede simplemente usar MAX. Por ejemplo, si intentaste:-

SELECT ads_post_id, MAX(id), MAX(ip_address) 
FROM fb_ads 
GROUP BY ads_post_id 
LIMIT 6

Obtendrá los siguientes datos devueltos

id   | ads_post_id         ip_address
---------------------------------------------------------------------------
767  | 983314845117571     192.168.0.7     
---------------------------------------------------------------------------

Si intentara lo siguiente en la mayoría de las variantes de SQL, obtendría un error. En MySQL con la configuración predeterminada, obtendría un resultado, pero la dirección IP que se devuelve no está definida (y en efecto es aleatoria).

SELECT ads_post_id, MAX(id), ip_address 
FROM fb_ads 
GROUP BY ads_post_id 
LIMIT 6

Las soluciones a esto son obtener el ID máximo para cada ads_post_id en una subconsulta y luego volver a unirlo a la tabla para obtener el resto de los 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

Una alternativa es (ab) usar la función agregada GROUP_CONCAT. GROUP_CONCAT devolverá todos los valores concatenados en 1 campo, cada uno separado por un , (por defecto). Puede agregar una cláusula ORDER BY para forzar el orden en el que se concatenan. Puede usar SUBSTRING_INDEX para devolver todo hasta la primera coma.

Esto puede ser útil para datos simples, pero se vuelve problemático con datos de texto o campos que como máximo pueden ser NULL.

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