「名前に『田』が含まれる人を検索したい」
「メールアドレスが特定のドメインで終わるデータだけ抽出したい」
「電話番号の形式が正しいかチェックしたい」
こんな要求、データベースを扱っていると頻繁に出てきますよね。
SQLには、こうした柔軟な検索を実現するための強力な機能が2つあります。それが「LIKE演算子」と「正規表現」です。
この記事では、SQLでのパターンマッチングの基本から、データベースごとの正規表現の使い方まで、初心者の方にも分かりやすく解説していきます。実務ですぐに使える実例もたくさん紹介しますよ。
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'
パフォーマンス問題
症状: 正規表現を使ったクエリが非常に遅い
対処法:
- EXPLAINで実行計画を確認
- 可能ならLIKEで代替
- インデックスが使えるように条件を工夫
- 正規表現の前に簡単な条件で絞り込み
-- 改善前
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で試してみて、表現できないパターンがあったら正規表現を検討する、という流れがおすすめです。
データの特性や検索頻度に合わせて、最適な方法を選んでくださいね!

コメント