web-dev-qa-db-fra.com

L'utilisation d'un alias de colonne dans la clause WHERE de la requête MySQL génère une erreur

La requête que j'exécute est la suivante, mais j'obtiens cette erreur:

N ° 1054 - Colonne inconnue 'secured_postcode' dans 'IN/ALL/ANY sous-requête'

SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE `guaranteed_postcode` NOT IN #this is where the fake col is being used
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)

Ma question est la suivante: pourquoi ne puis-je pas utiliser une fausse colonne dans la clause where de la même requête de base de données?

176
James

Vous ne pouvez utiliser que des alias de colonne dans les clauses GROUP BY, ORDER BY ou HAVING.

Le SQL standard ne vous permet pas de faire référence à un alias de colonne dans une clause WHERE. Cette restriction est imposée car, lorsque le code WHERE est exécuté, la valeur de la colonne peut ne pas encore être déterminée.

Copié depuis documentation MySQL

Comme indiqué dans les commentaires, utiliser HAVING à la place peut faire le travail. Assurez-vous de donner une lecture à ceci WHERE vs HAVING bien.

397
victor hugo

Comme Victor l'a souligné, le problème vient du pseudonyme. Cela peut toutefois être évité en plaçant l'expression directement dans la clause WHERE x IN y:

SELECT `users`.`first_name`,`users`.`last_name`,`users`.`email`,SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE SUBSTRING(`locations`.`raw`,-6,4) NOT IN #this is where the fake col is being used
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)

Cependant, je suppose que cela est très inefficace, car la sous-requête doit être exécutée pour chaque ligne de la requête externe.

23
rodion

Le SQL standard (ou MySQL) n'autorise pas l'utilisation d'alias de colonnes dans une clause WHERE car

lorsque la clause WHERE est évaluée, la valeur de la colonne n'a peut-être pas encore été déterminée.

(de documentation MySQL ). Ce que vous pouvez faire est de calculer la valeur de la colonne dans la clause , d'enregistrer la valeur dans une variable et de l'utiliser dans la liste de champs. Par exemple, vous pouvez faire ceci:

SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
@postcode AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE (@postcode := SUBSTRING(`locations`.`raw`,-6,4)) NOT IN
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)

Cela évite de répéter l'expression lorsqu'elle devient compliquée, ce qui facilite la maintenance du code.

19
Joni

Peut-être que ma réponse est trop tard, mais cela peut aider les autres.

Vous pouvez la joindre à une autre instruction select et utiliser la clause where.

SELECT * FROM (Select col1, col2,...) as t WHERE t.calcAlias > 0

calcAlias ​​est la colonne d'alias calculée.

14
George Khouri

Vous pouvez utiliser la clause HAVING pour le filtre calculé dans les champs et alias SELECT

8
Hett

J'utilise mysql 5.5.24 et le code suivant fonctionne:

select * from (
SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
) as a
WHERE guaranteed_postcode NOT IN --this is where the fake col is being used
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)
1
themis

Le SQL standard n'autorise pas les références aux alias de colonnes dans une clause WHERE. Cette restriction est imposée car, lorsque la clause WHERE est évaluée, la valeur de la colonne n’a peut-être pas encore été déterminée. Par exemple, la requête suivante est illégale:

SELECT id, COUNT (*) COMME cnt FROM nom_de_table WHERE cnt> 0 GROUP BY id;

0
Pavan Rajput

Vous pouvez utiliser SUBSTRING (locations.raw, - 6,4) pour la condition where

SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE SUBSTRING(`locations`.`raw`,-6,4) NOT IN #this is where the fake col is being used
(
SELECT `postcode` FROM `postcodes` WHERE `region` IN
(
 'australia'
)
)