oracle 函数:select 不同的值从逗号分隔的字符串中计数

oracle function for: select distinct values count from comma separated string

我需要一个 Oracle (11) 函数来处理这个问题。 我需要从逗号分隔的字符串中计算不同的值。

例如逗号分隔的字符串: 'Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text'

结果必须是 = 6

因为

  1. 洛伦
  2. 假和
  3. 简直
  4. 虚拟
  5. 文本

我想这样用

select fn_dist_count_values_in_list_arr('Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text') from dual;

任何人都可以帮助编写这个 ("fn_dist_count_values_in_list_arr") oracle 函数吗?

    CREATE OR REPLACE FUNCTION DIST_COUNT_VALUES_IN_STR_ARR
    (STR_ARR IN VARCHAR2)
    RETURN NUMBER
    AS
    DIST_COUNT NUMBER(38);
    BEGIN
        SELECT COUNT(DISTINCT COL1) 
        INTO DIST_COUNT FROM (
            SELECT REGEXP_SUBSTR(STR_ARR,'[^,]+', 1, LEVEL) COL1 
            FROM DUAL
            CONNECT BY LEVEL <= REGEXP_COUNT(STR_ARR, ',') + 1
        );
        RETURN DIST_COUNT;
    END;

这对我有用。内部查询通过在逗号字符上使用正则表达式将元素分隔成行。我不得不重命名你的函数,因为我达到了我的 Oracle 版本的对象名称的最大长度限制。

您不需要从 SQL 到 PL/SQL 函数的上下文切换,并且可以在 SQL:

中完成所有操作
SELECT ( SELECT COUNT( DISTINCT CAST(column_value AS VARCHAR2(20)) )
         FROM   XMLTABLE( ('"'||REPLACE(value,',','","')||'"') ) )
         AS num_distinct_values
FROM   table_name

其中,对于示例数据:

CREATE TABLE table_name ( value ) AS
SELECT 'Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text' FROM DUAL;

输出:

| NUM_DISTINCT_VALUES |
| ------------------: |
|                   6 |

如果你想要一个纯 PL/SQL 函数(这样你就没有多个上下文切换)那么:

CREATE FUNCTION fn_dist_count_values_in_list_arr (
  list_value IN VARCHAR2
) RETURN NUMBER DETERMINISTIC
IS
  TYPE t_words IS TABLE OF NUMBER(1,0) INDEX BY VARCHAR2(200);
  v_words t_words;
  v_start PLS_INTEGER := 1;
  v_end   PLS_INTEGER;
BEGIN
  IF list_value IS NULL THEN
    RETURN 0;
  END IF;
  LOOP
    v_end := INSTR( list_value, ',', v_start );
    EXIT WHEN v_end = 0;
    v_words(SUBSTR(list_value, v_start, v_end - v_start ) ) := 1;
    v_start := v_end + 1;
  END LOOP;
  v_words(SUBSTR(list_value,v_start)) := 1;
  RETURN v_words.COUNT;
END;
/

然后:

SELECT fn_dist_count_values_in_list_arr( value )
FROM   table_name

输出:

| FN_DIST_COUNT_VALUES_IN_LIST_ARR(VALUE) |
| --------------------------------------: |
|                                       6 |

db<>fiddle here

另一种方法是使用分层查询将逗号分隔值拆分为一组行(带子句)和运行一个简单的sql查询

with str_parsed as (SELECT REGEXP_SUBSTR('Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text', '[^,]+', 1, LEVEL) val
                    FROM dual
                    CONNECT BY REGEXP_SUBSTR('Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text,Lorem,Ipsum,is,simply,dummy,text', '[^,]+', 1, LEVEL) IS NOT NULL)
select count(distinct val) from str_parsed