3

これに似たレイアウトのテーブルがあります (所有していないため、変更できません)。

ID | CATEGORIES
---------------
1  | c1
2  | c2,c3
3  | c3,c2
4  | c3
5  | c4,c8,c5,c100

特定のカテゴリ ID を含む行を返す必要があります。値は文字列のどこにでもある可能性があるため、LIKE ステートメントを使用してクエリを作成することから始めます。

SELECT id FROM table WHERE categories LIKE '%c2%'; 行 2 と 3 を返します

SELECT id FROM table WHERE categories LIKE '%c3%' and categories LIKE '%c2%';行 2 と 3 は取得できますが、行 4 は取得できません

SELECT id FROM table WHERE categories LIKE '%c3%' or categories LIKE '%c2%';再び行 2、3、および 4 を取得します

LIKE私はすべてのステートメントが好きではありません。Oracle のドキュメントで見つけましFIND_IN_SET()たが、10g では動作しないようです。次のエラーが表示されます。

ORA-00904: "FIND_IN_SET": invalid identifier
00904. 00000 -  "%s: invalid identifier"

このクエリを実行する場合: SELECT id FROM table WHERE FIND_IN_SET('c2', categories);(ドキュメントの例) またはこのクエリ: SELECT id FROM table WHERE FIND_IN_SET('c2', categories) <> 0;(Google の例)

行 2 と 3 が返されることを期待します。

LIKE大量のステートメントを使用する代わりに、これらのクエリを作成するより良い方法はありますか?

4

5 に答える 5

12

LIKE を使用してできます。部分的な値を一致させたくないため、検索にコンマを含める必要があります。これはまた、テキストの先頭または末尾で値を検索するために余分なコンマを提供する必要があることを意味します:

select 
  * 
from
  YourTable 
where 
  ',' || CommaSeparatedValueColumn || ',' LIKE '%,SearchValue,%'

ただし、このクエリは、LIKE を使用するすべてのクエリと同様に、特に先頭にワイルドカードを使用すると遅くなります。

そしてリスクは常にあります。値の前後にスペースがある場合、または値自体にカンマが含まれている場合 (csv ファイルのように引用符で囲まれている場合)、このクエリは機能せず、さらにロジックを追加する必要があり、クエリの速度が低下します。さらに。

より良い解決策は、これらのカテゴリの子テーブルを追加することです。むしろ、カテゴリ用の別のテーブルと、それらを YourTable に相互リンクするテーブルです。

于 2011-08-27T06:51:04.560 に答える
2

1 列のテーブルを返す PIPELINED テーブル関数を作成できます。各行は、カンマ区切りの文字列からの値です。popリストからの文字列に次のようなものを使用し、putそれをテーブルの行として使用します。

PIPE ROW(ltrim(rtrim(substr(l_list, 1, l_idx - 1),' '),' '));

使用法:

SELECT * FROM MyTable 
WHERE 'c2' IN TABLE(Util_Pkg.split_string(categories));

詳細はこちら: Oracle ドキュメント

于 2014-06-05T11:26:37.150 に答える
1

はいといいえ...

"はい":

データを正規化します (強くお勧めします) - つまり、カテゴリ列を分割して、各カテゴリが別々になるようにします...その後、通常の方法でクエリを実行できます...

「いいえ」:
この「疑似構造」を保持している限り、いくつかの問題 (パフォーマンスなど) が発生し、次のようなことを行う必要があります。

SELECT * FROM MyTable WHERE categories LIKE 'c2,%' OR categories = 'c2' OR categories LIKE '%,c2,%' OR categories LIKE '%,c2'

絶対に必要な場合は、次のように FIND_IN_SET という名前の関数を定義できます。

CREATE OR REPLACE Function FIND_IN_SET
   ( vSET IN varchar2, vToFind IN VARCHAR2 )
   RETURN number
IS
    rRESULT number;
BEGIN

rRESULT := -1;
SELECT COUNT(*) INTO rRESULT FROM DUAL WHERE vSET LIKE ( vToFine || ',%' ) OR vSET = vToFind OR vSET LIKE ('%,' || vToFind || ',%') OR vSET LIKE ('%,' || vToFind);

RETURN rRESULT;

END;

次に、その関数を次のように使用できます。

SELECT * FROM MyTable WHERE FIND_IN_SET (categories, 'c2' ) > 0;
于 2011-08-27T04:35:00.680 に答える
1

将来の検索者のために、正規表現の方法を忘れないでください。

with tbl as (
select 1 ID, 'c1' CATEGORIES from dual
union
select 2 ID, 'c2,c3' CATEGORIES from dual
union
select 3 ID, 'c3,c2' CATEGORIES from dual
union
select 4 ID, 'c3' CATEGORIES from dual
union
select 5 ID, 'c4,c8,c5,c100' CATEGORIES from dual
)
select * 
from tbl
where regexp_like(CATEGORIES, '(^|\W)c3(\W|$)');

        ID CATEGORIES
---------- -------------
         2 c2,c3
         3 c3,c2
         4 c3

これは単語の境界で一致するため、コンマの後にスペースが続いていても機能します。より厳密に、コンマで値が区切られている場所のみに一致させたい場合は、'\W' をコンマに置き換えます。とにかく、正規表現を次のように読みます: 行頭または単語境界のグループに一致し、その後に対象の検索値が続き、単語境界または行末のグループが続きます。

于 2014-10-24T20:33:29.487 に答える