如何在选择语句的“NOT IN”子句中使用逗号分隔的字符串列表作为 pl/sql 存储的函数参数
Posted
技术标签:
【中文标题】如何在选择语句的“NOT IN”子句中使用逗号分隔的字符串列表作为 pl/sql 存储的函数参数【英文标题】:How to use a comma-separated list of strings as pl/sql stored function parameter inside a "NOT IN" clause of a select statement 【发布时间】:2013-01-04 08:48:17 【问题描述】:我有一个逗号分隔的字符串列表(来自用户输入),我想将此列表用作嵌套 sql 块中的 pl/sql 存储函数中的参数,使用“not in where 子句” .
我找不到一种优雅的方式让它工作......
这就是我的想法:
CREATE TABLE example ( somevalue VARCHAR(36) NOT NULL);
--
INSERT INTO example VALUES ('value1');
INSERT INTO example VALUES ('value2');
INSERT INTO example VALUES ('value3');
--
SELECT * FROM example;
--
CREATE OR REPLACE
FUNCTION resultmaker(
ignoreList IN VARCHAR2)
RETURN VARCHAR2
IS
result VARCHAR2(4000);
BEGIN
result := 'Here is my calculated result, using ignorelist=' || ignoreList || ':' || CHR(10);
FOR rec IN
(SELECT DISTINCT somevalue
FROM example
WHERE somevalue NOT IN resultmaker.ignoreList -- here's my issue, the NOT IN clause using the parameter value
)
LOOP
result := result || 'not in ignorelist: ' || rec.somevalue || CHR(10);
END LOOP;
result := result || '.' || CHR(10);
--
RETURN result;
END resultmaker;
/
--
-- simulate function call with user input 'value2, value3'
SELECT resultmaker('value2, value3') FROM dual; -- doesn't work
--
DROP TABLE example;
DROP FUNCTION resultmaker;
【问题讨论】:
How to convert varchar to numbers in sql developer的可能重复 谢谢,类似的问题!我的基本问题是不了解动态 sql。 【参考方案1】:只需传递'"value2","value3"'
之类的参数,并让您的语句将双引号替换为REPLACE(@Param1,'"','''')
之类的单引号。
函数调用:SELECT * FROM Function1('"value2","value3"')
内部函数:NOT IN REPLACE(@Param1,'"','''')
【讨论】:
【参考方案2】:在任何情况下,您都应该解析该输入。由于 PL/SQL 中没有内置的字符串标记器(至少我找不到它)你可能想看看这些选项,
http://blog.tanelpoder.com/2007/06/20/my-version-of-sql-string-to-table-tokenizer/
Does PL/SQL have an equivalent StringTokenizer to Java's?
解析字符串后,您可以创建一个新字符串,如:
not_in_statement varchar2(1000);
CURSOR c1 IS select token from tokenized_strings_table;
BEGIN
not_in_statement := '('
FOR rec IN c1 LOOP
not_in_statement := not_in_statement || '''||rec.token||'''||','
END LOOP
not_in_statement := not_in_statement||')'
END
SELECT DISTINCT somevalue
FROM example
WHERE somevalue NOT IN not_in_statement
你可能需要动态SQL,我没时间尝试。
【讨论】:
感谢坎布拉克的回答!将我指向“动态 sql”是关键。我可以控制 pl/sql 之外的逗号分隔列表的表示,所以使用动态 sql 的解决方案对我来说很好。 我会尽快发布我的新解决方案作为答案(我目前没有足够的声誉,必须等待 8 小时)【参考方案3】:这是我对上述原始问题使用动态 sql 的解决方案:
CREATE TABLE example ( somevalue VARCHAR(36) NOT NULL);
--
INSERT INTO example VALUES ('value1');
INSERT INTO example VALUES ('value2');
INSERT INTO example VALUES ('value3');
--
SELECT * FROM example;
--
CREATE OR REPLACE
FUNCTION resultmaker(
ignoreList IN VARCHAR2)
RETURN VARCHAR2
IS
result VARCHAR2(4000);
example_cursor sys_refcursor;
rec example.somevalue%type;
BEGIN
result := 'Here is my calculated result, using ignorelist=' || ignoreList || ':' || CHR(10);
OPEN example_cursor FOR ( 'SELECT DISTINCT somevalue FROM example WHERE somevalue NOT IN (' || ignoreList || ')' );
FETCH example_cursor INTO rec;
WHILE example_cursor%found
LOOP
result := result || 'not in ignorelist: ' || rec || CHR(10);
FETCH example_cursor INTO rec;
END LOOP;
CLOSE example_cursor;
result := result || '.' || CHR(10);
--
RETURN result;
END resultmaker;
/
--
-- simulate function call with user input 'value2', 'value3'
SELECT resultmaker('''value2'', ''value3''') FROM dual;
--
DROP TABLE example;
DROP FUNCTION resultmaker;
【讨论】:
【参考方案4】:经典且可能正确的解决方案是使用 PL/SQL 表将其作为参数传递...
【讨论】:
【参考方案5】:在 asktom.oracle.com 上有一些很好的解决方案,关于获取一串值并为它们动态创建一个 IN 子句:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:210612357425
【讨论】:
以上是关于如何在选择语句的“NOT IN”子句中使用逗号分隔的字符串列表作为 pl/sql 存储的函数参数的主要内容,如果未能解决你的问题,请参考以下文章