0

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 函数来列出丢失的数字:

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

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

有人有想法吗?

4

3 回答 3

1

有很多选择。这被称为“岛屿和差距”问题。尝试查看以下资源(大多数都可以在 Oracle 和 SQL 服务器中使用。有些可能需要调整):

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

或者

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

于 2012-06-15T18:13:23.707 回答
0

新加坡:

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
于 2012-06-15T17:43:37.033 回答
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 中的保留字。在我的测试中,我使用了不同的列名。

于 2012-06-15T18:11:49.217 回答