PL/SQL - 如何在 IN 子句中使用数组
Posted
技术标签:
【中文标题】PL/SQL - 如何在 IN 子句中使用数组【英文标题】:PL/SQL - How to use an array in an IN Clause 【发布时间】:2013-09-24 18:26:01 【问题描述】:我正在尝试在 IN 子句中将一组输入值用于我的过程,作为游标 where 子句的一部分。我知道以前有人问过这个问题,但是我还没有看到如何使我的语法正确编译。
在封装规范中,类型是
TYPE t_brth_dt IS TABLE OF sourceTable.stdt_brth_dt%TYPE INDEX BY PLS_INTEGER;
sourceTable.std_brth_dt
是表中的日期列。
我的光标的简化版在包体中是-
cursor DataCursor_Sort( p_brth_dt in t_brth_dt) is
SELECT *
FROM sourceTable
WHERE a.brth_dt IN (select column_value
from table(p_brth_dt))
当我尝试编译它时,我收到以下错误。
[1]:(错误): PLS-00382: 表达式类型错误 [2]:(错误):PL/SQL:ORA-22905:无法访问非嵌套表项中的行
我知道这看起来与其他问题相似,但我不明白语法错误是什么。
【问题讨论】:
尝试 p_brth_dt in (select sourceTable.std_brth_dt from t_brth_dt) passing an array into oracle sql and using the array 的可能重复项 可悲的是(显然)企业级过程语言无法处理数组的简单概念。 使用 Clever Idea Widgetry 建议的流水线函数效果很好。我唯一需要添加的是一些代码来忽略异常 no_data_needed,因为我的程序抛出错误 ORA-06548。当 no_data_needed 然后为 null 时出现异常; 【参考方案1】:为了在查询的from
子句中使用定义为嵌套表或关联数组的集合,正如@Alex Poole 正确指出的那样,您应该创建一个模式级别(SQL)类型或使用一个,当您打算使用日期列表时,您可以通过 ODCIConst
包 - odcidatelist
使用它。例如,您的光标定义可能如下所示:
cursor DataCursor_Sort(p_brth_dt in sys.odcidatelist) is
select *
from sourceTable
where a.brth_dt IN (select column_value
from table(p_brth_dt))
或
cursor DataCursor_Sort(p_brth_dt in sys.odcidatelist) is
select s.*
from sourceTable s
join table(p_brth_dt) t
on (s.brth_dt = t.column_value)
注意:在执行日期比较时,您应该考虑日期的时间部分。如果您只想比较日期部分,使用trunc()
函数去除时间部分可能会很有用。
【讨论】:
第二个语句中的错字 - t.brth_dt = s.column_value 应该是 s.brth_dt = t.column_value。 @0xdb 谢谢。【参考方案2】:可以在IN
子句中间接使用 PL/SQL 定义的嵌套表类型(相对于 SQL 定义的嵌套表类型) PL/SQL 包中的SELECT
语句。您必须使用PIPELINED
函数作为中介。写起来感觉有点聪明,但我不相信它的基本用途。
CREATE OR REPLACE PACKAGE so18989249 IS
TYPE date_plsql_nested_table_type IS TABLE OF DATE;
dates date_plsql_nested_table_type;
FUNCTION dates_pipelined RETURN date_plsql_nested_table_type PIPELINED;
PROCEDURE use_plsql_nested_table_type;
END so18989249;
/
CREATE OR REPLACE PACKAGE BODY so18989249 IS
FUNCTION dates_pipelined RETURN date_plsql_nested_table_type
PIPELINED IS
BEGIN
IF (dates.count > 0)
THEN
FOR i IN dates.first .. dates.last
LOOP
IF (dates.exists(i))
THEN
PIPE ROW(dates(i));
END IF;
END LOOP;
END IF;
END;
PROCEDURE use_plsql_nested_table_type IS
BEGIN
dates := NEW date_plsql_nested_table_type();
-- tweak these values as you see fit to produce the dbms_output results you want
dates.extend(5);
dates(1) := DATE '2013-12-25';
dates(2) := DATE '2013-01-01';
dates(3) := DATE '2013-07-01';
dates(4) := DATE '2013-09-03';
dates(5) := DATE '2008-11-18';
FOR i IN (SELECT o.owner,
o.object_name,
o.object_type,
to_char(o.last_ddl_time, 'YYYY-MM-DD') AS last_ddl
FROM all_objects o
WHERE trunc(o.last_ddl_time) IN
(SELECT column_value FROM TABLE(dates_pipelined))
--uses pipeline function which uses pl/sql-defined nested table
)
LOOP
dbms_output.put_line('"' || i.owner || '"."' || i.object_name || '" ("' || i.object_type || ') on ' || i.last_ddl);
END LOOP;
END;
END so18989249;
/
begin so18989249.use_plsql_nested_table_type; end;
/
【讨论】:
【参考方案3】:类型必须在 SQL 级别创建,而不是在包中。 SQL 查询不知道如何使用 PL/SQL 中定义的任何类型。所以你必须这样做:
CREATE OR REPLACE TYPE t_brth_dt IS TABLE OF date;
/
... 并从您的包规范中删除该类型。 (或者至少给它们起不同的名称,并且它们在使用中不能互换)。因为它是在 SQL 级别,所以很遗憾,您也不能在声明中使用sourceTable.stdt_brth_dt%TYPE
。
【讨论】:
以上是关于PL/SQL - 如何在 IN 子句中使用数组的主要内容,如果未能解决你的问题,请参考以下文章
如何转换逗号分隔的 varchar 以用于 pl/sql 中的“IN”子句?
如何在选择语句的“NOT IN”子句中使用逗号分隔的字符串列表作为 pl/sql 存储的函数参数
PL/SQL - 在 Where In 子句中使用“列表”变量