MySQLクエリのWHERE句で列エイリアスを使用するとエラーが発生する


201

私が実行しているクエリは次のとおりですが、このエラーが発生しています。

#1054-「IN / ALL / ANYサブクエリ」の不明な列「guaranteed_postcode」

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

私の質問は、同じDBクエリのwhere句で偽の列を使用できないのはなぜですか?

回答:


434

GROUP BY、ORDER BY、またはHAVING句でのみ列のエイリアスを使用できます。

標準SQLでは、WHERE句で列のエイリアスを参照することはできません。この制限が課されるのは、WHEREコードが実行されたときに、列の値がまだ決定されていない可能性があるためです。

MySQLのドキュメントからコピー

コメントで指摘されているように、代わりにHAVINGを使用することで作業を行うことができます。ただし、このWHEREとHAVINGを必ず読んでください。


1
迅速かつ正確な対応に乾杯!私はHAVING句を調べ、このクエリを正常に実行する方法を見つけました。再度、感謝します。
James

38
他の誰かが私と同じ問題を抱えている場合、where句でエイリアスされたcolを使用して失敗しました。
megaSteve4 2012年

@ megaSteve4私も同じ問題を抱えていました!「HAVING」を使うことでスムーズに解決しました。:)
ヨハン

9
これはあなたのケースでは重要かもしれませんし、重要ではないかもしれませんが、HAVING実行速度が遅いWHERE
DTは2014

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

ただし、サブクエリは外部クエリのすべての行に対して実行する必要があるため、これは非常に非効率的だと思います。


1
@rodion、はい、私はこれがあると信じてひどく遅く、非効率的。
Pacerier、2015

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
これは、 「原則として、ユーザー変数に値を割り当てて、同じステートメント内で値を読み取ることはできません。期待した結果が得られる可能性がありますが、これは保証されていません。」というドキュメント矛盾しません。
Arjan、2014年

それは間違いなく覚えておくべきことです。それはいつも私のために働いていましたが、ステートメントのさまざまな部分の評価の順序を固定する必要があったと思います(最初にWHERE、次にSELECT、次にGROUP BYなど)。しかし、その参照はありません
Joni

いくつかの例:一部ではMySQL 5.5で機能する主張していますselect @code:=sum(2), 2*@codeが、5.6では、2番目の列は最初の呼び出しでNULLを生成し、再度実行すると前の結果の 2倍を返します。興味深いことに、select @code:=2, 2*@codeselect @code:=rand(), 2*@codedoはどちらも私の5.6(今日)で動作するようです。しかし、それらは確かにSELECT句での書き込みと読み取りです。あなたの場合、あなたはそれをWHEREで設定しています。
Arjan、2014年

@Joni、なぜ条件を2回評価しないのですか?確かにMySQLはそれを最適化するスマート十分では.......ある
Pacerier

@Pacerierは式を繰り返す必要があり、特に複雑な場合はさらに悪化します。MySQLが共通の部分式の削除を実装しているかどうかを確認できませんでした。
Joni

16

多分私の答えは遅すぎますが、これは他の人を助けることができます。

別の選択ステートメントで囲み、それにwhere句を使用できます。

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

calcAliasは、計算されたエイリアス列です。


ナイスでショートですが、これは曖昧すぎて役に立たない。
アガメムス2014

@Agamemnus、それはどういう意味ですか?
Pacerier、2015

問題は、「同じDBクエリのwhere句で偽の列を使用できないのはなぜですか」でした。この答えはその質問には答えず、動詞がありません。
アガメムス2015

次に、HAVING
Hett

8

SELECTフィールドとエイリアスで計算されたフィルターにHAVING句を使用できます


@ fahimg23-わかりません。理由を探ろうとしたが見つからなかった!ただし、WHEREとの違いに注意してくださいHAVING。それらは同一ではありません。 stackoverflow.com/search?q=where+vs+having
rinogo 2017年

更新:これは、この回答が同じ解決策を提供するためですが、詳細情報が含まれています。
rinogo 2017年

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 FROM tbl_name WHERE cnt> 0 GROUP BY id;


0

条件付きの場所にはSUBSTRING(locationsraw、-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'
)
)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.