我正在使用Oracle 10g数据库。我正在试图弄清楚如何编写一个简单的SQL查询:
在86002895和86005197(含)之间的表格中找到缺失的数字,86002895和86005197之间有1955行。
例如:当前场景:table_1:
tracking_no | id_value
86002895 | 10
86002896 | 10
86002899 | 10
86002900 | 10
86002910 | 10
86005196 | 10
86005197 | 10
预期结果1:
“缺少tracking_id”,其中id_value 从table_1开始= 10;
86002897
86002898
86002900
到
86002910
86002910 到
86005196
提前致谢
答案 0 :(得分:3)
with data as
(
select tracking_no from table_1 where id_value = 10
),
data_n as
(
select level + (select min(tracking_no) from data) n
from dual
connect by level <= (select max(tracking_no) - min(tracking_no) from data)
)
select * from data_n
where not exists (select 1 from data where tracking_no = n);
如果要包括86002895和86005197,请执行:
with data as
(
select tracking_no from table_1
where id_value = 10
and tracking_no between 86002895 and 86005197
),
data_n as
(
select level + (select min(tracking_no) from data) n
from dual
connect by level <= (select max(tracking_no) - min(tracking_no) from data)
)
select * from data_n
where not exists (select 1 from data where tracking_no = n);
答案 1 :(得分:1)
试试光标?不是一个完整的解决方案...
declare
V_IDX number := 86002895;
begin
for REC in (select *
from TABLE_1
order by TRACKING_NO asc)
loop
if V_IDX <> REC.TRACKING_NO then
dbms_output.PUT_LINE('missing tracking_id '|| REC.TRACKING_NO || ' where id_value = ' || REC.ID_VALUE || ' from table_1');
end if;
V_IDX := V_IDX + 1;
end loop;
end;
更新:我还不能添加评论,但除了彼得的答案,你可以动态制作数字表。例如,以下内容将返回86002895和86004849之间的所有数字:
select rownum+86002895-1
from dual
connect by level <= 1955
答案 2 :(得分:1)
使用MINUS设置操作。
-- all numbers
SELECT ROWNUM
FROM dual
CONNECT BY level <= :SOME_LARGE_VALUE_HERE
MINUS
-- some numbers missing
SELECT id
FROM table_1
根据需要调整。
答案 3 :(得分:1)
使用model子句的解决方案:
select rangech
from
(
select rangech
from table_1
where id_value = 10
model
dimension by (row_number() over (order by tracking_no) rn)
measures (cast(null as varchar2(25)) rangech,tracking_no no)
rules
(
rangech[any] = case
when no[cv()+1] is not null and no[cv()]+1 < no[cv()+1]-1
then to_char(no[cv()]+1)||'-'||to_char(no[cv()+1]-1)
when no[cv()+1] is not null and no[cv()]+1 = no[cv()+1]-1
then to_char(no[cv()]+1)
else
'X'
end
)
)
where rangech <> 'X'
order by rangech;
输出:
RANGECH
-------------------------
86002897-86002898
86002901-86002909
86002911-86005195
答案 4 :(得分:0)
如果你有一个数字表,你会这样做:
SELECT t.min_no+n.Number-1 AS missing_no
FROM Numbers n
INNER JOIN (
SELECT MIN(tracking_no) AS min_no, MAX(tracking_no) AS max_no
FROM TABLE WHERE id_value = 10
) t ON n.Number BETWEEN 1 AND t.max_no-t.min_no+1
WHERE n.Number+t.min_no-1 NOT IN (
SELECT tracking_no FROM TABLE
WHERE id_value = 10
);
数字表是一个包含一个整数列的表,数字从0或1到你需要的高度。
答案 5 :(得分:0)
不是最优雅的解决方案,但它有效(在MySQL中 - 我不使用Oracle,所以我希望它适合你!):
SELECT tracking_no
FROM yourtable
WHERE id_value = 10
AND tracking_no-1 NOT IN (SELECT tracking_no FROM yourtable WHERE id_value=10)
UNION
SELECT tracking_no
FROM yourtable
WHERE id_value = 10
AND tracking_no+1 NOT IN (SELECT tracking_no FROM yourtable WHERE id_value=10)
ORDER BY tracking_no
答案 6 :(得分:0)
以下方法为您提供了所有缺失跟踪号的列表,但没有列出范围:
步骤1:找到tracking_no的最大值和最小值:M1和M2
步骤2:创建包含单列tracking_no
的临时表 TempNumbers步骤3:将(M2 - M1)+ 1个唯一行插入 TempNumbers ,其值从M1到M2包含
第4步:
SELECT tracking_no FROM TempNumbers
WHERE NOT EXISTS (SELECT 'not found' FROM table_1
WHERE TempNumbers.tracking_no = table_1.tracking_no)
答案 7 :(得分:0)
这将返回每个缺失范围的起始端列表:
select s, e from
(select s, rownum sr
from
(
select tracking_no + 1 s
from table_1
where id_value = 10
MINUS
select tracking_no
from table_1
where id_value = 10
order by s
)),
(
select e, rownum er
from
(
select tracking_no - 1 e
from table_1
where id_value = 10
MINUS
select tracking_no
from table_1
where id_value = 10
order by e
))
where er-1 = sr;
答案 8 :(得分:0)
select next_in_sequence missing_range_begin,
next_actual -1 missing_range_end
from
(
select
tracking_no,
tracking_no + 1 next_in_sequence,
lead(tracking_no, 1) over (order by tracking_no) next_actual
from test
where id_value = 10
order by tracking_no
)
where next_in_sequence <> next_actual
;
答案 9 :(得分:0)
基本上使用86002894作为偏移量。然后它变成一个简单的查询。如果你的表非常大,你可以添加一个where子句。
我已经使用了ALL_OBJECTS,但是你可以使用任何有足够行数的表。
SELECT rownum+86002894
FROM All_Objects
WHERE rownum between 1 AND 86005197-86002895
MINUS
SELECT tracking_no
FROM your_table