SQL正規表現とLIKE演算子の完全ガイド|パターンマッチングを使いこなそう

データベース・SQL

「名前に『田』が含まれる人を検索したい」
「メールアドレスが特定のドメインで終わるデータだけ抽出したい」
「電話番号の形式が正しいかチェックしたい」

こんな要求、データベースを扱っていると頻繁に出てきますよね。

SQLには、こうした柔軟な検索を実現するための強力な機能が2つあります。それが「LIKE演算子」と「正規表現」です。

この記事では、SQLでのパターンマッチングの基本から、データベースごとの正規表現の使い方まで、初心者の方にも分かりやすく解説していきます。実務ですぐに使える実例もたくさん紹介しますよ。


スポンサーリンク
  1. LIKE演算子の基本|まずはシンプルなパターンマッチングから
    1. LIKE演算子とは?
    2. LIKEで使える2つのワイルドカード
    3. LIKEの実用例
  2. LIKEの制約と注意点
    1. LIKEでできないこと
    2. パフォーマンスの問題
    3. 特殊文字のエスケープ
  3. 正規表現とは?LIKEとの違い
    1. 正規表現(Regular Expression)の基本
    2. LIKEと正規表現の比較
    3. 正規表現でできること
  4. MySQL・MariaDBでの正規表現
    1. REGEXP/RLIKE演算子
    2. 基本的な使用例
    3. 実用的なパターン例
    4. MySQL 8.0の新機能:REGEXP_LIKE
  5. PostgreSQLでの正規表現
    1. 正規表現演算子
    2. POSIX正規表現の機能
    3. 実用例
  6. SQL Serverでの正規表現
    1. PATINDEX関数(限定的な機能)
    2. CLR統合による正規表現
    3. LIKE演算子での代替
  7. Oracleでの正規表現
    1. REGEXP_LIKE関数
    2. 基本的な使用例
    3. Oracle独自の正規表現関数
  8. 正規表現の実践パターン集
    1. 入力値の検証
    2. データの抽出と分類
    3. データのクリーニング
  9. パフォーマンスの最適化
    1. インデックスを活用できるケース
    2. 処理を分割する
    3. 事前バリデーションの実装
  10. よくあるエラーと対処法
    1. バックスラッシュのエスケープ
    2. 特殊文字のエスケープ
    3. 大文字小文字の扱い
    4. パフォーマンス問題
  11. よくある質問と回答
    1. Q1. LIKEと正規表現、どちらを使うべきですか?
    2. Q2. 正規表現のパフォーマンスは悪いですか?
    3. Q3. データベースごとに正規表現の書き方が違うのですか?
    4. Q4. 日本語の正規表現は使えますか?
    5. Q5. NOT LIKEやNOT REGEXPは使えますか?
  12. まとめ:状況に応じて使い分けよう

LIKE演算子の基本|まずはシンプルなパターンマッチングから

正規表現の前に、まずは基本的なLIKE演算子から理解していきましょう。

LIKE演算子とは?

LIKE演算子は、文字列が特定のパターンに一致するかどうかを判定する機能です。

基本的な構文:

SELECT * FROM テーブル名
WHERE カラム名 LIKE 'パターン';

完全一致ではなく、「〇〇を含む」「〇〇で始まる」といった曖昧な検索ができるんですね。

LIKEで使える2つのワイルドカード

LIKE演算子では、2種類の特殊文字(ワイルドカード)が使えます。

パーセント記号(%):0文字以上の任意の文字列

% は、何文字でも(0文字でも)マッチします。

使用例:

-- 「山」で始まる名前を検索
SELECT * FROM users WHERE name LIKE '山%';
-- マッチ例: '山田', '山本', '山崎太郎'

-- 「田」で終わる名前を検索
SELECT * FROM users WHERE name LIKE '%田';
-- マッチ例: '山田', '前田', '太田'

-- 「田」を含む名前を検索
SELECT * FROM users WHERE name LIKE '%田%';
-- マッチ例: '田中', '山田', '前田', '太田'

一番よく使うパターンですね。

アンダースコア(_):ちょうど1文字の任意の文字

_ は、必ず1文字だけマッチします。

使用例:

-- 「山_太郎」というパターンを検索(_には任意の1文字が入る)
SELECT * FROM users WHERE name LIKE '山_太郎';
-- マッチ例: '山田太郎', '山本太郎', '山崎太郎'
-- 非マッチ例: '山太郎'(1文字足りない), '山口一太郎'(1文字多い)

-- 3文字の名前を検索
SELECT * FROM users WHERE name LIKE '___';
-- マッチ例: '山田太郎'の部分は×、'田中'や'佐藤'など3文字ちょうどのみ

文字数を指定したいときに便利です。

LIKEの実用例

電話番号の検索:

-- 090で始まる電話番号
SELECT * FROM contacts WHERE phone LIKE '090%';

-- 市外局番が03の電話番号
SELECT * FROM contacts WHERE phone LIKE '03-%';

メールアドレスの検索:

-- Gmailのアドレス
SELECT * FROM users WHERE email LIKE '%@gmail.com';

-- 特定ドメインのアドレス
SELECT * FROM users WHERE email LIKE '%@example.co.jp';

商品コードの検索:

-- 「ABC」で始まる5桁の商品コード
SELECT * FROM products WHERE product_code LIKE 'ABC__';
-- マッチ例: 'ABC12', 'ABC99'

LIKEの制約と注意点

LIKEは便利ですが、いくつか制約もあります。

LIKEでできないこと

1. 複雑なパターンマッチング

「数字3桁-数字4桁」のような複雑な形式は表現できません。

-- これではうまく検索できない
SELECT * FROM users WHERE postal_code LIKE '___-____';
-- 全角数字や記号も含まれてしまう

2. 選択肢の指定

「AまたはBまたはC」のような選択肢は表現できません。

-- これは不可能
-- WHERE name LIKE '山田 OR 田中 OR 中村'  -- こんな書き方はない

3. 文字の種類の指定

「数字のみ」「英字のみ」といった条件は指定できません。

パフォーマンスの問題

前方一致以外はインデックスが効かない:

-- インデックスが使える(高速)
SELECT * FROM users WHERE name LIKE '山%';

-- インデックスが使えない(低速)
SELECT * FROM users WHERE name LIKE '%田';
SELECT * FROM users WHERE name LIKE '%田%';

「%」が先頭にあると、全件スキャンになってしまうので注意が必要ですね。

特殊文字のエスケープ

% や _ を文字として検索したい場合は、エスケープが必要です。

-- %を文字として検索(データベースによって方法が異なる)
-- MySQLの例
SELECT * FROM products WHERE description LIKE '%\%%';

-- PostgreSQLの例
SELECT * FROM products WHERE description LIKE '%#%%' ESCAPE '#';

正規表現とは?LIKEとの違い

ここからは、より強力な正規表現について見ていきましょう。

正規表現(Regular Expression)の基本

正規表現は、文字列のパターンを表現するための記法です。

LIKEよりも遥かに複雑で柔軟なパターンマッチングができるんですね。

LIKEと正規表現の比較

項目LIKE正規表現
学習コスト低い高い
表現力限定的非常に高い
パフォーマンス比較的速いやや遅い
標準化SQL標準DB依存
使いどころシンプルな検索複雑なパターン

正規表現でできること

文字の種類を指定:

  • 数字のみ:[0-9]
  • 英字のみ:[a-zA-Z]
  • 特定の文字のみ:[あいうえお]

繰り返しを指定:

  • 1回以上:+
  • 0回以上:*
  • ちょうどn回:{n}
  • n回以上m回以下:{n,m}

選択肢を指定:

  • AまたはB:(A|B)

位置を指定:

  • 先頭:^
  • 末尾:$

複雑な条件も、正規表現なら1つの式で表現できます。


MySQL・MariaDBでの正規表現

データベースごとに正規表現の使い方が違います。まずはMySQLから見ていきましょう。

REGEXP/RLIKE演算子

MySQLでは、REGEXP または RLIKE を使います(どちらも同じ意味です)。

基本的な構文:

SELECT * FROM テーブル名
WHERE カラム名 REGEXP 'パターン';

基本的な使用例

数字を含むかチェック:

SELECT * FROM users WHERE name REGEXP '[0-9]';
-- マッチ例: '山田1号', 'user123'

特定の文字で始まる:

SELECT * FROM users WHERE name REGEXP '^山';
-- マッチ例: '山田', '山本'
-- 非マッチ例: '太山'(先頭ではない)

特定の文字で終わる:

SELECT * FROM users WHERE name REGEXP '田$';
-- マッチ例: '山田', '前田'
-- 非マッチ例: '田中'(末尾ではない)

複数の選択肢:

SELECT * FROM users WHERE name REGEXP '山田|田中|中村';
-- マッチ例: '山田太郎', '田中花子', '中村一郎'

実用的なパターン例

メールアドレスの形式チェック:

SELECT * FROM users 
WHERE email REGEXP '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$';

このパターンは、基本的なメールアドレスの形式を検証します。

電話番号の形式チェック(ハイフンあり):

SELECT * FROM contacts 
WHERE phone REGEXP '^0[0-9]{1,4}-[0-9]{1,4}-[0-9]{4}$';
-- マッチ例: '03-1234-5678', '090-1234-5678'

郵便番号の形式チェック:

SELECT * FROM addresses 
WHERE postal_code REGEXP '^[0-9]{3}-[0-9]{4}$';
-- マッチ例: '123-4567'

カタカナのみチェック:

SELECT * FROM users 
WHERE name_kana REGEXP '^[ァ-ヴー]+$';
-- マッチ例: 'ヤマダタロウ', 'タナカハナコ'

MySQL 8.0の新機能:REGEXP_LIKE

MySQL 8.0以降では、より標準的な REGEXP_LIKE 関数も使えます。

SELECT * FROM users 
WHERE REGEXP_LIKE(name, '^山', 'i');  -- 'i'は大文字小文字を区別しないオプション

PostgreSQLでの正規表現

PostgreSQLは、豊富な正規表現機能を持っています。

正規表現演算子

PostgreSQLでは、複数の正規表現演算子が用意されています。

演算子意味大文字小文字
~マッチする区別する
~*マッチする区別しない
!~マッチしない区別する
!~*マッチしない区別しない

使用例:

-- 大文字小文字を区別してマッチ
SELECT * FROM users WHERE name ~ '^山';

-- 大文字小文字を区別せずマッチ
SELECT * FROM users WHERE email ~* '^admin@';

-- マッチしないものを検索
SELECT * FROM users WHERE name !~ '[0-9]';
-- 数字を含まない名前のみ

POSIX正規表現の機能

PostgreSQLは、POSIX標準の正規表現をサポートしています。

文字クラス:

-- 数字のみチェック
SELECT * FROM products WHERE code ~ '^[[:digit:]]+$';

-- 英字のみチェック
SELECT * FROM users WHERE name ~ '^[[:alpha:]]+$';

-- 英数字のみチェック
SELECT * FROM codes WHERE value ~ '^[[:alnum:]]+$';

日本語を含むチェック:

-- ひらがなを含む
SELECT * FROM texts WHERE content ~ '[ぁ-ん]';

-- カタカナを含む
SELECT * FROM texts WHERE content ~ '[ァ-ヴ]';

-- 漢字を含む(範囲指定)
SELECT * FROM texts WHERE content ~ '[一-龯]';

実用例

IPv4アドレスの形式チェック:

SELECT * FROM servers 
WHERE ip_address ~ '^([0-9]{1,3}\.){3}[0-9]{1,3}$';

URLの形式チェック:

SELECT * FROM links 
WHERE url ~* '^https?://[a-z0-9.-]+\.[a-z]{2,}';

パスワード強度チェック(英字・数字・記号を含む8文字以上):

SELECT * FROM users 
WHERE password ~ '^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[@$!%*#?&])[A-Za-z0-9@$!%*#?&]{8,}$';

SQL Serverでの正規表現

SQL Serverは、標準では正規表現をサポートしていませんが、代替手段があります。

PATINDEX関数(限定的な機能)

PATINDEX関数は、ワイルドカードを使った簡易的なパターンマッチングができます。

基本的な構文:

PATINDEX('%pattern%', column_name)

戻り値が0より大きければマッチしています。

使用例:

-- 数字を含むかチェック
SELECT * FROM users 
WHERE PATINDEX('%[0-9]%', name) > 0;

-- 特定の文字を含む
SELECT * FROM products 
WHERE PATINDEX('%[ABC]%', product_code) > 0;

ただし、PATINDEXの機能は限定的で、複雑な正規表現は使えませんね。

CLR統合による正規表現

SQL Server 2005以降では、.NET Framework の正規表現を利用できます。

カスタム関数の作成例:

-- CLR関数を作成(管理者権限が必要)
CREATE FUNCTION dbo.RegexMatch
(
    @input NVARCHAR(MAX),
    @pattern NVARCHAR(MAX)
)
RETURNS BIT
AS EXTERNAL NAME [YourAssembly].[YourNamespace.YourClass].[RegexMatch];

-- 使用例
SELECT * FROM users 
WHERE dbo.RegexMatch(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$') = 1;

ただし、CLR統合の設定にはサーバー管理者権限が必要なので、実際に使える環境は限られます。

LIKE演算子での代替

複雑なパターンは諦めて、LIKEと複数条件の組み合わせで対応することも多いですね。

-- メールアドレスの簡易チェック
SELECT * FROM users 
WHERE email LIKE '%@%.%' 
  AND email NOT LIKE '%@%@%'
  AND LEN(email) > 5;

Oracleでの正規表現

Oracleは、充実した正規表現機能を提供しています。

REGEXP_LIKE関数

Oracleの正規表現は、REGEXP_LIKE関数を使います。

基本的な構文:

SELECT * FROM テーブル名
WHERE REGEXP_LIKE(カラム名, 'パターン', 'オプション');

オプション:

  • ‘i’: 大文字小文字を区別しない
  • ‘c’: 大文字小文字を区別する(デフォルト)
  • ‘m’: 複数行モード
  • ‘n’: .が改行にもマッチ

基本的な使用例

数字を含むチェック:

SELECT * FROM users 
WHERE REGEXP_LIKE(name, '[0-9]');

メールアドレス形式のチェック:

SELECT * FROM users 
WHERE REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$');

電話番号の形式チェック:

SELECT * FROM contacts 
WHERE REGEXP_LIKE(phone, '^0[0-9]{1,4}-[0-9]{1,4}-[0-9]{4}$');

Oracle独自の正規表現関数

Oracleには、正規表現を使った便利な関数がいくつかあります。

REGEXP_SUBSTR: パターンにマッチした部分を抽出

-- メールアドレスからドメイン部分を抽出
SELECT REGEXP_SUBSTR(email, '@[^@]+$') AS domain
FROM users;
-- 結果例: '@gmail.com', '@example.co.jp'

REGEXP_REPLACE: パターンにマッチした部分を置換

-- 電話番号のハイフンを削除
SELECT REGEXP_REPLACE(phone, '-', '') AS phone_no_hyphen
FROM contacts;
-- 結果例: '09012345678'

REGEXP_INSTR: パターンにマッチした位置を取得

-- 最初の数字の位置を取得
SELECT REGEXP_INSTR(name, '[0-9]') AS first_digit_position
FROM users;

REGEXP_COUNT: パターンにマッチした回数を取得

-- 文字列に含まれる数字の個数
SELECT REGEXP_COUNT(text, '[0-9]') AS digit_count
FROM documents;

正規表現の実践パターン集

実務でよく使うパターンをまとめました。

入力値の検証

日本の郵便番号:

-- MySQL/PostgreSQL
WHERE postal_code REGEXP '^[0-9]{3}-[0-9]{4}$'

-- Oracle
WHERE REGEXP_LIKE(postal_code, '^[0-9]{3}-[0-9]{4}$')

携帯電話番号(日本):

-- 090, 080, 070で始まる11桁
WHERE phone REGEXP '^0[789]0-[0-9]{4}-[0-9]{4}$'

クレジットカード番号(4桁-4桁-4桁-4桁):

WHERE card_number REGEXP '^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}$'

データの抽出と分類

全角文字のみのデータ:

-- PostgreSQL
WHERE text ~ '^[^\x00-\x7F]+$'

半角英数字のみのデータ:

WHERE text REGEXP '^[a-zA-Z0-9]+$'

ひらがなを含むデータ:

WHERE text REGEXP '[ぁ-ん]'

カタカナを含むデータ:

WHERE text REGEXP '[ァ-ヴ]'

データのクリーニング

連続したスペースを検出:

WHERE text REGEXP '  +'
-- 2つ以上連続したスペース

英字と数字以外の文字を含むデータ:

WHERE text REGEXP '[^a-zA-Z0-9]'

HTMLタグを含むデータ:

WHERE text REGEXP '<[^>]+>'

パフォーマンスの最適化

正規表現は便利ですが、処理が重くなりがちです。最適化のコツを紹介します。

インデックスを活用できるケース

正規表現でも、一部のパターンならインデックスが使えます。

前方一致の場合:

-- インデックスが使える可能性がある
WHERE name REGEXP '^山田'

-- LIKEのほうが確実にインデックスが使える
WHERE name LIKE '山田%'

前方一致なら、LIKEを使ったほうが確実ですね。

処理を分割する

複雑な正規表現は、シンプルな条件と組み合わせましょう。

非効率な例:

-- すべてのデータに対して複雑な正規表現を実行
SELECT * FROM users 
WHERE REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$');

効率的な例:

-- まずLIKEで絞り込んでから正規表現
SELECT * FROM users 
WHERE email LIKE '%@%.%'  -- インデックスが使える可能性
  AND REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$');

事前バリデーションの実装

データ登録時に正規表現でチェックしておけば、検索時の負荷が減ります。

-- バリデーション用カラムを追加
ALTER TABLE users ADD COLUMN email_valid BOOLEAN;

-- 定期的にチェック
UPDATE users 
SET email_valid = CASE 
    WHEN REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$') 
    THEN TRUE 
    ELSE FALSE 
END;

-- 検索は高速
SELECT * FROM users WHERE email_valid = TRUE;

よくあるエラーと対処法

正規表現を使っていて遭遇しがちなエラーと解決法です。

バックスラッシュのエスケープ

多くのデータベースで、バックスラッシュ(\)は特殊文字です。

問題:

-- これはエラーになることがある
WHERE text REGEXP '\d+'

解決策:

-- バックスラッシュを二重にする
WHERE text REGEXP '\\d+'

-- または文字クラスを使う
WHERE text REGEXP '[0-9]+'

特殊文字のエスケープ

正規表現の特殊文字(. + * ? など)を文字として扱いたい場合はエスケープが必要です。

-- ドット(.)を文字として検索
WHERE domain REGEXP '\\.com$'
-- マッチ例: 'example.com'
-- 非マッチ例: 'exampleXcom'

大文字小文字の扱い

データベースによって、デフォルトの動作が異なります。

MySQL:

-- デフォルトは大文字小文字を区別しない(照合順序による)
WHERE name REGEXP '^ABC'

-- 区別する場合はBINARYを使用
WHERE BINARY name REGEXP '^ABC'

PostgreSQL:

-- デフォルトは区別する
WHERE name ~ '^ABC'

-- 区別しない場合は~*を使用
WHERE name ~* '^ABC'

パフォーマンス問題

症状: 正規表現を使ったクエリが非常に遅い

対処法:

  1. EXPLAINで実行計画を確認
  2. 可能ならLIKEで代替
  3. インデックスが使えるように条件を工夫
  4. 正規表現の前に簡単な条件で絞り込み
-- 改善前
SELECT * FROM large_table 
WHERE content REGEXP '複雑なパターン';

-- 改善後
SELECT * FROM large_table 
WHERE length(content) > 10  -- まずシンプルな条件で絞る
  AND content LIKE '%キーワード%'
  AND content REGEXP '複雑なパターン';

よくある質問と回答

Q1. LIKEと正規表現、どちらを使うべきですか?

A. シンプルなパターンならLIKE、複雑なパターンなら正規表現を使いましょう。

LIKEが向いているケース:

  • 前方一致、後方一致、部分一致の検索
  • パフォーマンスを重視する場合
  • シンプルで読みやすいコードにしたい場合

正規表現が向いているケース:

  • 複雑なパターンマッチング(メールアドレス、電話番号など)
  • 文字の種類を指定したい場合(数字のみ、英字のみなど)
  • データの入力検証

Q2. 正規表現のパフォーマンスは悪いですか?

A. LIKEに比べると処理が重くなりがちです。

大量データに対して正規表現を使う場合は、以下の対策を検討しましょう:

  • WHERE句で事前に絞り込む
  • インデックスを活用できる条件と組み合わせる
  • アプリケーション側でチェックする
  • バリデーション結果をDBに保存しておく

Q3. データベースごとに正規表現の書き方が違うのですか?

A. はい、データベースによって記法や使える機能が異なります。

標準SQLには正規表現の仕様がないため、各データベースが独自に実装しているんですね。

移植性を考えるなら、基本的な正規表現だけを使うか、データベース固有の部分を関数化しておくと良いでしょう。

Q4. 日本語の正規表現は使えますか?

A. はい、使えます。ただし、文字コードの設定に注意が必要です。

-- ひらがな
WHERE text REGEXP '[ぁ-ん]'

-- カタカナ
WHERE text REGEXP '[ァ-ヴ]'

-- 漢字(範囲は環境によって調整が必要)
WHERE text REGEXP '[一-龯]'

データベースとテーブルの文字コードがUTF-8になっているか確認しましょう。

Q5. NOT LIKEやNOT REGEXPは使えますか?

A. はい、否定条件も使えます。

-- LIKEの否定
SELECT * FROM users WHERE name NOT LIKE '%田%';

-- REGEXPの否定(MySQL)
SELECT * FROM users WHERE name NOT REGEXP '[0-9]';

-- PostgreSQLの否定演算子
SELECT * FROM users WHERE name !~ '[0-9]';

ただし、NOTを使うとインデックスが効きにくくなるので注意が必要ですね。


まとめ:状況に応じて使い分けよう

SQLでのパターンマッチングは、LIKE演算子と正規表現を使い分けることが重要です。

この記事のポイント:

  • LIKE演算子はシンプルなパターンマッチングに最適
  • ワイルドカードは % (0文字以上)と _ (1文字)の2種類
  • 正規表現は複雑なパターンを表現できる強力なツール
  • データベースごとに正規表現の記法が異なる
  • パフォーマンスを考慮して適切な方法を選ぶ
  • 前方一致ならLIKEのほうがインデックスが効く
  • データの入力検証には正規表現が便利

使い分けの目安:

用途おすすめ
前方一致・後方一致・部分一致LIKE
メールアドレス検証正規表現
電話番号検証正規表現
数字のみ・英字のみチェック正規表現
大量データの検索LIKE(可能なら)
複雑なパターン正規表現

まずはLIKEで試してみて、表現できないパターンがあったら正規表現を検討する、という流れがおすすめです。

データの特性や検索頻度に合わせて、最適な方法を選んでくださいね!

コメント

タイトルとURLをコピーしました