我对Oracle PL / SQL有疑问。
在一个过程中,相同的嵌入式SELECT语句与查询中的WHERE子句重复使用:
...
where start_year in (
SELECT MB_START FROM MEMBERS
)
...
该过程中嵌入在WHERE子句中的实际SELECT语句是 更加详尽,并由“ SELECT MB_START FROM MEMBERS”替换为 我的问题在这里更容易理解。这就是为什么我要问 问题:
在许多WHERE子句中重复相同的子查询很麻烦, 阻塞的代码难以阅读,并且可能浪费服务器 资源。有没有一种方法可以将嵌入式子查询返回的内容保存在变量中,例如:
DECLARE
start_years <type_for_IN_operator>;
BEGIN
...
select mb_start into start_years from members;
...
WHERE start_year in (start_years)
...
END;
/
我进行了艰苦的搜索,未能发现Oracle是否支持将值保存到IN运算符使用的变量中。如果支持,type_for_IN_operator的数据类型是什么?
谢谢大家对问题的回答。
之所以问这个问题,是因为我观察到IN运算符接受一组不同形式的值,例如
因此,我认为它们可能有一些共同点,例如我不知道的数据类型。如果存在这种数据类型,查询代码可能会变得越来越简单。
APC的想法吸引了我,特别是纯sql和虚拟表可重用。我尝试过,但是遇到了问题。
脚本最初是:
select t.col1, t.col2, ... from
(
select ...
from ...
where start_year in (<that subquery>)
union
select ...
from ...
where start_year in (<that subquery>)
union
...
) t
join ...
...
现在使用虚拟表并替换第一个原始子查询:
with sqf as (
SELECT MB_START FROM MEMBERS
)
select t.col1, t.col2, ... from
(
select ...
from ...
where start_year in (select * from sqf)
union
select ...
from ...
where start_year in (<that subquery>)
union
...
) t
join ...
...
碰巧查询完成的速度甚至比原始代码快一点。但是,当第二个
有什么建议吗?
答案 0 :(得分:3)
oracle中的任何查询都会根据选择的列返回一个游标。您是否在IN条件下调用它都没关系。
但是,如果要保存子查询的结果以在多个查询中重复使用,则可以创建TYPE并在其中批量收集值。
CREATE TYPE MEMBER_TAB_TYPE AS TABLE OF DATE;
DECLARE
MB_START_TABLE MEMBER_TAB_TYPE;
BEGIN
SELECT MB_START BULK COLLECT INTO MB_START_TABLE FROM MEMBERS;
....
WHERE START_YEAR IN (SELECT COLUMN_VALUE FROM TABLE(MB_START_TABLE));
....
END;
您可以在程序中随意使用MB_START_TABLE多次,而无需实际查询MEMBERS表,因为“从表中选择COLUMN_VALUE(MB_START_TABLE)” 将始终获取本地存储的值。>
答案 1 :(得分:2)
有没有一种方法可以将嵌入式子查询返回的内容保存在变量中
排序。这是WITH子句,也称为子查询分解。自9i以来,它一直是Oracle SQL功能的一部分。
使用您发布的示例:
with sqf as (
SELECT MB_START FROM MEMBERS
)
select * from your_table
where col1 in ( select * from sqf )
and col2 in ( select * from sqf )
and col3 not in ( select * from sqf )
/
WITH子句执行一次,并在后续引用中重用。我们可以在FROM子句中使用它,包括其他子查询因子的FROM子句。
这样做的明显好处是它是纯SQL,因此不需要PL / SQL,变量或类型声明。有一个陷阱,那就是Oracle可能会选择实现大型结果集,这意味着要写入磁盘或从磁盘读取数据。
答案 2 :(得分:0)
IN
从逻辑上讲是一系列=
表达式,它们之间有OR
,因此实际上您是在要求相等性测试的数据类型。
在您的示例中,看起来mb_start
是date
,因此,如果您还没有一个独立的table of date
集合类型,则需要定义一个独立的集合类型然后在table()
或member of
表达式中使用。
答案 3 :(得分:0)
两种解决方案都可以,但是要付出一定的代价。
原始代码需要23秒才能完成查询。分解式子查询的40秒。使用集合的52秒(从表(集合)中选择列值)。另外,必须对原始代码进行一些修改才能使这两种替代方法起作用。
原始查询工作正常,这是它的框架:
select col1, col2 from
(
SELECT x.col_a, x.col_b, ... from ...
where
(
( conditions A AND condition B)
OR
( condition C AND condition D AND condition E)
)
AND
condition F
UNION
select B
UNION
select C
) x
JOIN ...
JOIN ...
...
但是分解后的子查询和集合选择都被阻塞,永远运行而不会产生结果,除非将第一个UNION运算符之前的SELECT拆分为两个,所以还有一个UNION:
select col1, col2 from
(
SELECT x.col_a, x.col_b, ... from ...
where
conditions A AND condition B AND condition F
UNION
SELECT col_a, col_b, ... from ...
where
condition C AND condition D AND condition E AND condition F
UNION
select B
UNION
select C
) x
JOIN ...
JOIN ...
...
因此,至少在我的情况下,在旧代码和新选择之间,这是性能和整洁代码之间的权衡。
(我尝试单击复选标记将这两种替代方法都标记为解决方案,但是stackoverflow不允许并且在这两种方法之间进行切换。很抱歉,谢谢大家的帮助。)