web-dev-qa-db-ja.com

SQLの結合でlikeを使用する方法は?

テーブルAとテーブルBの2つのテーブルがあり、結合を実行したいが、一致条件はAの列がBの列に「似ている」必要があることを意味します。つまり、 B:

例:Aの列が「foo」の場合。次に、Bの列が「fooblah」、「somethingfooblah」、または単に「foo」の場合、結合が一致します。標準のlikeステートメントでワイルドカードを使用する方法は知っていますが、結合を行うときに混乱します。これは理にかなっていますか?ありがとう。

44
jim

[〜#〜] instr [〜#〜] を使用:

SELECT *
  FROM TABLE a
  JOIN TABLE b ON INSTR(b.column, a.column) > 0

LIKEの使用:

SELECT *
  FROM TABLE a
  JOIN TABLE b ON b.column LIKE '%'+ a.column +'%'

CONCATでLIKEを使用する:

SELECT *
  FROM TABLE a
  JOIN TABLE b ON b.column LIKE CONCAT('%', a.column ,'%')

すべてのオプションで、大文字と小文字の区別を気にせずに一致するようにするために、比較する前に列の値を大文字にしたいと思うでしょう。

SELECT *
  FROM (SELECT UPPER(a.column) 'ua'
         TABLE a) a
  JOIN (SELECT UPPER(b.column) 'ub'
         TABLE b) b ON INSTR(b.ub, a.ua) > 0

最も効率的な方法は、最終的に EXPLAIN plan の出力に依存します。

JOIN句は、WHERE句の記述と同じです。 JOIN構文は、標準化されているため、ANSI JOINとも呼ばれます。非ANSI JOINは次のようになります。

SELECT *
  FROM TABLE a,
       TABLE b
 WHERE INSTR(b.column, a.column) > 0

非ANSI LEFT JOINの例を気にするつもりはありません。 ANSI JOIN構文の利点は、テーブルを結合しているものとWHERE句で実際に起こっていることを分離することです。

75
OMG Ponies

MySQLでは、次のことを試すことができます。

SELECT * FROM A INNER JOIN B ON B.MYCOL LIKE CONCAT('%', A.MYCOL, '%');

もちろん、これは完全なテーブルスキャンを実行するため、非常に非効率的なクエリになります。

更新:これは証拠です


create table A (MYCOL varchar(255));
create table B (MYCOL varchar(255));
insert into A (MYCOL) values ('foo'), ('bar'), ('baz');
insert into B (MYCOL) values ('fooblah'), ('somethingfooblah'), ('foo');
insert into B (MYCOL) values ('barblah'), ('somethingbarblah'), ('bar');
SELECT * FROM A INNER JOIN B ON B.MYCOL LIKE CONCAT('%', A.MYCOL, '%');
+-------+------------------+
| MYCOL | MYCOL            |
+-------+------------------+
| foo   | fooblah          |
| foo   | somethingfooblah |
| foo   | foo              |
| bar   | barblah          |
| bar   | somethingbarblah |
| bar   | bar              |
+-------+------------------+
6 rows in set (0.38 sec)
19
Asaph

これが頻繁に実行する必要がある場合は、テーブルAとテーブルBの関係を非正規化することができます。

たとえば、テーブルBへの挿入時に、部分マッピングに基づいてBをAにマッピングするジャンクションテーブルに0個以上のエントリを書き込むことができます。同様に、いずれかのテーブルを変更すると、この関連付けが更新される可能性があります。

これはすべて、テーブルAとBが変更される頻度に依存します。それらがかなり静的である場合、INSERTでヒットすることは、SELECTで繰り返されるヒットより痛みが少ないです。

5
David Andres

結合で条件基準を使用することは、Where句とは明らかに異なります。テーブル間のカーディナリティにより、Joins句とWhere句に違いが生じる可能性があります。

たとえば、外部結合でLike条件を使用すると、結合にリストされている最初のテーブルのすべてのレコードが保持されます。 Where句で同じ条件を使用すると、結合が暗黙的に内部結合に変更されます。通常、Where句の条件付き比較を行うには、両方のテーブルにレコードが存在する必要があります。

私は通常、前の回答の1つで与えられたスタイルを使用します。

tbl_A as ta
    LEFT OUTER JOIN tbl_B AS tb
            ON ta.[Desc] LIKE '%' + tb.[Desc] + '%'

このようにして、結合タイプを制御できます。

2
Geoffrey Fuller

サーバーLIKEまたはINSTR(またはT-SQLのCHARINDEX)でクエリを作成するのに時間がかかりすぎるため、次の構造のようにLEFTを使用します。

select *
from little
left join big
on left( big.key, len(little.key) ) = little.key

'%' + b + '%'を使用した他の提案とは異なり、クエリに対してendingsを変更した場合にのみ機能する可能性があることを理解していますが、b + '%'のみが必要な場合は十分かつはるかに高速です。

(メモリではなく)速度を最適化する別の方法は、「lenkey」として「len(little.key)」である「little」の列を作成し、代わりに上記のクエリでユーザーを作成することです。