LoginSignup
5
4

More than 1 year has passed since last update.

MySQL5.6->MySQL8.0へのバージョンアップで対応したこと4つ

Posted at

MySQL5.6->MySQL8.0という大幅なバージョンアップで、コード修正しなければならない部分が多数あったので、今回対応した4つの変更点について書きます。

MySQL5.7以降の変更

distinct使用時、selectリストにない項目でORDER BY すると怒られるようになった

例えば以下のように注文テーブル、ユーザーテーブルがあるとします。

ORDERTABLE

orderid(主キー) orderdate fixdate userid
OD0001 2022-07-10 12:34:56 2022-07-20 12:34:56 0001
OD0002 2022-07-12 12:34:56 0002
OD0003 2022-07-11 12:34:56 0001

USERTABLE

userid(主キー) username
0001 山田太郎
0002 田中花子

「fixdateが入っていない」レコードから「orderid, username」を「orderdate」順に取得したい場合、下記のようなSQLになります。

SELECT distinct o.orderid,u.username
FROM ORDERTABLE o INNER JOIN USERTABLE u ON o.userid = u.userid
WHERE o.fixdate IS NULL
ORDER BY o.orderdate;

MySQL5.7以降だとこのSQLで怒られます。

PDOException: SQLSTATE[HY000]: General error: 3065 Expression #1 of ORDER BY clause is not in SELECT list, references column 'db_name.o.orderdate' which is not in SELECT list; this is incompatible with DISTINCT

これは、MySQL設定の ONLY_FULL_GROUP_BY モードが有効になっているから。
MySQL5.7から設定デフォルト値として「ONLY_FULL_GROUP_BY」が追加になったため、設定を変えなければこのエラーに遭遇すると思います。

対策としては下記が挙げられます。

  • selectリストにORDER BY項目を追加
  • ORDER BY項目にselectリストのカラムを追加
  • ONLY_FULL_GROUP_BY モードを無効にする
  • サブクエリでORDER BY項目ありのselect distinctをし、外側でORDER BYする

今回はselect項目を増やしたくなかったので、以下のサブクエリで対応しました。

SELECT t1.orderid,t1.username
FROM (
    SELECT distinct o.orderid,o.orderdate,u.username
    FROM ORDERTABLE o INNER JOIN USERTABLE u ON o.userid = u.userid
    WHERE o.fixdate IS NULL
    ) AS t1
ORDER BY t1.orderdate;

なお、今回distinct項目に「o.orderdate」が追加されていますが、同テーブルの主キー(ユニークキー)である「o.orderid」も入っているので、この変更によって取得行数が増えることはありません。(o.orderid,u.usernameが同じ かつ o.orderdate が異なることはあり得ない)

参考

MySQL8.0以降の変更

「GROUP BYによる暗黙のソート」がされなくなる

今までGROUP BYで暗黙のソートが行われていましたが、MySQL8からソートしなくなったので取得順が一定でなくなりました。
プロダクトコードで暗黙のソートに依存してしまっている場合はもちろん、ユニットテストで並び順を検証している場合もテスト実行結果が変わってくるので対応が必要になります。

公式リファレンスより:

以前に GROUP BY ソートに依存していたクエリーでは、以前の MySQL バージョンとは異なる結果が生成される場合があります。 特定のソート順序を生成するには、ORDER BY 句を指定します。

対応策としては公式の通り、ソートしたいときはちゃんとORDER BYしてねというところですね。

参考

datetime(date)型に変換できない文字列とdatetime型を比較するSQLが不正になった

datetime型カラムと空文字と比較しているSQLでエラーが出るようになりました。
datetime型カラムにはそもそも空文字は登録できないので、比較している所を削除することで対応しました。(なんで比較してるんだって感じですが)

参考

Rankが予約語になった

これは何とも…「Rank」って普通にカラム名とかで使うような気がするんですが…困っちゃいますね…
対応策としてはエスケープするか、予約語になっていない「〇〇_RANK」とかにカラム名変えるかしかないですね。
今回対応したときはカラムの使用箇所が少なかったので、カラム名変更で対応しました。

参考

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4