Использование псевдонима столбца в предложении WHERE запроса MySQL приводит к ошибке

202

Запрос, который я выполняю, выглядит следующим образом, однако я получаю эту ошибку:

# 1054 - Неизвестный столбец 'Guaranteed_postcode' в 'IN / ALL / ANY subquery'

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'
 )
)

Мой вопрос: почему я не могу использовать поддельный столбец в предложении where того же запроса к БД?

Джеймс
источник

Ответы:

434

Вы можете использовать псевдонимы столбцов только в предложениях GROUP BY, ORDER BY или HAVING.

Стандартный SQL не позволяет ссылаться на псевдоним столбца в предложении WHERE. Это ограничение наложено потому, что при выполнении кода WHERE значение столбца может еще не быть определено.

Скопировано из документации MySQL

Как указано в комментариях, вместо этого можно использовать HAVING. Удостоверьтесь, чтобы прочитать в этом, ГДЕ против ПРОТИВ, хотя.

Виктор Гюго
источник
1
Приветствия для быстрого и точного ответа! Я изучил предложение HAVING и нашел способ успешно выполнить этот запрос. Еще раз спасибо.
Джеймс
39
В случае, если у кого-то еще есть такая же проблема, как и у меня, которая использовала псевдоним col в предложении where, не удалось - поменяв 'WHERE' на 'HAVING, исправил это сразу +1 хороший ответ.
megaSteve4
@ megaSteve4 У меня была такая же проблема! Использование "HAVING" решило это гладко. :)
Йохан
9
Это может или не может быть важным в вашем случае, но HAVINGвыполняется медленнее, чемWHERE
DTs
1
Причина в havingтом, что значения столбцов должны быть вычислены к тому времени, когда вы доберетесь до having. Это не так where, как указано выше.
Милли Смит
24

Как отметил Виктор, проблема в псевдониме. Этого можно избежать, поместив выражение непосредственно в предложение 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'
 )
)

Тем не менее, я думаю, что это очень неэффективно, поскольку подзапрос должен выполняться для каждой строки внешнего запроса.

Rodion
источник
1
@rodion, да, я считаю, что это очень медленно и неэффективно.
Pacerier
20

Стандартный SQL (или MySQL) не разрешает использование псевдонимов столбцов в предложении WHERE, потому что

при оценке предложения WHERE значение столбца может еще не быть определено.

(из документации MySQL ). Что вы можете сделать, так это вычислить значение столбца в предложении WHERE , сохранить значение в переменной и использовать его в списке полей. Например, вы можете сделать это:

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'
 )
)

Это позволяет избежать повторения выражения, когда оно усложняется, что облегчает поддержку кода.

Joni
источник
9
Не противоречит ли это документации, которая гласит: «Как правило, вы никогда не должны присваивать значение пользовательской переменной и читать значение в том же выражении. Вы можете получить ожидаемые результаты, но это не гарантируется». ?
Арьян
Это определенно что-то иметь в виду. Это всегда работало для меня, хотя, я думаю, что порядок оценки различных частей оператора должен был быть установлен (сначала WHERE, затем SELECT, затем GROUP BY, ...), но у меня нет ссылки на это
Джони
Несколько примеров: некоторые утверждают, что для них select @code:=sum(2), 2*@codeработает в MySQL 5.5, но для меня в 5.6 второй столбец выдает NULL при первом вызове и возвращает 2 раза предыдущий результат при повторном запуске. Достаточно интересно, как выбрать @code:=2, 2*@codeи select @code:=rand(), 2*@code, кажется, работает в моих 5.6 (сегодня). Но они действительно пишут и читают в предложении SELECT; в вашем случае вы устанавливаете его в ГДЕ.
Арджан
@Joni, почему бы просто не оценить состояние дважды? Конечно, MySQL достаточно умен, чтобы оптимизировать это .......
Pacerier
@Pacerier необходимость повторения выражения еще хуже, особенно если это сложно. Я не был в состоянии подтвердить, реализует ли MySQL общее устранение подвыражения.
Джони
16

Может быть, мой ответ слишком поздно, но это может помочь другим.

Вы можете заключить его в другой оператор select и использовать к нему предложение where.

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

calcAlias ​​- это столбец псевдонимов, который был рассчитан.

Джордж Хоури
источник
Красиво и коротко, но это слишком расплывчато, чтобы быть полезным.
Агамемн
@Agamemnus, что ты имеешь в виду под этим?
Pacerier
Вопрос был: «Почему я не могу использовать поддельный столбец в предложении where того же запроса к БД?» Этот ответ не отвечает на этот вопрос и отсутствует глагол.
Агамемн
Тогда просто используйте HAVING
Hett
8

Вы можете использовать предложение HAVING для фильтра, рассчитанного в полях и псевдонимах SELECT.

Хетт
источник
@ fahimg23 - Не уверен. Я пытался найти причину, но не могу! Имейте в виду различия между WHEREи HAVING, хотя. Они не идентичны. stackoverflow.com/search?q=where+vs+having
риного
ОБНОВЛЕНИЕ: Это потому, что этот ответ дает то же решение, но с дополнительной информацией.
Риного
1

Я использую MySQL 5.5.24 и работает следующий код:

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'
 )
)
themhz
источник
0

Стандартный SQL запрещает ссылки на псевдонимы столбцов в предложении WHERE. Это ограничение наложено потому, что при оценке предложения WHERE значение столбца может еще не быть определено. Например, следующий запрос недопустим:

SELECT id, COUNT (*) AS cnt ОТ tbl_name WHERE cnt> 0 GROUP BY id;

Паван Раджпут
источник
0

Вы можете использовать SUBSTRING ( locations. raw, -6,4) для где условия

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'
)
)
Самера Прасад Джаясингхе
источник