J'ai récemment publié une nouvelle technique pour traiter ce type de problème dans MySQL.
RÉDUCTION SCALAIRE-AGRÉGÉE
La réduction scalaire-agrégée est de loin l'approche la plus performante et la méthode la plus simple (en termes de moteur de base de données) pour y parvenir, car elle ne nécessite ni jointures, ni sous-requêtes, ni CTE.
Pour votre requête, cela ressemblerait à quelque chose comme ceci :
SELECT
video_category,
MAX(video_id) AS video_id,
SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_url)), 12) AS video_url,
SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_date)), 12) AS video_date,
SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_title)), 12) AS video_title,
SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), short_description)), 12) AS short_description
FROM
videos
GROUP BY
video_category
La combinaison des fonctions scalaires et agrégées permet d'obtenir les résultats suivants :
- LPADs l'identifiant corrélé intra-agrégat pour permettre une comparaison correcte des chaînes de caractères (par exemple, "0009" et "0025" seront correctement classés). J'utilise ici un LPADDING de 11 caractères en supposant une clé primaire INT. Si vous utilisez un BIGINT, vous voudrez augmenter cette valeur pour prendre en charge l'ordinalité de votre table. Si vous effectuez une comparaison sur un champ DATETIME (longueur fixe), aucun remplissage n'est nécessaire.
- CONCAT l'identifiant padded avec la colonne de sortie (ainsi vous obtenez "00000000009myvalue" contre "0000000025othervalue")
- MAX l'ensemble des agrégats, ce qui donnera "00000000025othervalue" comme gagnant.
- SUBSTRING le résultat, ce qui tronquera la partie identifiant comparé, ne laissant que la valeur.
Si vous voulez récupérer des valeurs dans des types autres que CHAR, vous devrez peut-être effectuer un CAST supplémentaire sur la sortie, par exemple si vous voulez que video_date
pour être un DATETIME :
CAST(SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_date)), 12) AS DATETIME)
Un autre avantage de cette méthode par rapport à la méthode d'auto-jonction est que vous pouvez combiner d'autres données agrégées (pas seulement les dernières valeurs), ou même combiner le premier ET le dernier élément dans la même requête, par ex.
SELECT
-- Overall totals
video_category,
COUNT(1) AS videos_in_category,
DATEDIFF(MAX(video_date), MIN(video_date)) AS timespan,
-- Last video details
MAX(video_id) AS last_video_id,
SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_url)), 12) AS last_video_url,
...
-- First video details
MIN(video_id) AS first_video_id,
SUBSTRING(MIN(CONCAT(LPAD(video_id, 11, '0'), video_url)), 12) AS first_video_url,
...
-- And so on
Pour plus de détails expliquant les avantages de cette méthode par rapport aux autres méthodes plus anciennes, mon article de blog complet est ici : https://www.stevenmoseley.com/blog/tech/high-performance-sql-correlated-scalar-aggregate-reduction-queries