0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SQLでタブ文字(\t)を置換しようとしてハマった話(REPLACE と REGEXP_REPLACE)

0
Posted at

はじめに

データベース内のデータに含まれるタブ文字(\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のREPLACELIKE\tを使うと、エスケープの仕様により 単なるtとして扱われるリスクがある。正規表現や特殊文字を扱うなら、REGEXP_REPLACEを使うか、CHAR(9)でコード指定するのが安全です。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?