はじめに
データベース内のデータに含まれるタブ文字(\t)を半角スペースに一括更新しようとした際、想定外の挙動に遭遇しました。
単純な REPLACE関数ではうまくいかなかった原因と、解決策をまとめます。
発生した問題
当初、以下のようなSQLを実行しましたが、更新対象が0件でした。
UPDATE users
SET name = REPLACE(name, '\t', ' ')
WHERE name LIKE '%\t%';
さらに、LIKE '%\t%'で検索すると、タブ文字が含まれていないはずのデータ(例: 'test' など)までヒットしてしまうという現象が発生しました。
なぜ\tでアルファベットのtがヒットするのか?
多くのSQL環境(MySQLなど)において、バックスラッシュ(\)はエスケープ文字として扱われます。
\tと書くと、環境によっては「タブ」ではなく、単に「tという文字をエスケープしたもの」と解釈されます。その結果、内部的にバックスラッシュが消え、単なるLIKE '%t%'として実行されてしまい、名前にtが含まれる全ての行がヒットしてしまいます。
解決策1:REGEXP_REPLACEを使う
MySQL 8.0以降やPostgreSQLなどで利用可能な正規表現関数を使うと、より直感的に記述できます。
UPDATE users
SET name = REGEXP_REPLACE(name, '\t', ' ');
REPLACEと違い、正規表現エンジンは\tを「水平タブ」として解釈するルールを持っているため、アルファベットのtと混同することなく正確に置換が行われます。
参考:MySQL :: MySQL 8.0 リファレンスマニュアル :: 12.8.2 正規表現
解決策その2:CHAR(9) を使う
\tを使わず、タブ文字の文字コードである9を直接指定しても置換できます。
UPDATE users
SET name = REPLACE(name, CHAR(9), ' ')
WHERE name LIKE CONCAT('%', CHAR(9), '%');
まとめ
SQLのREPLACEやLIKEで\tを使うと、エスケープの仕様により 単なるtとして扱われるリスクがある。正規表現や特殊文字を扱うなら、REGEXP_REPLACEを使うか、CHAR(9)でコード指定するのが安全です。