【问题标题】:Want a query to find the missed numbers in DB想要查询以查找数据库中丢失的号码
【发布时间】:2012-06-15 17:09:38
【问题描述】:

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

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

有人有想法吗?

【问题讨论】:

  • 字母前缀列表是否仅限于显示的 2 个值,或者是否还有其他值?另外,你确定有差距时重要吗?你能负担得起将T0 视为2 个字符的前缀,还是T 系列可以得到T10000T0系列和T1系列的差距分开列出有关系吗?
  • @JammyC.c - 如果你喜欢答案,你应该投票给他们。

标签: sql oracle oracle11g query-optimization


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢,有没有什么链接或资料提供了关于Oracle的好解决方案?
  • 是的 - 那些链接。语法可能略有变化,但解决方案是相同的。如果您需要最佳的 Oracle 优化解决方案(“完美的性能”),您可能需要询问 Oracle 的一位负责设计数据库引擎的同事。
【解决方案2】:

对于新加坡:

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

【讨论】:

  • 非常感谢,我将您的查询复制到 Oracle SQL 开发人员,但出现编译错误。什么是“WITH t AS”?
  • 奇怪...我要试试 sqlfiddle
  • 谢谢,“WITH t AS”是什么意思?它是这个查询的一部分吗?
  • @Sebas:硬编码前缀不是一个好方法,因为它只是指定的演示数据卡。
  • @JammyC.c: 你的表格是否包含以 SG 和 T 开头的?
【解决方案3】:

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 中的保留字。在我的测试中,我使用了不同的列名。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2020-02-27
    • 2016-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多