「分かりにくい命名はやめましょう」「分かりやすいSQLを書きましょう」ということの例示をしていたら、MySQLが謎の挙動をしたので少しビビったという話。
なにが起きたか
id | date |
---|---|
1 | 2001-01-01 |
2 | 2005-05-05 |
↑のテーブルを念頭に↓を紹介していた。
-- まず、お手本のSQLを用意した(WHERE句を抜粋。分かりやすさのために一部修正)
WHERE date BETWEEN '2000-01-01' AND '2003-03-03';
-- そこからちょっとだけ分かりにくい(諸説あり)文を用意したが、一番最初のdateを消し忘れていた。でも普通に動いた
WHERE date '2000-01-01' <= date AND date <= '2003-03-03';
-- もちろんこれも動く
WHERE '2000-01-01' <= date AND date <= '2003-03-03';
あってもなくてもいい根無草のdate
が出現してしまった。
「WHERE date という文がNULL判定しているんですか?」「キャストしてますか?」といった推測が入り乱れ、当の本人はめちゃくちゃ焦りながら「持ち帰って検討します」をした。
なぜそんな動きをしたか
意図せず、日付リテラルの型の明示date '2000-01-01'
の文になっており、date
はあってもなくても変わらない動作をするので。
標準 SQL では、型キーワードと文字列を使用して時間リテラルを指定する必要があります。 キーワードと文字列の間の空白はオプションです。(中略)
MySQL は認識しますが、標準 SQL とは異なり、type キーワードは必要ありません。
-- よく見る普通の日付リテラル
'2000-01-01'
-- DATE型であることを明示。くっつけるパターン
date'2000-01-01'
-- DATE型であることを明示。空白を挟むパターン ←今回はこれ ←混乱する(※個人の感想)
date '2000-01-01'
すべての原因
MySQLのキーワードであるdate
をカラム名として使ったのが悪い。
「date
という名前のカラムはキーワードだが予約済みではないので、識別子として使えるが、使わない方がいい。」
という一般論を紹介しようとしたら、偶然にもはっきりとした理由を示すことができた。
(識別子の大文字小文字を区別しない環境においては日付リテラルの型の明示 DATE 'str' の他にも 関数 DATE() 等とややこしいのでダメ)
自戒
日付型、時間型だけでも、今回の「寛容な」型の明示の他に「世話を焼いてくれる」変換があったりするが、それらとちゃんと向き合ってクエリを書こう。(自戒)