如何通过 PL-Sql 获取数字范围内的数字。?

Posted

技术标签:

【中文标题】如何通过 PL-Sql 获取数字范围内的数字。?【英文标题】:How to get Numbers in number range by PL-Sql .? 【发布时间】:2013-11-21 09:17:23 【问题描述】:

这是我的序列表。它有超过 1000 条记录。它有开始号和结束号。但数字之间不存在。 我需要在另一个临时表中添加所有数字 [开始/之间和结束数字] 记录 按数字编号 如下所示

存在表

select concat(CARD_BULK_CODE,start_serial) startserial,concat(CARD_BULK_CODE,end_serial) endserial
from TSR_BULK_CARD_SERIALS
-------------------------- STARTSERIAL ENDSERIAL | -------------------------- 18126944 18126946 | 18141101 18141122 | 15150722 15150729 | 19069303 19069317 | --------------------------

必填表

------------ SERIAL_NO | ------------ 18126944 18126945 18141101 18141102 …… ------------

似乎它需要 pl-sql 来实现这一点。 请帮我解决这个问题

我在双重的帮助下尝试了以下查询。 但它很慢而且还没有得到结果:-) 运行超过 1 小时

select distinct concat(t.CARD_BULK_CODE,t.START_SERIAL)+level-1 SERIAL
from TSR_BULK_CARD_SERIALS t, dual
connect by level-1<=(concat(t.CARD_BULK_CODE,t.END_SERIAL ))-concat(t.CARD_BULK_CODE,t.START_SERIAL) 
order by 1

编辑:

亲爱的 Alen 和 Dba。我尝试了你的,但发生了以下错误。

DECLARE
     l_st NUMBER;
     l_en NUMBER;
BEGIN
     FOR rec IN (select concat(card_bulk_code, start_serial) startserial,concat(card_bulk_code, end_serial) endserial from tsr_bulk_card_serials)
     LOOP
          l_st := rec.startserial;
          l_en := rec.endserial;
          FOR rec1 IN l_st..l_en
          LOOP
               INSERT INTO temp(serial_no) values(rec1);
          END LOOP;
     END LOOP;
     COMMIT;
END;
Error at line 1
ORA-01426: numeric overflow
ORA-06512: at line 9

Script Terminated on line 1.

【问题讨论】:

Oracle get numbers with range 的可能重复项 发布临时表结构解决数字溢出错误 亲爱的 psaraj12,它带有 serial_no 列 |型号 亲爱的朋友 Nicholas,我从那个帖子中得到了双 sql。但它不符合我的要求。 【参考方案1】:

一种不使用 plsql 的方法

WITH ranges AS
(
  SELECT CONCAT(CARD_BULK_CODE, start_serial) startserial,
         CONCAT(CARD_BULK_CODE, end_serial) endserial
    FROM TSR_BULK_CARD_SERIALS
),
numbers(n) AS (
  SELECT 0 n
    FROM dual
UNION ALL
  SELECT n + 1
    FROM numbers
   WHERE n <= 
  (
    SELECT MAX(endserial - startserial)
      FROM ranges
  )
)
SELECT t.startserial + n.n SERIAL_NO
  FROM ranges t JOIN numbers n
    ON n.n <= t.endserial - t.startserial
 ORDER BY SERIAL_NO

这里是SQLFiddle演示

【讨论】:

感谢亲爱的 peterm。我曾用 dual 尝试过一次。但它有更多时间来执行。这就是为什么我要 plsql :-)【参考方案2】:

只需编写一些 PL/SQL - 遍历您的表并在临时表中插入行。

declare
   l_start number;
   l_end number;
begin
   for r_rec in (select to_number(concat(card_bulk_code, start_serial)) startserial
                 ,      to_number(concat(card_bulk_code, end_serial)) endserial
                 from   tsr_bulk_card_serials )
   loop
      l_start := r_rec.startserial;
      l_end := r_rec.endserial;
      for l_i in l_start..l_end loop
         insert into your_temp_table;
      end loop;
   end loop;
end;

【讨论】:

只需添加 to_number( ... ) 以使数据类型为数字。您示例中的 Concat 函数可能返回 varchar2 类型。更新了答案。 你的数字有多大?最大起始序列号和最终序列号是多少? 喜欢这个'121100246016920' OK,然后添加 to_number() 就可以了。【参考方案3】:

这样试试,

WITH t(ST, EN) AS
(
     SELECT 18126944,    18126946 FROM dual
     UNION
     SELECT 18141101,    18141122 FROM dual
     UNION
     SELECT 15150722,    15150729 FROM dual
     UNION
     SELECT 19069303 ,   19069317 FROM dual
)
SELECT DISTINCT st + LEVEL -1
FROM   t
CONNECT BY LEVEL <= (SELECT en - st + 1 FROM DUAL)
ORDER BY 1;

/

为 PL/SQL 尝试类似的方法,

DECLARE
     l_st NUMBER;
     l_en NUMBER;
BEGIN
     FOR rec IN (SELECT * FROM t)
     LOOP
          l_st := rec.st;
          l_en := rec.en;
          FOR rec1 IN l_st..l_en
          LOOP
               INSERT INTO <your_tab>;
          END LOOP;
     END LOOP;
     COMMIT;
END;     

【讨论】:

亲爱的 Dba,这里使用的 pl-sql 怎么样?因为存在表中的行数更多 这会产生大量的行并且会很慢。 只需编写一些 PL/SQL - 遍历您的表并在临时表中插入行。 是的,亲爱的 Przemyslaw.thatswhy 我想插入临时表。 @PrzemyslawKruglej,你说得对,如果我们使用 sql 会非常慢。感谢您指出。【参考方案4】:
DECLARE
   l_st      NUMBER (20);
   l_en      NUMBER (20);
   testnum   NUMBER (4);
BEGIN
   FOR rec IN (SELECT CONCAT (card_bulk_code, start_serial) startserial,CONCAT (card_bulk_code, end_serial) endserial FROM tsr_bulk_card_serials)
   LOOP
      l_st := TO_NUMBER (rec.startserial);
      l_en := TO_NUMBER (rec.endserial);
      testnum := l_en - l_st;
      DBMS_OUTPUT.put_line (l_st);
      DBMS_OUTPUT.put_line (l_en);

      IF l_st < l_en
      THEN
         FOR rec1 IN 0 .. testnum
         LOOP
            l_st := l_st + 1;

            INSERT INTO temp(serial_no) VALUES (l_st);
         END LOOP;
      END IF;
   END LOOP;
   COMMIT;
END;

上面的代码帮助我解决了我的问题 谢谢大家:-)

【讨论】:

以上是关于如何通过 PL-Sql 获取数字范围内的数字。?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 HSQLDB 中生成一个范围内的数字行列表?

如何创建一个 NSPredicate 过滤给定范围内的所有字符,包括数字/数字?

如何列出属于一组范围内的所有数字对?

在线性时间内对 0 到 n^2 – 1 范围内的 n 个数字进行排序

如何使用模板来规范化 0 到 1 范围内的数字?

生成 1 - 10 范围内的随机数