MySQL 入門

MySQL LIKE 演算子

本章では、MySQLにおける LIKE 演算子を使用した文字列データのパターンマッチング(Pattern Matching)に焦点を当てます。以前の章で学んだ WHERE 句では、=, >, < などの演算子を使用して正確な一致や比較を行いましたが、LIKE 演算子は指定されたパターンに一致するデータを検索するための柔軟な手段を提供します。これは、正確な値が不明であっても、その構造や一部の内容がわかっている場合のテキスト情報のクエリにおいて非常に重要です。

1. LIKE 演算子の紹介

LIKE 演算子は WHERE 句で使用され、カラム(Column)内の指定されたパターンを検索します。文字列カラムに特定の文字列が含まれているか、特定の文字で始まっているか、特定の末尾で終わっているか、あるいは特定の順序で文字が並んでいる行を探す際に特に有効です。LIKE 演算子はワイルドカード(Wildcard characters)と組み合わせてパターンを定義します。

MySQLでは、主に2つのワイルドカードを LIKE と共に使用します:

  • % (パーセント記号):0文字、1文字、または複数文字の任意の文字列を表します。
  • _ (アンダースコア):単一の任意の1文字を表します。

2. パーセント記号 (%) ワイルドカード

% ワイルドカードは、0文字以上の任意の文字シーケンスのプレースホルダーとして機能します。非常に用途が広く、パターンの先頭、末尾、あるいは中間に配置することができます。

2.1 % ワイルドカードの使用例

デモンストレーションのために、world データベースの city(都市)テーブルを使用します。

1. 特定のシーケンスで始まる文字列を検索:

SELECT
    Name,
    CountryCode,
    District
FROM
    world.city
WHERE
    Name LIKE 'Lon%'; -- 'Lon' で始まる都市名を検索

このクエリは、'London'(ロンドン)、'Long Beach'(ロングビーチ)、'Longueuil'(ロングイユ)など、後に続く文字に関係なく "Lon" で始まるすべての都市名を取得します。

2. 特定のシーケンスで終わる文字列を検索:

SELECT
    Name,
    CountryCode,
    District
FROM
    world.city
WHERE
    Name LIKE '%ville'; -- 'ville' で終わる都市名を検索

このクエリは、'Jacksonville'(ジャクソンビル)、'Louisville'(ルイビル)、'Nashville'(ナッシュビル)など、"ville" で終わる名前の都市を返します。

3. 任意の位置に特定のシーケンスを含む文字列を検索:

SELECT
    Name,
    CountryCode,
    District
FROM
    world.city
WHERE
    Name LIKE '%burg%'; -- どこかに 'burg' を含む都市名を検索

このクエリは、'Hamburg'(ハンブルク)、'St. Petersburg'(サンクトペテルブルク)、'Edinburgh'(エディンバラ)など、任意の位置に "burg" シーケンスを含む都市名にマッチします。

4. 特定のシーケンスで始まり、かつ終わる文字列を検索:

SELECT
    Name,
    CountryCode,
    District
FROM
    world.city
WHERE
    Name LIKE 'San %isco'; -- 'San ' で始まり 'isco' で終わる都市名を検索

このパターン San %isco は、主に 'San Francisco'(サンフランシスコ)にマッチします。% が "San " と "isco" の間にある任意の文字を許容するためです。

3. アンダースコア (_) ワイルドカード

_ ワイルドカードは、単一文字のプレースホルダーとして機能します。特定の文字位置は不明または可変であるが、文字列の断片の長さが固定されているパターンをマッチさせたい場合に便利です。

3.1 _ ワイルドカードの使用例

world.city テーブルを使用した例です:

1. 特定の文字数を持つ文字列を検索:

SELECT
    Name,
    CountryCode,
    District
FROM
    world.city
WHERE
    Name LIKE '____'; -- ちょうど4文字の都市名を検索

このクエリは、'Rome'(ローマ)、'Oslo'(オスロ)、'Bern'(ベルン)、'Lima'(リマ)、'Doha'(ドーハ)など、ちょうど4文字で構成される都市名を返します。

2. 既知の位置に特定の文字がある文字列を検索:

SELECT
    Name,
    CountryCode,
    District
FROM
    world.city
WHERE
    Name LIKE 'P_ris'; -- 'P' で始まり、次に任意の1文字、その後に 'ris' が続く都市を検索

このクエリは 'Paris'(パリ)にマッチします。アンダースコアが 'a' の位置を正確に占めているためです。'Pariss' や 'P_aris' にはマッチしません。これが _ による単一文字制限の特徴です。

3. _% ワイルドカードを組み合わせて使用:

SELECT
    Name,
    CountryCode,
    District
FROM
    world.city
WHERE
    Name LIKE '_l%nd'; -- 2文字目が 'l' で、かつ 'nd' で終わる都市名を検索

このパターンは、'Portland'(ポートランド)、'Cleveland'(クリーブランド)、'Oakland'(オークランド)などにマッチします。_ が1文字目の任意の1文字、l が2文字目、% が中間にある任意の文字シーケンス、nd が末尾のシーケンスにそれぞれマッチします。

4. エスケープ文字 (Escaping Wildcards)

検索対象の実際の文字列自体に %_ の文字が含まれている場合があります。そのまま LIKE を使用すると、MySQLはこれらをワイルドカードとして解釈してしまいます。これらの文字そのものを検索するには、「エスケープ(Escape)」する必要があります。

ESCAPE 句を使用するとエスケープ文字を指定でき、その直後の文字をワイルドカードではなく「リテラル文字(文字通りそのもの)」として扱うようMySQLに指示できます。デフォルトのエスケープ文字はバックスラッシュ(\)ですが、任意の文字を指定することも可能です。

4.1 エスケープワイルドカードの例

製品説明カラムから、"20% off" という文字列を含む製品を検索したいとします。

SELECT
    ProductName,
    Description
FROM
    products
WHERE
    Description LIKE '%20\% off%'; -- 文字通りの '20% off' を検索

この例では、\% がMySQLに対してパーセント記号をリテラル文字として扱うよう指示しています。アンダースコアを検索したい場合は、\_ を使用します。

カスタムエスケープ文字を指定することもできます:

SELECT
    ProductName,
    Description
FROM
    products
WHERE
    Description LIKE '%20#% off%' ESCAPE '#'; -- '#' をエスケープ文字として使用して '20% off' を検索

ここでは # がエスケープ文字として宣言されているため、#% はリテラルとしてのパーセント記号と解釈されます。

5. NOT LIKE 演算子

NOT LIKE 演算子は、文字列が指定されたパターンに一致しない行を取得するために使用されます。これは LIKE の論理的な反転です。

5.1 NOT LIKE の使用例

'A' で始まらないすべての都市名を検索する場合:

SELECT
    Name,
    CountryCode,
    District
FROM
    world.city
WHERE
    Name NOT LIKE 'A%'; -- 'A' で始まらない都市名を検索

このクエリは 'Amsterdam'(アムステルダム)、'Athens'(アテネ)、'Atlanta'(アトランタ)などの 'A' で始まる都市を除外し、それ以外のすべての都市名を返します。

6. 実践的な検討事項とパフォーマンスの最適化

LIKE 演算子、特にパターンがワイルドカード(%_)で始まる場合、正確な一致や範囲検索よりも効率が低下することがあります。これは、パターンの先頭がワイルドカードの場合、MySQLがインデックスを効果的に利用できず、フルテーブルスキャン(Full Table Scan)が発生する可能性があるためです。

  • インデックスの使用 (Index Usage):LIKE パターンがワイルドカードで始まらない場合(例:Name LIKE 'Lon%')、MySQLは通常、Name カラム上のインデックスを使用できます。最初の文字に基づいて検索範囲を効果的に絞り込めるためです。
  • フルテーブルスキャン (Full Table Scans):パターンがワイルドカードで始まる場合(例:Name LIKE '%burg%'Name LIKE '_l%nd')、MySQLは通常インデックスを使用できません。これにより、データベースは全行をスキャンしてパターンをチェックせざるを得なくなり、大規模なテーブルでは非常に低速になります。
  • 大文字小文字の区別 (Case Sensitivity):デフォルト設定の多くのキャラクタセットにおいて、MySQLの LIKE による比較は大文字と小文字を区別しません。例えば、LIKE 'london' は 'London', 'london', 'LONDON' のすべてにマッチします。厳密に区別する必要がある場合は、BINARY 演算子を使用します(例:WHERE Name LIKE BINARY 'Lon%')。