逗号分隔值循环使用硬编码值但不使用参数值

Posted

技术标签:

【中文标题】逗号分隔值循环使用硬编码值但不使用参数值【英文标题】:comma separated value to loop working with Hardcoded value but not with parameter value 【发布时间】:2019-06-17 07:01:31 【问题描述】:

我的主要问题是:我想将逗号分隔的字符串传递给 oracle 9i 存储的 proc 并在其中,我想遍历它并在插入语句中使用每个值。 Oracle 9i 以上版本提供了一些内部函数,如 regex_susbstr 可用于实现此功能,但使用 oracle 9i 我能够找到我粘贴在下面的一个代码。 当我在存储过程中使用逗号分隔字符串的硬编码值时,这很好用,但是当通过存储过程的输入参数传递它时,它认为该字符串是单个值,只需循环一次并在列中插入完整的字符串

CREATE OR REPLACE PROCEDURE SP_INSERTDOCUMENTDETAILS_BD
(
    BatchId  IN NUMBER,
    strDocumentIds IN varchar2
)
IS
  type table_varchar  is table of varchar2(32767);
  var_table_varchar  table_varchar;
begin
  var_table_varchar  := table_varchar(strDocumentIds);
  var_table_varchar  := table_varchar('004416979','004416987','004416988','004416989');

  for elem in 1 .. var_table_varchar.count loop
      Insert into documentdetails(DocumentID,BatchID,DocumentSRCGUID,Name,documentType,ExtractionStatus,InjectionStatus) 
      values(DocumentID_SEQ.NEXTVAL,BatchId,var_table_varchar(elem),'','',1,1);
  end loop;
end;
/
show errors;

【问题讨论】:

您已经在问题中发现了问题:“它认为该字符串是单个值”。您的输入字符串来自哪里,该来源能否提供值列表而不是单个字符串值? 它来自 .net 代码,我无法将集合作为 Oracle 参数从 .net 传递。但无论如何我从鲍勃那里得到了下面的解决方案。谢谢亚历克斯:) 【参考方案1】:

您的table_varchar 类型不会神奇地将包含逗号分隔值的字符串解析为单独的子字符串。你仍然必须这样做。

这是一个很好的小函数,可以为您进行解析。它使用内置的系统类型DBMS_SQL.VARCHAR2A而不是你的表类型,但结果是相似的:

FUNCTION EXTRACT_TOKENS(p_string     IN VARCHAR2,
                        p_separators IN VARCHAR2)
  RETURN DBMS_SQL.VARCHAR2A
IS
  arrTokens DBMS_SQL.VARCHAR2A;
BEGIN
  WITH sel_string AS 
      (SELECT p_string AS fullstring FROM DUAL)
  SELECT SUBSTR(fullstring, beg + 1, end_p - beg - 1) AS token
    BULK COLLECT INTO arrTokens
    FROM (SELECT beg, LEAD(beg) OVER (ORDER BY beg) AS end_p, fullstring
            FROM (SELECT beg, fullstring
                    FROM (SELECT LEVEL beg, fullstring
                            FROM sel_string
                            CONNECT BY LEVEL <= LENGTH(fullstring))
                    WHERE INSTR(p_separators, SUBSTR(fullstring, beg, 1)) > 0
                  UNION ALL
                    SELECT 0, fullstring FROM sel_string
                  UNION ALL
                    SELECT LENGTH(fullstring) + 1, fullstring FROM sel_string))
    WHERE end_p IS NOT NULL AND
          end_p > beg + 1;

  RETURN arrTokens;
END EXTRACT_TOKENS;

您可以通过将程序更改为:

CREATE OR REPLACE PROCEDURE SP_INSERTDOCUMENTDETAILS_BD
(
    BatchId  IN NUMBER,
    strDocumentIds IN varchar2
)
IS
  var_table_varchar  DBMS_SQL.VARCHAR2A ;
begin
  var_table_varchar := EXTRACT_TOKENS(strDocumentIds, ',');

  for elem in 1 .. var_table_varchar.count loop
      Insert into documentdetails
        (DocumentID, BatchID, DocumentSRCGUID, Name, documentType, ExtractionStatus, InjectionStatus) 
      values
        (DocumentID_SEQ.NEXTVAL, BatchId, var_table_varchar(elem), ',' , 1, 1);
  end loop;
end SP_INSERTDOCUMENTDETAILS_BD;

请注意,这仍然不起作用,因为您的 INSERT 语句中的字段列表有七个已命名的字段,而 VALUES 子句仅包含六个值,但我相信您可以解决这个问题。

【讨论】:

谢谢鲍勃,它工作得很好。非常感谢您对此的帮助。从过去 4 天开始,我一直被困在这个问题上,并且无法在谷歌上找到与此问题相关的任何内容。 但是我遇到了另一个问题,我在 strDocumentIds 输入参数中传递了一个长字符串,它给出了异常:ORA-01460:未实现或不合理的转换请求。当我传递大约 1200 个字符的字符串长度时,它工作正常,但是当我尝试下一批 6000 个字符时,它给出了该错误。我也必须使用这个 SP 来处理大约 49000 个字符的长度。有什么建议吗? Oracle 中的字符串限制为 4000 字节,这意味着 4000 个字符或更少,具体取决于数据库中使用的字符集。如果您需要使用更长的字符串,则必须使用 CLOB,我对此没有经验。 谢谢 Bob,我在您的函数 EXTRACT_TOKENS 中将 p_string 从 Varchar2 替换为 CLOB,并且对我的存储过程 SP_INSERTDOCUMENTDETAILS_BD 中的 strDocumentIds 也做了同样的事情。现在它需要 32513 字符串长度,与之前接受的相比非常大。

以上是关于逗号分隔值循环使用硬编码值但不使用参数值的主要内容,如果未能解决你的问题,请参考以下文章

将逗号分隔的值作为搜索参数附加到 url [重复]

Spring实战bean装配的运行时值注入——属性占位符和SpEL

Django % include % 标签显示硬编码字符串但不可变

Oracle SQL - 动态案例语句

用参数值替换硬编码的问题

循环通过逗号分隔的 shell 变量