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

我不完全确定我理解了,但是...假设您的函数将采用管道分隔的字符串并将其拆分为它包含的多个标记,并假设用户输入了一个管道分隔的字符串作为绑定变量:input,并且您的基表table_1包含一列user_country,可能还有其他列,并且您希望找到table_1其中user_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))
                 )
;

这可能会花费很多时间——违反第一范式所要付出的代价。您可以拥有良好的性能,或者您可以在这种非常糟糕的设计中拥有数据,但不能两者兼而有之。

于 2016-11-09T23:19:52.090 回答
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

注意我直接在 sql 中对输入字符串进行了拆分——不需要单独的 pl/sql 函数调用。但是,您可能希望继续使用您的 split_text_fn 函数,在这种情况下,您可以跳过声明vals_to_check子查询而只table(split_text_fn(...))在主 SQL 语句中使用您的。

于 2016-11-10T08:44:19.117 回答