Використання псевдоніму стовпця в пункті WHERE запиту MySQL створює помилку


201

Я веду наступний запит, однак я отримую цю помилку:

№ 1054 - Невідомий стовпець "Гарантований_поштовий код" у "ВП / ВСІ / ЯКІ-небудь підзапити"

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

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

Відповіді:


434

Псевдоніми стовпців можна використовувати лише в пунктах GROUP BY, ORDER BY або HAVING.

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

Скопійовано з документації на MySQL

Як зазначено в коментарях, використання HAVING натомість може зробити цю роботу. Не забудьте ознайомитись з цього питання, де ГОЛЯ проти НЕМАЄ .


1
Привіт за швидку та точну відповідь! Я переглянув пункт HAVING і розробив спосіб успішного запуску цього запиту. Знову дякую.
Джеймс

38
У випадку, якщо хтось інший має таку ж проблему, як і я, яка використовувала відчужене кольце в тому випадку, коли застереження не вдалося - замінивши "WHERE" на "HAVING, це виправлено це негайно +1 хороша відповідь.
megaSteve4

@ megaSteve4 У мене була така ж проблема! Використовуючи "HAVING" вирішили це гладко. :)
Йоган

9
Це може бути або не важливо у вашому випадку, але HAVINGвиконується повільніше, ніжWHERE
DTs

1
Причина havingпрацює в тому, що значення стовпців повинні бути обчислені до часу, коли ви потрапите до having. Як це було whereсказано вище, це не так.
Міллі Сміт

24

Як зазначив Віктор, проблема полягає у псевдонімі. Цього можна уникнути, ввівши вираз безпосередньо в пункт WHERE x IN:

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

Однак, я думаю, це дуже неефективно, оскільки підзапит має виконуватися для кожного ряду зовнішнього запиту.


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

Це дозволяє уникнути повторення виразу, коли воно ускладнюється, що полегшує підтримку коду.


9
Чи не конфліктує це з документацією, в якій сказано: "Як правило, ніколи не слід призначати значення змінної користувача та читати значення в межах одного і того ж оператора. Можливо, ви отримаєте очікувані результати, але це не гарантується". ?
Ар'ян

Це, безумовно, про що слід пам’ятати. Це завжди працювало для мене, але я думаю, що порядок оцінювання різних частин твердження повинен був бути встановлений (спочатку ДЕ, потім ВИБІР, потім ГРУПА ПО, ...), але я не маю на це посилання
Джоні

Кілька прикладів: дехто стверджує, що для них 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; у вашому випадку ви встановлюєте це де.
Ар'ян

@ Джоні, чому б просто не оцінити стан двічі? Напевно, MySQL досить розумний, щоб оптимізувати, що .......
Pacerier

@Pacerier, який повинен повторювати вираз, все ще гірше, особливо якщо він складний. Я не зміг підтвердити, чи MySQL реалізує загальне усунення піддепресії.
Джоні

16

Можливо, моя відповідь пізно, але це може допомогти іншим.

Ви можете долучити його до іншого оператора select і використовувати там, де до нього.

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

calcAlias ​​- стовпець псевдоніма, який був обчислений.


Приємно і коротко, але це занадто розпливчасто, щоб бути корисним.
Агамемнус

@Agamemnus, що ти розумієш під цим?
Пейсьєр

Питання полягало в тому, "чому я не в змозі використати підроблений стовпець у пункті" де "того ж запиту БД?" Ця відповідь не відповідає на це запитання і не містить дієслова.
Агамемнус

Тоді просто скористайтеся
ПЕРЕГЛЯДОМ

8

Ви можете використовувати пункт HAVING для фільтра, обчисленого в полях SELECT і псевдонімах


@ fahimg23 - Не впевнений. Я намагався знайти причину, але не можу! Майте на увазі відмінності між WHEREі HAVING, хоча. Вони не тотожні. stackoverflow.com/search?q=where+vs+having
rinogo

ОНОВЛЕННЯ: Це тому, що ця відповідь пропонує те саме рішення, але більше інформації.
rinogo

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

0

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

SELECT id, COUNT (*) AS cnt OF 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'
)
)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.