【SQL LIKE句】部分一致検索をマスターする!`%`と`_`ワイルドカードの使い方
Webサイトに検索機能は欠かせませんね。「『SQL』という単語を含む本を探したい」「名前が『鈴木』で始まるユーザーを一覧表示したい」といった、完全には一致しないけれど、一部分が合致するデータを探したい場面は数え切れないほどあります。WHERE句で =(イコール)を使えば完全一致のデータは探せますが、このような「あいまい検索」や「部分一致検索」はどうすれば良いのでしょうか?
その答えが、SQLのLIKE句です。LIKE句は、WHERE句と組み合わせることで、文字列の部分的な一致を条件にしたデータ抽出を可能にします。そして、その検索能力を飛躍的に高めるのが、ワイルドカードと呼ばれる特殊な記号です。トランプのジョーカーのように、どんな文字にも化けることができるこの記号を使いこなせば、あなたのデータ検索はもっと自由でパワフルになります。
この記事では、LIKE句の基本的な使い方から、2種類の主要なワイルドカード(% と _)の使い分け、そして実務で役立つ注意点まで、コピペで動くコードと共に徹底的に解説します。さあ、検索の達人を目指して、LIKE句の世界を探検しましょう!
準備:検索対象の書籍データを用意しよう
部分一致検索を試すために、まずは検索対象となるデータを用意しましょう。今回は、シンプルな書籍リストを管理するbooksテーブルを作成します。検索のバリエーションを試せるように、意図的に似たようなタイトルの本や、特殊な記号を含むタイトルを登録しておきます。
-- もしbooksテーブルが存在すれば削除(繰り返し試せるように)
DROP TABLE IF EXISTS books;
-- 新しいbooksテーブルを作成
CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
author TEXT NOT NULL,
price INTEGER
);
-- 初期データを挿入
INSERT INTO books (id, title, author, price) VALUES
(1, 'SQLをはじめよう', '山田 太郎', 2500),
(2, '実践!SQLデータ分析', '鈴木 一郎', 3200),
(3, 'Webデザインの教科書', '佐藤 花子', 2800),
(4, 'たのしいSQL入門', '山田 太郎', 2200),
(5, 'Webサイト制作ガイド', '佐藤 次郎', 3000),
(6, '成長率120%のマーケティング術', '田中 実', 1800),
(7, '続・SQLをはじめよう', '山田 太郎', 2600);
これで、様々なキーワードで検索を試す準備が整いました。
ワイルドカード①:`%` (パーセント)- 0文字以上の任意の文字列
%は、LIKE句で最もよく使われるワイルドカードです。これは「長さも種類も問わない、0文字以上の任意の文字列」を意味します。つまり、何でもアリのオールマイティなカードだと考えてください。
前方一致:「~で始まる」データを探す
検索したい文字列%という形で使うと、「指定した文字列で始まる」データを探すことができます。
シナリオ:「タイトルが『SQL』で始まる本を探したい」
SELECT * FROM books WHERE title LIKE 'SQL%';
実行結果:
id | title | author | price
---|-----------------|-----------|-------
1 | SQLをはじめよう | 山田 太郎 | 2500
IDが1の『SQLをはじめよう』が見つかりました。『たのしいSQL入門』や『実践!SQLデータ分析』は、"SQL"で始まっていないため、検索結果には含まれません。
後方一致:「~で終わる」データを探す
%検索したい文字列という形で使うと、「指定した文字列で終わる」データを探せます。
シナリオ:「著者名が『太郎』で終わる本を探したい」
SELECT * FROM books WHERE author LIKE '%太郎';
実行結果:
id | title | author | price
---|-----------------|-----------|-------
1 | SQLをはじめよう | 山田 太郎 | 2500
4 | たのしいSQL入門 | 山田 太郎 | 2200
7 | 続・SQLをはじめよう | 山田 太郎 | 2600
「山田 太郎」さんの本がすべてリストアップされました。
部分一致(中間一致):「~を含む」データを探す
これが最も汎用性の高い使い方です。%検索したい文字列%のように、検索キーワードを%で挟むことで、「指定した文字列をどこかに含む」すべてのデータを探し出すことができます。
シナリオ:「タイトルに『SQL』という単語が含まれる本をすべて探したい」
SELECT * FROM books WHERE title LIKE '%SQL%';
実行結果:
id | title | author | price
---|-----------------|-----------|-------
1 | SQLをはじめよう | 山田 太郎 | 2500
2 | 実践!SQLデータ分析 | 鈴木 一郎 | 3200
4 | たのしいSQL入門 | 山田 太郎 | 2200
7 | 続・SQLをはじめよう | 山田 太郎 | 2600
今度は、タイトルのどこに"SQL"があっても、すべて検索結果に含まれるようになりました。Webサイトの検索機能の裏側では、このようなクエリが頻繁に使われています。
ワイルドカード②:`_` (アンダースコア)- 任意の1文字
もう一つの重要なワイルドカードが_(アンダースコア)です。%が0文字以上の「なんでもあり」だったのに対し、_は「ちょうど1文字分の、任意の文字」を意味します。文字数は固定で1文字だけ、という点が大きな違いです。
例えば、「サイト」と「サイトウ」を区別したい、といった細かい検索で役立ちます。
シナリオ:「著者の姓が『佐藤』で、名が漢字2文字の人物を探したい(例:佐藤 花子、佐藤 次郎)」
-- '佐藤 ' の後に任意の1文字が2つ続くパターン
SELECT * FROM books WHERE author LIKE '佐藤 __';
実行結果:
id | title | author | price
---|------------------|-----------|-------
3 | Webデザインの教科書 | 佐藤 花子 | 2800
5 | Webサイト制作ガイド | 佐藤 次郎 | 3000
_を2つ続けることで、「任意の2文字」を指定し、「佐藤 花子」さんと「佐藤 次郎」さんの両方を見つけることができました。もしLIKE '佐藤 _'とすれば、名が1文字の人(もし存在すれば)だけがヒットします。
応用:`%`や`_`自体を文字として検索したい場合 (`ESCAPE`句)
さて、ここで少し意地悪な問題です。「タイトルに『120%』という文字列が含まれる本を探したい」場合はどうすれば良いでしょうか?
何も考えずにWHERE title LIKE '%120%%'と書くと、最初の%と最後の%はワイルドカードとして解釈されてしまい、意図した通りの検索ができません。このように、ワイルドカードとして使われる文字自体を「ただの文字」として検索したい場合に登場するのがESCAPE句です。
ESCAPE句を使うと、「この文字の直後にあるワイルドカードは、特殊な意味を無効にする(エスケープする)」という特別な「エスケープ文字」を自分で定義できます。
-- '!'をエスケープ文字として定義
SELECT * FROM books WHERE title LIKE '%120!%%' ESCAPE '!';
このクエリでは、ESCAPE '!'で、!をエスケープ文字に指定しました。これにより、!%と書かれた部分は「これはワイルドカードではなく、ただの文字としての '%' ですよ」という意味になります。結果として、IDが6の『成長率120%のマーケティング術』だけが正しくヒットします。
エスケープ文字には、!や#、\(バックスラッシュ)などがよく使われます。
【体験コーナー】ブラウザでSQLを動かし、部分一致検索を試そう!
知識をスキルに変える時間です! 以下のHTMLコードを丸ごとコピーして、sql_like_test.htmlのようなファイル名で保存し、ブラウザで開いてみてください。あなた専用のSQL実行環境が立ち上がり、この記事で使っているbooksテーブルが用意されています。
%や_の位置を変えたり、キーワードを変えたりして、検索結果がどう変わるか色々試してみてください。検索の達人への道は、試行錯誤の中にあります!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SQL LIKE句 オンライン実行環境</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; line-height: 1.7; color: #333; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
h1 { color: #3498db; }
textarea { width: 100%; height: 180px; font-family: "SF Mono", "Consolas", monospace; font-size: 16px; padding: 12px; border: 1px solid #ccc; border-radius: 6px; box-sizing: border-box; margin-bottom: 1rem; }
button { background-color: #3498db; color: white; border: none; padding: 12px 22px; font-size: 16px; border-radius: 6px; cursor: pointer; transition: background-color 0.2s; }
button:hover { background-color: #2980b9; }
button:disabled { background-color: #bdc3c7; cursor: not-allowed; }
#result-container { margin-top: 2rem; border: 1px solid #ddd; padding: 1rem; border-radius: 6px; background: #fdfdfd; min-height: 50px; }
#error-message { color: #e74c3c; font-weight: bold; }
table { border-collapse: collapse; width: 100%; margin-top: 1rem; }
th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
th { background-color: #f2f2f2; }
tr:nth-child(even) { background-color: #f9f9f9; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script>
</head>
<body>
<h1>SQLを試してみよう!</h1>
<p>下のテキストエリアにSQL文を入力して「実行」ボタンを押してください。色々なキーワードで検索してみましょう!</p>
<textarea id="sql-input">-- タイトルに「Web」を含む本を探してみよう
SELECT * FROM books WHERE title LIKE '%Web%';
</textarea>
<button id="execute-btn">実行</button>
<div id="result-container">
<p id="error-message"></p>
<div id="result-output"></div>
</div>
<script>
const sqlInput = document.getElementById('sql-input');
const executeBtn = document.getElementById('execute-btn');
const errorMsg = document.getElementById('error-message');
const resultOutput = document.getElementById('result-output');
let db;
async function initDb() {
executeBtn.disabled = true;
executeBtn.textContent = 'DB準備中...';
try {
const SQL = await initSqlJs({
locateFile: file => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/${file}`
});
db = new SQL.Database();
const setupSql = `
DROP TABLE IF EXISTS books;
CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
author TEXT NOT NULL,
price INTEGER
);
INSERT INTO books (id, title, author, price) VALUES
(1, 'SQLをはじめよう', '山田 太郎', 2500),
(2, '実践!SQLデータ分析', '鈴木 一郎', 3200),
(3, 'Webデザインの教科書', '佐藤 花子', 2800),
(4, 'たのしいSQL入門', '山田 太郎', 2200),
(5, 'Webサイト制作ガイド', '佐藤 次郎', 3000),
(6, '成長率120%のマーケティング術', '田中 実', 1800),
(7, '続・SQLをはじめよう', '山田 太郎', 2600);
`;
db.run(setupSql);
executeBtn.disabled = false;
executeBtn.textContent = '実行';
resultOutput.innerHTML = '<p>準備完了!自由にSQLを試してみてください。</p>';
} catch (err) {
errorMsg.textContent = 'データベースの初期化に失敗しました: ' + err.message;
console.error(err);
}
}
function executeSql() {
if (!db) return;
const sql = sqlInput.value;
errorMsg.textContent = '';
resultOutput.innerHTML = '';
try {
const results = db.exec(sql);
if (results.length === 0) {
resultOutput.innerHTML = '<p>クエリは成功しましたが、結果セットは返されませんでした。</p>';
return;
}
results.forEach(result => {
const table = document.createElement('table');
const thead = document.createElement('thead');
const tbody = document.createElement('tbody');
const headerRow = document.createElement('tr');
result.columns.forEach(colName => {
const th = document.createElement('th');
th.textContent = colName;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
result.values.forEach(row => {
const bodyRow = document.createElement('tr');
row.forEach(cellValue => {
const td = document.createElement('td');
td.textContent = cellValue === null ? 'NULL' : cellValue;
bodyRow.appendChild(td);
});
tbody.appendChild(bodyRow);
});
table.appendChild(thead);
table.appendChild(tbody);
resultOutput.appendChild(table);
});
} catch (err) {
errorMsg.textContent = 'SQLエラー: ' + err.message;
console.error(err);
}
}
executeBtn.addEventListener('click', executeSql);
initDb();
</script>
</body>
</html>
気をつけるべき点:パフォーマンスと大文字・小文字の区別
LIKE句は非常に便利ですが、実務で使う際にはいくつか注意点があります。
- パフォーマンス:
LIKE '%keyword'やLIKE '%keyword%'のように、検索文字列の前方に%を付けると、検索パフォーマンスが大幅に低下することがあります。これは、データベースがインデックス(索引)を効率的に使えなくなるためです。データが数百万件もあるような巨大なテーブルでこれを行うと、検索に非常に時間がかかる可能性があります。可能な限りLIKE 'keyword%'のような前方一致検索を使うのが、パフォーマンスを維持するコツです。 - 大文字と小文字の区別:
'sql'と'SQL'を区別するかどうかは、データベースの種類や設定(照合順序)によって異なります。MySQLのデフォルト設定などでは区別しませんが、他のデータベースでは厳密に区別することもあります。大文字・小文字を区別せずに検索したい場合は、LOWER()やUPPER()といった関数を使って、WHERE LOWER(title) LIKE '%sql%'のように、比較する文字列をすべて小文字(または大文字)に揃えるのが確実な方法です。
大量のテキストデータから高速に検索を行いたい場合は、LIKE句よりも「全文検索(Full-Text Search)」という、より高度な検索機能を使うのが一般的です。まずはLIKE句をマスターし、次のステップとして全文検索について学んでみるのも良いでしょう。
まとめ
今回は、SQLで部分一致検索を行うためのLIKE句について、その強力な助っ人であるワイルドカードを中心に学びました。
LIKE句:WHERE句と使い、文字列のあいまい検索を実現する。- ワイルドカード
%: 0文字以上の任意の文字列にマッチする。'A%'(前方一致)、'%A'(後方一致)、'%A%'(部分一致)の3パターンが基本。 - ワイルドカード
_: ちょうど1文字の任意の文字にマッチする。文字数を指定したい場合に使う。 ESCAPE句:%や_という文字自体を検索したい場合に、エスケープ文字を定義してワイルドカードの機能を無効化する。- 注意点: 前方
%のパフォーマンス問題と、データベースによる大文字・小文字の扱いの違いを意識することが重要。
LIKE句を使いこなすことは、ユーザーにとって使いやすい検索機能を提供する上で不可欠なスキルです。ぜひ、この記事の体験コーナーで様々なパターンを試し、部分一致検索の感覚を身体で覚えてください。あなたのSQLスキルがまた一段とレベルアップしたはずです!