MySQLでHAVINGがSELECTエイリアスを使用できるのはなぜですか?


14

私の知る限り、SQLでは、概念的な解釈順序である論理クエリ処理順序は、次のようにFROMで始まります。

  1. から
  2. どこ
  3. GROUP BY
  4. 持っている
  5. 選択する
  6. ORDER BY

このリストに従うと、エイリアスがまだ作成されていないため、WHERE句でSELECTエイリアスを使用できない理由を簡単に確認できます。T-SQL(SQL Server)は厳密にこれに従い、SELECTを渡すまでSELECTエイリアスを使用できません。

しかし、MySQLでは、SELECT句の前に(論理的に)処理する必要がある場合でも、HAVING句でSELECTエイリアスを使用できます。これはどのように可能ですか?

例を挙げると:

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;

ステートメントはT-SQLでは無効です(HAVINGはSELECTエイリアスを参照しているためAmount)...

Msg 207, Level 16, State 1, Line 5
Invalid column name 'Amount'.

...しかし、MySQLでは問題なく動作します。

これに基づいて、私は疑問に思っています:

  • MySQLはユーザーを支援するためにSQLルールのショートカットを取っていますか?何らかの事前分析を使用しているのでしょうか?
  • または、MySQLはすべてのRDBMSが従っていたものとは異なる概念解釈順序を使用していますか?

1
私の推測では、それはあなたの2番目の箇条書きです。
a_horse_with_no_name

3
ランク付け機能をサポートするまで、あいまいさや混乱を引き起こさないと思います。次にSELECT C, ROW_NUMBER() OVER (ORDER BY X) AS RN FROM T GROUP BY C HAVING RN = 1として問題になる可能性がありますROW_NUMBER実行した後にHAVING
マーティン・スミス

MySQLでサポートされているランキング関数はわかりません。行番号が必要な場合は、次の方法で作成する必要がありますSELECT @rownum:=@rownum + 1 as row ...。たぶん、SELECTエイリアスをサポートする理由は、それが不可能になることをサポートしていないという事実のために、単にサポートできるからです。:)
オーリン

@MartinSmithが説明するように、ウィンドウ/ランク付け関数がない限り、for 節HAVINGとfor SELECT節の実行の論理的な順序は交換できます。そのため、これを行うのにあいまいさはなく、に巨大な式がある場合にコードの外観を簡素化できSELECTます。
ypercubeᵀᴹ

うまくいけば、ここで質問に答えたと言ってもいいかもしれません。ここでは、同じ出力にもかかわらず、より高速な結果を(でdistincts)楽しんいます。そのため、オプティマイザーでいくつかのバリエーションが発生しています。Alias in the HavingExplain
ドリュー

回答:


13

この種の質問がある場合、私見の最高の情報源はMySQLのドキュメントです。ここまでがポイントです。これは、GROUP BYデフォルトで有効になっているMySql拡張機能の動作です。

GROUP BY
MySQLの MySQL拡張機能は、この動作拡張して、集計列のHAVING句でエイリアスを使用できるようにします

標準の動作が必要な場合は、この拡張機能を無効にすることができます sql_mode ONLY_FULL_GROUP_BY

SET [SESSION | GLOBAL] sql_mode = ONLY_FULL_GROUP_BY;

上記のクエリをONLY_FULL_GROUP_BYsql_modeで実行しようとすると、次のエラーメッセージが表示されます。

非グループ化フィールド「金額」はHAVING句で使用されます:SELECT YEAR(orderdate)、COUNT(*)as Amount FROM Orders GROUP BY YEAR(orderdate)HAVING Amount> 1

SQLFiddleデモはこちら

したがって、MySQLのインスタンスを構成および使用する方法はユーザー次第です。


あなたはドキュメントについて絶対に正しいです。あなたがそれを上に引用したようにはっきりと書かれているとは思わなかった:)それを見つけてくれてありがとう
...-オーリン

この回答は、「MySQLは事前分析を行っているのですか、MySQLは別の概念的な解釈を使用していますか?」とは答えません。
Pacerier

2
@Pacerier MySQLはもちろん「事前分析を行っています」。なぜなら、クエリオプティマイザはクエリのすべての面を考慮しながら、最良のクエリプランであると信じるものを選択するからです。「異なる概念解釈」の概念は、サーバーが有効な結果を生成する方法で概念モデルを自由に実装できるという事実の誤解を裏切ります。 ORDER BY、たとえば、オプティマイザが、すでに目的の順序にある​​インデックスから順番に行を最初に読み取ることができる場合、理論的にははるかに早く処理される可能性があります。
マイケル-sqlbot

4

良い質問。

これらのクエリを実行する必要があると思います

EXPLAIN SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;
SHOW WARNINGS;

クエリの書き換え方法を確認します。Iamは、クエリオプティマイザーがAmountをCOUNT(*)に置き換えることをかなり確実にしています

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING COUNT(*)>1;

のように

select 
 *
from 
 test
where 
 id = 5 - 3

クエリオプティマイザーの後、次のようになります。

select 
 test.id as 'id'
from 
 test
where 
 test.id = 2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.