Oracle SQL:检查逗号分隔字符串中是否存在指定的单词

发布于 2025-01-27 03:00:25 字数 765 浏览 4 评论 0 原文

我有一个SQL函数,它使我返回一串逗号分隔的国家代码。

我已经在另一个表中配置了一些特定代码,并且以后可能会删除或添加更多。

我想检查逗号分开的字符串是否只是这些特定国家代码的组合。也就是说,如果该字符串具有除指定的代码以外的单个国家代码,则应返回true。

假设我在静态数据表GB和CH中配置了两个行。然后我需要以下结果:

的字符串 函数结果
gb false
false false
gb,ch false
ch,gb false
gb,fr true
fr,es true
es,ch true
ch,gb,gb,es true

我在Oracle 19c上,只能使用可用于此版本的功能。另外,我希望它得到优化。就像我可以检查字符串中的值数,然后计算每个特定代码。如果不匹配,则显然存在一些其他代码。但是我不想使用循环。

有人可以建议我一个更好的选择。

I have an SQL function that returns me a string of comma separated country codes.

I have configured some specific codes in another table and I may remove or add more later.

I want to check if the comma separated string is only the combination of those specific country codes or not. That said, if that string is having even a single country code other than the specified ones, it should return true.

Suppose I configured two rows in the static data table GB and CH. Then I need below results:

String from function result
GB false
CH false
GB,CH false
CH,GB false
GB,FR true
FR,ES true
ES,CH true
CH,GB,ES true

I am on Oracle 19c and can use only the functions available for this version. Plus I want it to be optimised. Like I can check the number of values in string and then count for each specific code. If not matching then obviously some other codes are present. But I don't want to use loops.

Can someone please suggest me a better option.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

笑脸一如从前 2025-02-03 03:00:25

假设静态表中的所有国家代码以及逗号分隔字符串中的所有令牌始终都是两个字符串,您可以做这样的事情:

with
  static_data(country_code) as (
    select 'GB' from dual union all
    select 'CH' from dual
  )
, sample_inputs(string_from_function) as (
    select 'GB'       from dual union all
    select 'CH'       from dual union all
    select 'GB,CH'    from dual union all
    select 'CH,GB'    from dual union all
    select 'GB,FR'    from dual union all
    select 'FR,ES'    from dual union all
    select 'ES,CH'    from dual union all
    select 'CH,GB,ES' from dual
  )
select string_from_function,
       case when regexp_replace(string_from_function,
                   ',| |' || (select listagg(country_code, '|')
                                       within group (order by null)
                              from   static_data))
                 is null then 'false' else 'true' end as result
from   sample_inputs
;

输出:

STRING_FROM_FUNCTION   RESULT  
---------------------- --------
GB                     false   
CH                     false   
GB,CH                  false   
CH,GB                  false   
GB,FR                  true    
FR,ES                  true    
ES,CH                  true    
CH,GB,ES               true

正则表达式替代逗号,空间,每两个 - 带有 null 的静态数据表中的字母乡村代码。如果整个过程的结果是 null ,则CSV中的所有编码都在静态表中;这就是您需要测试的。

假设保证了像GBCH这样的令牌(对于像“大障碍国家”这样的国家)不会被误认为是可以的,因为GB和CH分别可以。

Assuming that all country codes in the static table, as well as all tokens in the comma-separated strings, are always exactly two-letter strings, you could do something like this:

with
  static_data(country_code) as (
    select 'GB' from dual union all
    select 'CH' from dual
  )
, sample_inputs(string_from_function) as (
    select 'GB'       from dual union all
    select 'CH'       from dual union all
    select 'GB,CH'    from dual union all
    select 'CH,GB'    from dual union all
    select 'GB,FR'    from dual union all
    select 'FR,ES'    from dual union all
    select 'ES,CH'    from dual union all
    select 'CH,GB,ES' from dual
  )
select string_from_function,
       case when regexp_replace(string_from_function,
                   ',| |' || (select listagg(country_code, '|')
                                       within group (order by null)
                              from   static_data))
                 is null then 'false' else 'true' end as result
from   sample_inputs
;

Output:

STRING_FROM_FUNCTION   RESULT  
---------------------- --------
GB                     false   
CH                     false   
GB,CH                  false   
CH,GB                  false   
GB,FR                  true    
FR,ES                  true    
ES,CH                  true    
CH,GB,ES               true

The regular expression replaces comma, space, and every two-letter country code from the static data table with null. If the result of the whole thing is null, then all coded in the csv are in the static table; that's what you need to test for.

The assumptions guarantee that a token like GBCH (for a country like "Great Barrier Country Heat") would not be mistakenly considered OK because GB and CH are OK separately.

怎言笑 2025-02-03 03:00:25

您可以将CSV列转换为表格并使用。例如

with tbl(id,str) as
( 
SELECT 1,'GB,CH' FROM DUAL UNION ALL
SELECT 2,'GB,CH,FR' FROM DUAL UNION ALL
SELECT 3,'GB' FROM DUAL 
),
countries (code) as
(SELECT 'GB' FROM DUAL UNION ALL
 SELECT 'CH' FROM DUAL 
)

select t.* ,
     case when exists (
        select 1 
        from xmltable(('"' || REPLACE(str, ',', '","') || '"')) s  
        where trim(s.column_value) not in (select code from countries)
      ) 
      then 'true' else 'false' end flag
from tbl t

You can convert a csv column to a table and use EXISTS. For example

with tbl(id,str) as
( 
SELECT 1,'GB,CH' FROM DUAL UNION ALL
SELECT 2,'GB,CH,FR' FROM DUAL UNION ALL
SELECT 3,'GB' FROM DUAL 
),
countries (code) as
(SELECT 'GB' FROM DUAL UNION ALL
 SELECT 'CH' FROM DUAL 
)

select t.* ,
     case when exists (
        select 1 
        from xmltable(('"' || REPLACE(str, ',', '","') || '"')) s  
        where trim(s.column_value) not in (select code from countries)
      ) 
      then 'true' else 'false' end flag
from tbl t
稚气少女 2025-02-03 03:00:25

一种选择是逐一匹配国家代码,然后确定是否存在从提供的文字作为参数中的额外的非匹配国家 /地区。

以下一个具有完整加入的人将考虑上面的逻辑

WITH
  FUNCTION with_function(i_countries VARCHAR2) RETURN VARCHAR2 IS
    o_val VARCHAR2(10);
  BEGIN
     SELECT CASE WHEN SUM(NVL2(t.country_code,0,1))=0 THEN 'false' 
                 ELSE 'true'
                  END
       INTO o_val           
       FROM (SELECT DISTINCT REGEXP_SUBSTR(i_countries,'[^ ,]+',1,level) AS country
               FROM dual
            CONNECT BY level <= REGEXP_COUNT(i_countries,',')+1) tt
       FULL JOIN t
              ON tt.country = t.country_code;      
    RETURN o_val;
  END;
SELECT with_function(<comma-seperated-parameter-list>) AS result
  FROM dual

One option is to match the country codes one by one, and then determine whether there exists an extra non-matched country from the provided literal as parameter.

The following one with FULL JOIN would help by considering the logic above

WITH
  FUNCTION with_function(i_countries VARCHAR2) RETURN VARCHAR2 IS
    o_val VARCHAR2(10);
  BEGIN
     SELECT CASE WHEN SUM(NVL2(t.country_code,0,1))=0 THEN 'false' 
                 ELSE 'true'
                  END
       INTO o_val           
       FROM (SELECT DISTINCT REGEXP_SUBSTR(i_countries,'[^ ,]+',1,level) AS country
               FROM dual
            CONNECT BY level <= REGEXP_COUNT(i_countries,',')+1) tt
       FULL JOIN t
              ON tt.country = t.country_code;      
    RETURN o_val;
  END;
SELECT with_function(<comma-seperated-parameter-list>) AS result
  FROM dual

Demo

記柔刀 2025-02-03 03:00:25

这是一个解决方案

 使用CTE为
(选择不同的
s,regexp_substr(s,'[^,]+',1,级别)代码来自字符串
    
 通过Regexp_substr(s,'[^,]+',1,1,级别)连接不是null
)
选择 
s字符串,最小(存在的情况
  (从国家 /地区选择 *
   cod =代码)然后'yes'
   否则'no'end)all_found
来自CTE
组
s命令s;
 
字符串| all_found
:----- | :---------
ch |是的      
CH,GB |是的      
ES |不       
Es,Ch |不       
fr |不       
GB |是的      
GB,ch |是的      
GB,ES |不       

db<>fiddle here

Here is one solution

with cte as
(select distinct
s,regexp_substr(s, '[^,]+',1, level) code from strings
    
 connect by regexp_substr(s, '[^,]+', 1, level) is not null
)
select 
s string,min(case when exists
  (select * from countries
   where cod = code) then 'yes'
   else 'no'end) all_found
from cte
group by s
order by s;
STRING | ALL_FOUND
:----- | :--------
CH     | yes      
CH,GB  | yes      
ES     | no       
ES,CH  | no       
FR     | no       
GB     | yes      
GB,CH  | yes      
GB,ES  | no       

db<>fiddle here

¢好甜 2025-02-03 03:00:25

如果静态表中有少数值,那么最简单的方法可能不是将值与函数拆分,而是使用静态表中的所有值组合,使用:

SELECT SUBSTR(SYS_CONNECT_BY_PATH(value, ','), 2) AS combination
FROM   static_table
CONNECT BY NOCYCLE PRIOR value != value;

对于示例数据:

CREATE TABLE static_table(value) AS
SELECT 'GB' FROM DUAL UNION ALL
SELECT 'CH' FROM DUAL;

输出:输出:

组合
GB
GB,CH
ch
CH,GB

,然后您可以将简单的案例表达到字符串输出到组合:

SELECT function_value,
       CASE
       WHEN function_value IN (SELECT SUBSTR(SYS_CONNECT_BY_PATH(value, ','), 2)
                               FROM   static_table
                               CONNECT BY NOCYCLE PRIOR value != value)
       THEN 'false'
       ELSE 'true'
       END AS not_matched
FROM   string_from_function;

对于示例数据:输出:

CREATE TABLE string_from_function(function_value) AS
SELECT 'GB' FROM DUAL UNION ALL
SELECT 'CH' FROM DUAL UNION ALL
SELECT 'GB,CH' FROM DUAL UNION ALL
SELECT 'CH,GB' FROM DUAL UNION ALL
SELECT 'GB,FR' FROM DUAL UNION ALL
SELECT 'FR,ES' FROM DUAL UNION ALL
SELECT 'ES,CH' FROM DUAL UNION ALL
SELECT 'CH,GB,ES' FROM DUAL;

输出:

function_value not_matched
gb false
ch false
gb,ch false
ch,gb false
gb,fr true
fr,es true
es,ch true
ch,gb,es true

db&lt;&gt; fiddle here

If you have a small number of values in the static table then the simplest method may not be to split the values from the function but to generate all combinations of values from the static table using:

SELECT SUBSTR(SYS_CONNECT_BY_PATH(value, ','), 2) AS combination
FROM   static_table
CONNECT BY NOCYCLE PRIOR value != value;

Which, for the sample data:

CREATE TABLE static_table(value) AS
SELECT 'GB' FROM DUAL UNION ALL
SELECT 'CH' FROM DUAL;

Outputs:

COMBINATION
GB
GB,CH
CH
CH,GB

Then you can use a simple CASE expression to your string output to the combinations:

SELECT function_value,
       CASE
       WHEN function_value IN (SELECT SUBSTR(SYS_CONNECT_BY_PATH(value, ','), 2)
                               FROM   static_table
                               CONNECT BY NOCYCLE PRIOR value != value)
       THEN 'false'
       ELSE 'true'
       END AS not_matched
FROM   string_from_function;

Which, for the sample data:

CREATE TABLE string_from_function(function_value) AS
SELECT 'GB' FROM DUAL UNION ALL
SELECT 'CH' FROM DUAL UNION ALL
SELECT 'GB,CH' FROM DUAL UNION ALL
SELECT 'CH,GB' FROM DUAL UNION ALL
SELECT 'GB,FR' FROM DUAL UNION ALL
SELECT 'FR,ES' FROM DUAL UNION ALL
SELECT 'ES,CH' FROM DUAL UNION ALL
SELECT 'CH,GB,ES' FROM DUAL;

Outputs:

FUNCTION_VALUE NOT_MATCHED
GB false
CH false
GB,CH false
CH,GB false
GB,FR true
FR,ES true
ES,CH true
CH,GB,ES true

db<>fiddle here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文