【发布时间】:2014-10-15 17:48:21
【问题描述】:
有以下查询:
select table_name
from user_tables
where table_name in ('A','B','C','D','E','F');
假设只有 user_tables 记录 B、C 和 F 存在,我想检索不存在的值 A、D 和 E。这是一个简单的例子,在现实世界中列表可能很大。
【问题讨论】:
有以下查询:
select table_name
from user_tables
where table_name in ('A','B','C','D','E','F');
假设只有 user_tables 记录 B、C 和 F 存在,我想检索不存在的值 A、D 和 E。这是一个简单的例子,在现实世界中列表可能很大。
【问题讨论】:
生成假行的好方法是使用标准集合,例如sys.odcivarchar2list:
select
tables_to_check.table_name,
case when user_tables.table_name is null then 'No' else 'Yes'end table_exists
from
(
select column_value table_name
from table(sys.odcivarchar2list('does not exist', 'TEST1'))
) tables_to_check
left join user_tables
on tables_to_check.table_name = user_tables.table_name
order by tables_to_check.table_name;
TABLE_NAME TABLE_EXISTS
---------- ------------
TEST1 Yes
does not exist No
【讨论】:
如果您在 Table1 中有要检查的所有这些表的列表,那么您可以使用 NOT EXISTS 子句
select name
from Table1 T1
where not exists ( select 1 from
user_tables U
where T1.name = U.table_name)
【讨论】:
唯一的方法是将IN clause字符串转换为值表来使用NOT EXISTS。(CTE)
虽然这不是一个干净的解决方案。因为IN子句表达式的最大长度将是4000,包括逗号..
WITH MY_STRING(str) AS
(
SELECT q'#'A','B','C','D','E','F'#' FROM DUAL
),
VALUES_TABLE AS
(
SELECT TRIM(BOTH '''' FROM REGEXP_SUBSTR(str,'[^,]+',1,level)) as table_name FROM MY_STRING
CONNECT BY LEVEL <= REGEXP_COUNT(str,',')
)
SELECT ME.* FROM VALUES_TABLE ME
WHERE NOT EXISTS
(SELECT 'X' FROM user_tables u
WHERE u.table_name = ME.table_name);
【讨论】:
你不能。至少必须将这些值输入到临时表中才能执行所需的操作。此外,Oracle 的 IN 子句列表不能很大(即不超过 1000 个值)。
【讨论】:
您是否仅限于以逗号分隔列表的形式接收这些值?
然后你可以从表B中选择所有
select * from tab1;
------------------
A
B
C
D
E
F
Create or replace procedure proc1 as
cursor c is select col1 from tab1;
r tab1.col1%type;
i number;
begin
open c;
loop
fetch c into r;
exit when c%notfound;
select count(tname) into i from tab where tname = r;
if i = 0 then
v_sql := 'insert into tab2 values ('''||r||''');
execute immediate v_sql;
commit;
end if;
end loop;
close c;
end proc1;
select * from tab2;
------------------
A
D
E
如果这不是一次性的,那么手头有这个过程会很方便。
【讨论】: