选择记录不存在的位置

时间:2016-06-03 11:18:33

标签: sql oracle select

我正在尝试使用oracle 11g。我有一个要求,我想从列表中获取那些在表中不存在的id。

例如:

SELECT * FROM STOCK
where  item_id in ('1','2'); // Return those records where result is null

我的意思是如果db中没有item_id '1',那么查询应该返回1

我怎样才能做到这一点?

4 个答案:

答案 0 :(得分:2)

您需要将值存储在某种"表"中。然后,您可以使用left joinnot exists或类似内容:

with ids as (
      select 1 as id from dual union all
      select 2 from dual
     )
select ids.id
from ids
where not exists (select 1 from stock s where s.item_id = ids.id);

答案 1 :(得分:2)

您可以将LEFT JOIN用于包含要搜索的值的内联表:

SELECT t1.val
FROM (
   SELECT '1' val UNION ALL SELECT '2'
) t1
LEFT JOIN STOCK t2 ON t1.val = t2.item_id
WHERE t2.item_id IS NULL

答案 2 :(得分:1)

首先创建可能的ID列表(例如,在下面的查询中为0到99)。你可以使用递归cte。然后选择这些ID并从结果中删除表中已存在的ID:

with possible_ids(id) as
(
  select 0 as id from dual
  union all
  select id + 1 as id from possible_ids where id < 99
)
select id from possible_ids
minus
select item_id from stock;

答案 3 :(得分:1)

OP的主要关注点似乎是查询的简洁表示法,特别是要测试的值集。直接建议是通过另一个查询检索这些值,或者将它们生成为双表中查询的并集(请参阅其他答案)。

以下替代解决方案允许在以下条件下逐字指定测试值:

  1. 在提供的任何测试值中都没有出现任何字符(在-的示例中)

  2. 要测试的值的数量远远低于2000(确切地说,值列表加上分隔符必须写为varchar2文字,这会产生长度限制)。但是,这不应该是一个实际问题 - 如果测试涉及数百个ID的列表,那么这些列表肯定应该从表/视图中检索。

  3. <强> 买者

    这种方法是否值得麻烦(更不用说潜在的性能影响)是值得怀疑的,imho。

    <强> 解决方案

    测试值将作为单个varchar2文字提供,-将值与规范一样简洁,作为IN运算符的列表参数。该字符串以-开头和结尾。

    '-1-2-3-156-489-4654648-'
    

    项目数的计算方法如下:

    select cond, regexp_count ( cond, '[-]' ) - 1 cnt_items  from (select '-1-2-3-156-489-4654648-' cond from dual) 
    

    可以使用分层查询中的LEVEL伪列生成最多为1开头的项目的整数列表:

    select level from dual connect by level < 42;
    

    该列表中的第n个整数将用于从字符串中提取第n个值(以第4个值为例):

    select substr ( cond, instr(cond,'-', 1, 4 )+1, instr(cond,'-', 1, 4+1 ) - instr(cond,'-', 1, 4 ) - 1 ) si from (select cond, regexp_count ( cond, '[-]' ) - 1 cnt_items  from (select '-1-2-3-156-489-4654648-' cond from dual) );
    

    通过从值集合中减去一组股票ID来生成不存在的股票ID。把它们放在一起:

        select substr ( cond, instr(cond,'-',1,level )+1, instr(cond,'-',1,level+1 ) - instr(cond,'-',1,level ) - 1 ) si 
          from (
                  select cond
                       , regexp_count ( cond, '[-]' ) - 1 cnt_items
                    from (
                            select '-1-2-3-156-489-4654648-' cond from dual
                         )
               ) 
    connect by level <= cnt_items + 1
         minus
        select item_id from stock
             ;
    
相关问题