【问题标题】:Split string and iterate for each value in a stored procedure拆分字符串并迭代存储过程中的每个值
【发布时间】:2015-06-15 22:09:24
【问题描述】:

我在 Oracle 中有一个要求,我必须将逗号分隔的国家代码字符串传递给 Oracle 存储过程。

在存储过程中,我想用逗号分割字符串并为每个国家代码进行迭代。

我想要一个类似如下的SP:

PROCEDURE Get_Query
(
  v_company IN VARCHAR2,

) IS
sqlstr VARCHAR2(32767);
BEGIN
/*
split the v_company on comma (e.g. IN,US,...etc)
iterate for each country code  

*/
END;

【问题讨论】:

  • 这是一个非常普遍的请求(尝试谷歌搜索,“stackoverflow oracle parse csv string”)。不乏这方面的文档。

标签: oracle stored-procedures oracle11g tokenize


【解决方案1】:

您可以使用DBMS_UTILITY.COMMA_TO_TABLE

DBMS_UTILITY 包提供了各种实用子程序。 COMMA_TO_TABLE 过程就是这样一个有用的实用程序,它将以逗号分隔的名称列表转换为 PL/SQL 名称表。

例如,

SQL> set serveroutput on;
SQL> DECLARE
  2    l_tablen BINARY_INTEGER;
  3    l_tab DBMS_UTILITY.uncl_array;
  4    CURSOR cur
  5    IS
  6      SELECT 'word1, word2, word3, word4, word5, word6' val FROM dual;
  7    rec cur%rowtype;
  8  BEGIN
  9    OPEN cur;
 10    LOOP
 11      FETCH cur INTO rec;
 12      EXIT
 13    WHEN cur%notfound;
 14      DBMS_UTILITY.comma_to_table (
 15      list => rec.val, tablen => l_tablen, tab => l_tab);
 16      FOR i IN 1 .. l_tablen
 17      LOOP
 18        DBMS_OUTPUT.put_line(i || ' : ' || trim(l_tab(i)));
 19      END LOOP;
 20    END LOOP;
 21    CLOSE cur;
 22  END;
 23  /
1 : word1
2 : word2
3 : word3
4 : word4
5 : word5
6 : word6

PL/SQL procedure successfully completed.

SQL>

更新正如@ruudvan 指出的那样,使用COMMA_TO_TABLE 有一些限制,如果您将关键字 用作分隔字符串(如IS,AS 等),它将无法工作.

要克服COMMA_TO_TABLE的限制,还有很多其他方法可以做到,见How to split comma delimited string into rows in Oracle

例如,您可以使用正则表达式,如下所示:

测试用例

SQL> CREATE OR REPLACE
  2  PROCEDURE Get_Query(
  3      v_company IN VARCHAR2 )
  4  IS
  5  BEGIN
  6    
  7    FOR i IN
  8    (SELECT level,
  9      trim(regexp_substr(v_company, '[^,]+', 1, LEVEL)) str
 10    FROM dual
 11      CONNECT BY regexp_substr(v_company , '[^,]+', 1, LEVEL) IS NOT NULL
 12    )
 13    LOOP
 14      -- do something
 15      dbms_output.put_line('Company code no.'||i.level||' = '||i.str);
 16    END LOOP;
 17  END;
 18  /

Procedure created.

SQL> sho err
No errors.

让我们检查一下:

SQL> set serveroutput on
SQL> EXEC get_query('COMP1,COMP2,COMP3,COMP4');
Company code no.1 = COMP1
Company code no.2 = COMP2
Company code no.3 = COMP3
Company code no.4 = COMP4

PL/SQL procedure successfully completed.

SQL>

【讨论】:

  • 我认为你应该把 regexp_substr 方法放在这里而不是 comma_to_table。每当您推荐某人 comma_to_table 时,我觉得您也应该告知他们它的局限性。 Tom Kyte 总结了here。即使在这个国家/地区代码的特定示例中,它也可能不会给您正确的结果,因为 OP 可能具有像“AS”和“IS”这样的国家/地区代码,它们是保留字,而 comma_to_table 将无法处理它们。
  • @ruudvan 当然,内置包有限制。这就是我提供我的文章链接的原因,我在该文章中演示了各种方法。我会让 OP 回来询问他是否需要更多帮助。如果我必须深入细节,在这里提供每一个微细节,那就像写一本书一样。无论如何,谢谢你的评论。如果他有进一步的担忧回来,我将非常乐意帮助 OP。
  • 你有足够的代表知道 StackOverflow 是如何工作的。我们应该在此站点 上提供有效的答案。提供低于标准的解决方案 - 正如@ruudvan 指出的那样,COMMA_TO_TABLE() 就是这样 - 加上指向您博客的链接还不够好。
  • @APC 和 ruudvan,伙计们。添加了完整的工作解决方案。谢谢你推我;-)
【解决方案2】:

正则表达式的这种使用将输入字符串转换为标记流,可以像任何其他 SELECT 语句的结果集一样进行处理。

PROCEDURE Get_Query
(
  v_company IN VARCHAR2,

) IS
    sqlstr VARCHAR2(32767);
BEGIN

    for rec in (select distinct regexp_substr(v_company, '[^,]+', 1, level) as ctry
    from dual
    connect by level <= regexp_count (v_company, '[,]')  +1
   loop
        do_something ( rec.ctry );

    end loop;
END;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-05
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多