我正在尝试使用oracle 11g。我有一个要求,我想从列表中获取那些在表中不存在的id。
例如:
SELECT * FROM STOCK
where item_id in ('1','2'); // Return those records where result is null
我的意思是如果db中没有item_id '1'
,那么查询应该返回1
。
我怎样才能做到这一点?
答案 0 :(得分:2)
您需要将值存储在某种"表"中。然后,您可以使用left join
或not 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的主要关注点似乎是查询的简洁表示法,特别是要测试的值集。直接建议是通过另一个查询检索这些值,或者将它们生成为双表中查询的并集(请参阅其他答案)。
以下替代解决方案允许在以下条件下逐字指定测试值:
在提供的任何测试值中都没有出现任何字符(在-
的示例中)
要测试的值的数量远远低于2000(确切地说,值列表加上分隔符必须写为varchar2文字,这会产生长度限制)。但是,这不应该是一个实际问题 - 如果测试涉及数百个ID的列表,那么这些列表肯定应该从表/视图中检索。
<强> 买者 强>
这种方法是否值得麻烦(更不用说潜在的性能影响)是值得怀疑的,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
;