SELECT文の評価・実行順序 MySQLはGROUP BY・HAVINGで別名使用可

SQL データベース
この記事は約4分で読めます。

※当ブログではアフィリエイト広告を利用しています。

WordPressのDBサーバー MySQLSELECT文のSQLを実行していた時にふと気付きました。

MySQLでは、GROUP BY句・HAVING句でカラムに付けた別名(AS句)を指定できるんですね。
確かOracle・PostgreSQL・SQL Serverなどの他のRDMSは普通使えなかったような…。

ということで、調べました。

なお、今回のバージョンは以下の通りです。

  • MySQL 5.7

SQL SELECT文の評価・実行順序

SQLのSELECT文を実行すると、RDMSの内部で各句が順番に解釈されますが、その際の順番を実行順序評価順序)と言います。

その実行順序は上から順・下から順という単純なものではなく、次のようになっています。

  1. FROM
  2. WHERE(結合条件)
  3. START WITH
  4. CONNECT BY
  5. WHERE(行のフィルタ条件)
  6. GROUP BY
  7. HAVING
  8. MODEL
  9. SELECT
  10. UNION、MINUS、INTERSECTなどの集合演算
  11. ORDER BY

出典:図でイメージするOracle DatabaseのSQL全集 第4回 集約関数など

こちらはOracleのものですが、どのRDMSも基本的にこんな感じです。
赤字は主要なものです。

SELECT句はSQL文の先頭ですが、だいぶ後ろの方になっていますね。

そのため、SELECT句でAS句を使用してカラムに別名を付けたものをWHERE句などで使用することはできません
WHERE句などの評価順序がSELECT句よりも前だからです。
逆に、ORDER BY句ならSELECT句よりも実行順序が後ろなので使用できます。

例えば、WordPressで2019年に公開した投稿・固定ページの件数を月ごとに出すSQLは、以下のようになります。

SELECT
  DATE_FORMAT(post_date, '%Y%m') AS yyyymm
 ,post_type AS post_or_page
 ,COUNT(ID) AS cnt
FROM
  posts
WHERE
  (post_type = 'post'
   OR post_type = 'page')
  AND post_status = 'publish'
  AND post_date BETWEEN '20190101' AND '20191231'
GROUP BY
  DATE_FORMAT(post_date, '%Y%m')
 ,post_type
HAVING
  COUNT(ID) > 1
ORDER BY
  yyyymm
 ,post_or_page

SELECT句でAS句を使用してカラムにそれぞれ別名を付けていますが、通常これらはWHERE句・GROUP BY句・HAVING句ではその別名を使用できません。

ちなみに、このSQLはこんな感じでデータが取れます。

yyyymmpost_or_pagecnt
201901page2
201901post2
201902post15
201903post17
201904post10
201905post7
201906post2
201907post6
201908post6
201909post10
201910post7
201911post11
201912post8

MySQLはGROUP BY句・HAVING句にカラムの別名を使用可

MySQLの場合は、SELECT句で指定した別名をGROUP BY句・HAVING句で使用できます。

先ほどのSQLを以下のように変更しても、エラーなく実行できます。

SELECT
  DATE_FORMAT(post_date, '%Y%m') AS yyyymm
 ,post_type AS post_or_page
 ,COUNT(ID) AS cnt
FROM
  posts
WHERE
  (post_type = 'post'
   OR post_type = 'page')
  AND post_status = 'publish'
  AND post_date BETWEEN '20190101' AND '20191231'
GROUP BY
  yyyymm
 ,post_or_page
HAVING
  cnt > 1
ORDER BY
  yyyymm
 ,post_or_page

これは知らなかった。。

特に、COUNTなどのグループ関数を使用している場合は見やすいし、理解しやすいのでありがたいです。

MySQLの公式ドキュメント内を探してみたんですが、実行順序についての記載を見つけることはできませんでした。
なので、MySQLはGROUP BY句・HAVING句で別名使用可と覚えておこうと思います。

最後に

今回は、SQL SELECT文評価順序実行順序)についてでした。
MySQLだけは特殊で、GROUP BY句・HAVING句にSELECT句で指定したカラムの別名を使用できます。

コメント

タイトルとURLをコピーしました