Oracle SQL:从IN子句中检索不存在的值

时间:2014-10-15 17:48:22

标签: sql oracle

有以下查询:

select table_name
from user_tables
where table_name in ('A','B','C','D','E','F');

假设只存在user_tables记录B,C和F,我想检索不存在的值A,D和E.这是一个简单的例子,在现实世界中列表可能很大。

5 个答案:

答案 0 :(得分:4)

生成假行的好方法是使用标准集合,例如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

答案 1 :(得分:2)

如果你有表1中要检查的所有表的列表,那么你可以使用NOT EXISTS子句

select name
from Table1 T1
where not exists ( select 1 from  
                   user_tables U
                   where T1.name = U.table_name)

答案 2 :(得分:2)

唯一的方法是通过将NOT EXISTS字符串转换为值表来使用IN clause。(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);

答案 3 :(得分:0)

你做不到。必须至少将这些值输入临时表以执行所需的操作。 Oracle的IN子句列表也不能很大(即不超过1000个值)。

答案 4 :(得分:0)

您是否仅限于以逗号分隔列表的形式接收这些值?

  1. 不是使用源值创建逗号分隔列表,而是填充数组(或表)。
  2. 将数组传递给pl / sql过程(或从表中拉出光标)。
  3. 循环遍历数组(游标)并使用动态cusror从user_tables中选择count(table_name),其中table_name = value_pulled。
  4. 当count(table_name)= 0时插入表B.
  5. 然后您可以从表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 
    
  6. 如果这不是一次性的话,那么手头有这个过程会很方便。