0

こんにちは、以下のような値のテーブルがあります

    user_country
    -------------
    210|9|211
    210|211
    9|87
    210|117|54

そして、文字「|」でデータを分割する分割関数があります . ユーザーが 210|9 のような値を入力すると、210 と 9 の両方の値を含む列が返されます (つまり、行 1 だけが返されます)。複数の存在で試しましたが、実際の答えを得ることができませんでした

これまでに試した:

    SELECT 1
    FROM TABLE(split_text_fn('210|9', '|')) a
    WHERE EXISTS
       (SELECT 1
          FROM TABLE(split_text_fn('210|87', '|')) b
         WHERE     b.COLUMN_VALUE = a.COLUMN_VALUE
               AND EXISTS
                       (SELECT 1
                          FROM TABLE(split_text_fn('210|9', '|')) a1
                         WHERE a1.COLUMN_VALUE = b.COLUMN_VALUE))
4

2 に答える 2

0

私があなたを正しく理解していれば、あなたは次のようなものを求めていると思います:

WITH your_table AS (SELECT 1 user_id, '210|9|211' user_country FROM dual UNION ALL
                    SELECT 2 user_id, '210|211' user_country FROM dual UNION ALL
                    SELECT 3 user_id, '9|87' user_country FROM dual UNION ALL
                    SELECT 4 user_id, '210|117|54' user_country FROM dual),
-- end of mimicking a table containing your data; you wouldn't need the above subquery
-- as you would just select directly from your table instead
  vals_to_check AS (SELECT regexp_substr(:p_values_to_check_for, '[^'||:p_delimiter||']+', 1, LEVEL) val,
                           COUNT(DISTINCT regexp_substr(:p_values_to_check_for, '[^'||:p_delimiter||']+', 1, LEVEL)) OVER () cnt_vals
                    FROM   dual
                    CONNECT BY regexp_substr(:p_values_to_check_for, '[^'||:p_delimiter||']+', 1, LEVEL) IS NOT NULL)
SELECT yt.user_id,
       yt.user_country
FROM   your_table yt
       INNER JOIN vals_to_check vtc ON :p_delimiter||yt.user_country||:p_delimiter LIKE '%'||:p_delimiter||vtc.val||:p_delimiter||'%'
GROUP BY yt.user_id,
         yt.user_country,
         vtc.cnt_vals
HAVING   COUNT(*) = cnt_vals;

結果:

-- with the bind variables set to the following:
variable p_delimiter varchar2
variable p_values_to_check_for varchar2
exec :p_delimiter := '|'; :p_values_to_check_for := '210|9';

   USER_ID USER_COUNTRY
---------- ------------
         1 210|9|211

-- with the bind variables set to the following:
variable p_delimiter varchar2
variable p_values_to_check_for varchar2
exec :p_delimiter := '|'; :p_values_to_check_for := '210|211';

   USER_ID USER_COUNTRY
---------- ------------
         1 210|9|211
         2 210|211

NB 入力文字列を sql で直接分割しました。別の pl/sql 関数呼び出しは必要ありません。ただし、split_text_fn 関数を引き続き使用したい場合は、vals_to_checkサブクエリの宣言をスキップしてtable(split_text_fn(...))、メインの SQL ステートメントで your のみを使用できます。

于 2016-11-10T08:44:19.117 に答える
0

私が理解しているかどうかは完全にはわかりませんが...関数がパイプで区切られた文字列を取り、それを含むトークンの数に分割し、ユーザーがパイプで区切られた文字列をバインド変数として入力すると仮定し:input、ベーステーブルにはtable_1列とおそらく他の列があり、からのすべてのトークンを含むすべてのuser_country行を検索したい:table_1user_country:input

select * 
from   table_1
where not exists ( select column_value from table(split_text_fn(:input, '|')) 
                   minus 
                   select column_value from table(split_text_fn(user_country))
                 )
;

これにはおそらく多くの時間がかかります。これは、第 1 正規形に違反したことに対する代償です。この非常に貧弱な設計で優れたパフォーマンスを実現することも、データを取得することもできますが、両方を実現することはできません。

于 2016-11-09T23:19:52.090 に答える