先日、業務でSQLを実装してみて、「あれ? これできないの?」と思ったことがるので書きます。試した環境はMySQL8(他のDBMSでは動作が異なるかもしれない)。
うまく動かなかったのは、サブクエリのサブクエリにメインクエリの値を使おうとしたとき。例えば下記のようにmember(会員)テーブルとscore(点数)テーブルがあるとする。
ここから、memberテーブルのname(名前)と、その名前に対応するscoreテーブルの最新のscore(点数)を取り出したいとして、下記のように書きました。
SELECT member.member_name
, (SELECT MAX(sub_score.score)
FROM (SELECT *
, ROW_NUMBER() OVER(ORDER BY date DESC) AS row_num
FROM score AS subsub_score
WHERE subsub_score.member_id = member.member_id
) AS sub_score
WHERE row_num = 1) AS newly_score
FROM member
ようは、memberテーブルのmember_idで絞り込んだscoreテーブルのうち、date(日付)でソートしたときの順序を取得して順序が1つ目の値をとってきています(JOINしろといわれそうですが、実際に作成したのはIFNULLの第二引数で取得するようにしていて、ほとんどの行でこの結果を取得することはないので、サブクエリとしました)。
しかし、これを実行すると下記のようなエラーが発生します。
Error Code: 1054. Unknown column 'member.member_id' in 'where clause'
つまり、’member.member_id’なんてフィールドはないということだと思います。
もちろん、下記のようにサブクエリで指定するようにすると取得できます(違いとしては、上記がサブクエリのサブクエリでIDを絞り込もうとしていたのにたし、下記ではサブクエリでIDを絞り込もうとしている)。
SELECT member.member_name
, (SELECT MAX(sub_score.score)
FROM (SELECT *
, ROW_NUMBER() OVER(
PARTITION BY subsub_score.member_id
ORDER BY date DESC) AS row_num
FROM score AS subsub_score ) AS sub_score
WHERE row_num = 1
AND sub_score.member_id = member.member_id) AS newly_score
FROM member
多分、サブクエリのサブクエリにはメインクエリの値は利用できないのだろうと思ったのだけど、調べてみても根拠となるソースが見つからなかった。何でこういうふうになっているんだろう? 内部ロジックが複雑になるからか?
コメント