MySQL réutilise certains alias
J'ai actuellement une requête dans laquelle je fais deux sous-requêtes pour obtenir des données X, Y:
SELECT
t.series AS week,
( ... ) X,
( ..., AND ... ) Y,
ROUND(( ... ) * 100) / ( ..., AND ... ), 2) Z
FROM series_tmp t
Y est une sorte de sous-ensemble de X, puisque j'applique juste une condition supplémentaire à celles existantes, si X est:
SELECT COUNT(*)
FROM t1
INNER JOIN t2
ON t2.id = t1.another_id
WHERE t2.something = 1
AND t1.date BETWEEN t.series AND t.series + INTERVAL 6 DAY
Alors Y a une condition AND supplémentaire:
SELECT COUNT(*)
FROM t1
INNER JOIN t2
ON t2.id = t1.another_id
WHERE t2.something = 1
AND t1.date BETWEEN t.series AND t.series + INTERVAL 6 DAY
AND t1.some_state = 'x state'
Et pour la valeur de XI, il faut prendre ces deux résultats - X et Y et faire un calcul. Comme je ne peux pas utiliser les alias, je dois utiliser une sous-requête, non? Mais dans ce cas, cela semble trop.
Existe-t-il un moyen de réutiliser ces sous-requêtes? Cela semble trop être la même chose.
J'utilise MySQL 5.6 donc je ne peux pas utiliser les CTE :(
PS: series_tmpvient de cette merveilleuse idée (grâce à eux).
Réponses
Le standard SQL n'autorise pas la réutilisation de l'alias ici.
Cependant, MySQL utilise une extension du standard qui vous permet de faire quelque chose de proche, à savoir utiliser un alias préalablement défini dans une sous-requête:
select some_expression as alias_name, (select alias_name)
ce qui dans votre cas signifierait que vous pouvez faire
SELECT
t.series AS week,
( ... ) X,
( ... AND ... ) Y,
ROUND( (select X) * 100) / (select Y), 2) Z
FROM series_tmp t
L'alias ne doit pas correspondre à un nom de colonne, car cela aurait la priorité et cela ne fonctionnera pas pour les agrégats. Semblable à la réponse de nbk , ceci est spécifique à MySQL et ne fonctionnera pas dans d'autres systèmes de base de données.
Une solution qui fonctionne également dans d'autres systèmes de bases de données et que vous, selon votre commentaire, déjà trouvée, serait d'introduire une table dérivée, par exemple
select week, X, Y, ROUND(X * 100 / Y, 2) Z
from (
SELECT
t.series AS week,
( ... ) X,
( ..., AND ... ) Y
FROM series_tmp t
) as sub
Pour cela, vous pouvez utiliser des variables définies par l'utilisateur
SELECT
t.series AS week,
@x:=(SELECT
COUNT(*)
FROM
t1
INNER JOIN
t2 ON t2.id = t1.another_id
WHERE
t2.something = 1
AND t1.date BETWEEN t.series AND t.series + INTERVAL 6 DAY) X,
@y:=(SELECT
COUNT(*)
FROM
t1
INNER JOIN
t2 ON t2.id = t1.another_id
WHERE
t2.something = 1
AND t1.date BETWEEN t.series AND t.series + INTERVAL 6 DAY
AND t1.some_state = 'x state') Y,
ROUND((@x * 100) / @y, 2) Z
FROM
series_tmp t
Si vous souhaitez utiliser vos alias, MySQL vous permet uniquement de les utiliser dans ORDER BY, GROUP BYetHAVING
Comme exemple, vous pouvez utiliser ORDER BY X DESC,Y ASCouHAVING X > 0.5
Y est une sorte de sous-ensemble de X, puisque j'applique juste une condition supplémentaire à celles existantes, si X est:
SELECT COUNT(*) FROM t1 INNER JOIN t2 ON t2.id = t1.another_id WHERE t2.something = 1 AND t1.date BETWEEN t.series AND t.series + INTERVAL 6 DAYAlors Y a une condition AND supplémentaire:
SELECT COUNT(*) FROM t1 INNER JOIN t2 ON t2.id = t1.another_id WHERE t2.something = 1 AND t1.date BETWEEN t.series AND t.series + INTERVAL 6 DAY AND t1.some_state = 'x state'
Dans ce cas particulier, je vous recommande d'utiliser l'agrégation conditionnelle:
SELECT COUNT(*) AS total_count,
SUM(t1.some_state = 'x state') AS x_state_count
FROM t1
INNER JOIN t2
ON t2.id = t1.another_id
WHERE t2.something = 1
AND t1.date BETWEEN t.series AND t.series + INTERVAL 6 DAY
Si la condition t1.some_state = 'x state'pour une ligne particulière est TRUE(qui est un alias de 1dans MySQL) alors SUM()s'ajoutera 1à la somme intermédiaire pour cette ligne.
Si la condition t1.some_state = 'x state'pour une ligne particulière est FALSE(qui est un alias de 0dans MySQL) alors SUM()ajoutera 0(ie ne modifiera pas la somme intermédiaire) pour cette ligne.
En conséquence, le nombre de lignes correspondantes sera calculé.
Dans la plupart des cas simples, une telle agrégation conditionnelle au lieu d'une réutilisation d'alias suffit.