想要查询以查找数据库中丢失的号码

时间:2012-06-15 17:09:39

标签: sql oracle oracle11g query-optimization

我有一个表part,其中包含一些演示数据,如下面的Oracle DB中所示:

ID    NUMBER     DESCRIPTION
1     T00001     test
2     T00002     test
3     T00003     test
4     T00004     test
5     T00008     test
6     SG0001     test
7     SG0002     test
8     SG0003     test
9     SG0004     test
10    SG0006     test

NUMBER定义了具有不同预定义前缀和自动增量数后缀的不同类别部分。现在在DB中有一些错过的数字,因此连续性被打破。我想要一个具有完美性能的SQL查询或PL-SQL函数来列出错过的数字:

例如:对于上述演示数据。应返回以下数据:

 Category1 start with T: T00005,T00006,T00007 
 Category1 start with SG: SG0005

有人有想法吗?

3 个答案:

答案 0 :(得分:1)

有很多选择。这被称为“群岛和空白”问题。尝试查看以下资源(大多数将在Oracle和SQL服务器中运行。有些可能需要调整):

http://msdn.microsoft.com/en-us/library/aa175780(v=sql.80).aspx

http://www.sqlservercentral.com/articles/Advanced+Querying/anefficientsetbasedsolutionforislandsandgaps/1619/

答案 1 :(得分:0)

对于SG:

WITH t AS ( 
    SELECT 
        0 as start_n, 
        p.a as end_n 
    FROM (
        SELECT MAX(TO_NUMBER(SUBSTR("NUMBER", 3))) a FROM Part p2 
        WHERE "NUMBER" LIKE 'SG%') p
)
SELECT 
    'SG' || LPAD(r.cur_num, 4, '0') AS missing_expr
FROM 
    (SELECT t.start_n + level - 1 AS cur_num FROM t CONNECT BY t.start_n + level - 1 <= t.end_n) r
WHERE 
    NOT EXISTS(
        SELECT * FROM part p WHERE p."NUMBER" = 'SG' || LPAD(r.cur_num, 4, '0')
    )
ORDER BY missing_expr ASC;

对于T:

WITH t AS ( 
    SELECT 
        0 as start_n, 
        p.a as end_n 
    FROM (
        SELECT MAX(TO_NUMBER(SUBSTR("NUMBER", 2))) a FROM Part p2 
        WHERE "NUMBER" LIKE 'T%') p
)
SELECT
    'T' || LPAD(r.cur_num, 5, '0') AS missing_expr
FROM 
    (SELECT t.start_n + level - 1 AS cur_num FROM t CONNECT BY t.start_n + level - 1 <= t.end_n) r
WHERE 
    NOT EXISTS(
        SELECT * FROM part p WHERE p.number = 'T' || LPAD(r.cur_num, 5, '0')
    )
ORDER BY missing_expr ASC

答案 2 :(得分:0)

对于T使用:

 select 'T' || substr('0000' || to_char(r.rn),length(to_char(r.rn)-1))
    from (select rownum rn from part 
        where rownum <= (select max(to_number(substr(p.number,2))) from part p 
                         where p.number like 'T%'
                        )
       ) r
     where 
      'T' || substr('0000' || to_char(r.rn),length(to_char(r.rn)-1)) 
      not in (select p.number from part p where p.number like 'T%');

供SG使用:

select 'SG' || substr('000' || to_char(r.rn),length(to_char(r.rn)-1))
    from (select rownum rn from part 
      where rownum <= (select max(to_number(substr(p.number,3))) from part p 
                       where p.number like 'SG%'
                      )
     ) r
where 
  'SG' || substr('000' || to_char(r.rn),length(to_char(r.rn)-1)) 
  not in (select p.number from part p where p.number like 'SG%');

有几点需要注意:

1)我正在使用表PART获取rownum值。如果有足够的行,则可以使用任何表。如果使用此方法,请确保使用足够大的表来提取所需的值范围。 USER_OBJECTS也可以正常工作。 PART可能没有足够的值来使用。

2)似乎NUMBER作为列名会导致您遇到问题。这是Oracle中的保留字。在我的测试中,我使用了不同的列名。