我正在做一个为大学创建录取系统的项目;这些技术是Java和Oracle。
在其中一个表格中,存储了预先生成的序列号。之后,根据这些序列号,将输入申请人的表格数据。我的要求是,当输入过程完成后,我将不得不生成一个明智的报告。如果在喂食预先生成的序列号期间,任何序列号都会丢失。
例如,在表中,序列号是7001,7002,7004,7005,7006,7010。 从上面的系列中可以清楚地看出,从7001到7010,缺失的数字是7003,7007,7008和7009
Oracle中是否有任何DBMS功能可以找出这些数字,或者如果任何存储过程可能符合我的目的,请建议一个算法。
我可以在Java中找到一些技术,但为了提高速度,我想在Oracle中找到解决方案。
答案 0 :(得分:42)
没有硬编码9的解决方案:
select min_a - 1 + level
from ( select min(a) min_a
, max(a) max_a
from test1
)
connect by level <= max_a - min_a + 1
minus
select a
from test1
结果:
MIN_A-1+LEVEL
-------------
7003
7007
7008
7009
4 rows selected.
答案 1 :(得分:13)
试试这个:
SELECT t1.SequenceNumber + 1 AS "From",
MIN(t2.SequenceNumber) - 1 AS "To"
FROM MyTable t1
JOIN MyTable t2 ON t1.SequenceNumber < t2.SequenceNumber
GROUP BY t1.SequenceNumber
HAVING t1.SequenceNumber + 1 < MIN(t2.SequenceNumber)
以下是序列7001,7002,7004,7005,7006,7010的结果:
From To
7003 7003
7007 7009
答案 2 :(得分:2)
这适用于postgres&gt; = 8.4。通过对CTE语法的一些细微修改,它也可以用于oracle和microsoft。
-- EXPLAIN ANALYZE
WITH missing AS (
WITH RECURSIVE fullhouse AS (
SELECT MIN(num)+1 as num
FROM numbers n0
UNION ALL SELECT 1+ fh0.num AS num
FROM fullhouse fh0
WHERE EXISTS (
SELECT * FROM numbers ex
WHERE ex.num > fh0.num
)
)
SELECT * FROM fullhouse fh1
EXCEPT ( SELECT num FROM numbers nx)
)
SELECT * FROM missing;
答案 3 :(得分:1)
为您的方案提供答案的一种简单方法是:
create table test1 ( a number(9,0));
insert into test1 values (7001);
insert into test1 values (7002);
insert into test1 values (7004);
insert into test1 values (7005);
insert into test1 values (7006);
insert into test1 values (7010);
commit;
select n.n from (select ROWNUM + 7001 as n from dual connect by level <= 9) n
left join test1 t on n.n = t.a where t.a is null;
选择将为您提供示例中的答案。这只是有意义的,如果你事先知道你的数字在哪个范围内,范围不应该太大。第一个数字必须是ROWNUM
部分中的偏移量,序列的长度是connect by
部分中的水平限制。
答案 4 :(得分:1)
我会建议connect by level
为Stefan has done,但是,您不能在此声明中使用子查询,这意味着它不适合您,因为您需要知道您的序列的最大值和最小值是什么。
我建议pipe-lined table function可能是生成加入所需数字的最佳方法。为了使其工作,您需要数据库中的对象将值返回到:
create or replace type t_num_array as table of number;
然后功能:
create or replace function generate_serial_nos return t_num_array pipelined is
l_first number;
l_last number;
begin
select min(serial_no), max_serial_no)
into l_first, l_last
from my_table
;
for i in l_first .. l_last loop
pipe row(i);
end loop;
return;
end generate_serial_nos;
/
使用此功能,以下内容将返回最小值和最大值之间的序列号列表。
select * from table(generate_serial_nos);
这意味着您的查询找出缺少的序列号:
select serial_no
from ( select *
from table(generate_serial_nos)
) generator
left outer join my_table actual
on generator.column_value = actual.serial_no
where actual.serial_no is null
答案 5 :(得分:1)
这有效但选择了第一个序列(起始值),因为它没有前任。在SQL Server中测试但应该在Oracle中工作
SELECT
s.sequence FROM seqs s
WHERE
s.sequence - (SELECT sequence FROM seqs WHERE sequence = s.sequence-1) IS NULL
这是测试结果
Table
-------------
7000
7001
7004
7005
7007
7008
Result
----------
7000
7004
7007
要获得未分配的序列,只需执行value[i] - 1
,其中i位于第一行,例如(7004 - 1 = 7003 and 7007 - 1 = 7006)
可用序列
我认为你可以改进这个简单的查询
答案 6 :(得分:1)
以下是一个解决方案:
SQL:
WITH MentionedValues /*this would just be your actual table, only defined here to provide data for this example */
AS (SELECT *
FROM ( SELECT LEVEL + 7000 seqnum
FROM DUAL
CONNECT BY LEVEL <= 10000)
WHERE seqnum NOT IN (7003,7007,7008,7009)--omit those four per example
),
Ranges /*identifies all ranges between adjacent rows*/
AS (SELECT seqnum AS seqnum_curr,
LAG (seqnum, 1) OVER (ORDER BY seqnum) AS seqnum_prev,
seqnum - (LAG (seqnum, 1) OVER (ORDER BY seqnum)) AS diff
FROM MentionedValues)
SELECT Ranges.*,
( SELECT LISTAGG (Ranges.seqnum_prev + LEVEL, ',') WITHIN GROUP (ORDER BY 1)
FROM DUAL
CONNECT BY LEVEL < Ranges.diff) "MissingValues" /*count from lower seqnum+1 up to lower_seqnum+(diff-1)*/
FROM Ranges
WHERE diff != 1 /*ignore when diff=1 because that means the numers are sequential without skipping any*/
;
输出:
SEQNUM_CURR SEQNUM_PREV DIFF MissingValues
7004 7002 2 "7003"
7010 7006 4 "7007,7008,7009"
答案 7 :(得分:0)
SELECT ROWNUM "Missing_Numbers" FROM dual CONNECT BY LEVEL <= (SELECT MAX(a) FROM test1)
MINUS
SELECT a FROM test1 ;
答案 8 :(得分:0)
改进的查询是:
SELECT ROWNUM "Missing_Numbers" FROM dual CONNECT BY LEVEL <= (SELECT MAX(a) FROM test1)
MINUS
SELECT ROWNUM "Missing_Numbers" FROM dual CONNECT BY LEVEL < (SELECT Min(a) FROM test1)
MINUS
SELECT a FROM test1;
注意:a是我们在其中发现缺失值的列。
答案 9 :(得分:-1)
select A.ID + 1 As ID
From [Missing] As A
Where A.ID + 1 Not IN (Select ID from [Missing])
And A.ID < n
Data: ID
1
2
5
7
Result: ID
3
4
6