PLSQL 中的 LIMIT 子句用法

Posted

技术标签:

【中文标题】PLSQL 中的 LIMIT 子句用法【英文标题】:LIMIT clause usage in PLSQL 【发布时间】:2021-09-24 14:24:50 【问题描述】:

我有一个用于提取数据然后插入它们的过程。我的问题是我正在使用 BULK COLLECTION。我的目标是每次都提取例如 10,000 条数据,然后插入这 10,000 条记录。但是在我的脚本中,我可以用那个值来限制它,但它不会插入更多。例如,我有 6 条记录,我用 4 条带 LIMIT 子句。我想要的是程序应该首先插入 4 条记录,然后提取剩余的 2 条记录。

我可以简要描述一下问题。我对脚本中的任何修复建议持开放态度。从现在开始谢谢你。

我解决了我的问题在下面添加了新版本的脚本,谢谢大家

create or replace procedure GPU_DATA_EXTRACTOR_TEST(pid_billdate DATE) is
v_cnt      NUMBER;
c_limit   CONSTANT PLS_INTEGER DEFAULT 4;

CURSOR c1 IS
SELECT DISTINCT intl_prod_id
      FROM apld_bill_rt abr,
           acct_bill ab
      WHERE abr.CHRG_TP = 'INSTALLMENT'
          AND abr.TAX_CATG_ID = 'NOTAX'
          AND abr.acct_bill_id = ab.acct_bill_id
          AND ab.bill_date = pid_billdate;

TYPE prod_ids_t IS TABLE OF apld_bill_rt.intl_prod_id%TYPE INDEX BY PLS_INTEGER;
l_prod_ids   prod_ids_t;
begin

   execute immediate 'truncate table GPU_INV_TEST';

   v_cnt := 0;
  OPEN c1;

  LOOP
     FETCH c1 BULK COLLECT INTO l_prod_ids LIMIT c_limit;
     
     EXIT WHEN l_prod_ids.COUNT = 0;

    FOR indx IN 1 .. l_prod_ids.COUNT
    loop
      INSERT INTO GPU_INV_TEST
         SELECT AB.ACCT_BILL_ID,
                AB.BILL_NO,
                AB.INV_ID,
                AB.BILL_DATE,
                ba2.bill_acct_id,
                ba1.bill_acct_id parent_bill_acct_id,
                AB.DUE_DATE,
                PG.CMPG_ID,
                ABR.NET_AMT,
                AB.DUE_AMT,
                P.PROD_NUM,
                pds.DST_ID,
                ABR.DESCR,
                p.intl_prod_id
           FROM apld_bill_rt abr,
                acct_bill ab,
                prod p,
                FCBSADM.PROD_DST pds,
                bill_acct_prod bap,
                bill_acct ba1,
                bill_acct ba2,
                prod_cmpg pg
          WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
                AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
                AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
                AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
                AND bap.intl_prod_id = abr.intl_prod_id
                AND ABR.CHRG_TP = 'INSTALLMENT'
                AND bap.intl_prod_id = pds.intl_prod_id
                AND bap.intl_prod_id = p.intl_prod_id
                AND p.intl_prod_id = pg.intl_prod_id(+)
                AND ABR.intl_prod_id = l_prod_ids(indx)
UNION
    SELECT AB.ACCT_BILL_ID,
                AB.BILL_NO,
                AB.INV_ID,
                AB.BILL_DATE,
                ba1.bill_acct_id,
                ba1.bill_acct_id parent_bill_acct_id,
                AB.DUE_DATE,
                PG.CMPG_ID,
                ABR.NET_AMT,
                AB.DUE_AMT,
                P.PROD_NUM,
                pds.DST_ID,
                ABR.DESCR,
                p.intl_prod_id
           FROM apld_bill_rt abr,
                acct_bill ab,
                prod p,
                FCBSADM.PROD_DST pds,
                bill_acct_prod bap,
                bill_acct ba1,
                prod_cmpg pg
          WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
                AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
                --AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
                AND ba1.intl_bill_acct_id = bap.intl_bill_acct_id
                AND bap.intl_prod_id = abr.intl_prod_id
                AND ABR.CHRG_TP = 'INSTALLMENT'
                AND bap.intl_prod_id = pds.intl_prod_id
                AND bap.intl_prod_id = p.intl_prod_id
                AND p.intl_prod_id = pg.intl_prod_id(+)
                AND ABR.intl_prod_id = l_prod_ids(indx);

      v_cnt := v_cnt + 1;

      IF MOD (v_cnt, 4) = 0
      THEN
         COMMIT;
      END IF;

    end loop;
    COMMIT;
    END LOOP;
   CLOSE c1;
end;

【问题讨论】:

出于兴趣,为什么abr.TAX_CATG_IDabr.acct_bill_id?大写的意义是什么? @WilliamRobertson 没有显着差异 【参考方案1】:

您需要一个循环来获取多个记录子集。示例 sn-p:

...
loop
  FETCH c1 BULK COLLECT INTO l_prod_ids LIMIT c_limit;
  exit when l_prod_ids.count = 0;
  
  FOR indx IN 1 .. l_prod_ids.COUNT
    ...
end loop;
CLOSE c1;
...

顺便说一句,执行数千个单独的 INSERT 语句会导致性能下降。您应该使用 FORALL 语法(这不是循环)从您的集合中执行基于集合的插入操作。 Find out more.

当您可以只使用纯 SQL INSERT INTO ... SELECT ... FROM 语句时,您还应该考虑是否应该使用集合。这将比 FORALL 操作执行得更好。

【讨论】:

"which is not a loop" 它不会多次执行插入,但它确实是一个循环,因为在执行插入之前必须填充绑定变量数组。 @JeffHolt 毫无疑问,PL/SQL 引擎在内部必须遍历数组绑定变量,但从语法上讲,对于程序员来说,它是处理数组的单个语句。 您好,您的建议有效。我为问题添加了新的解决方案。谢谢

以上是关于PLSQL 中的 LIMIT 子句用法的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL LIMIT 子句

PostgreSQL LIMIT 子句

JPQL 中的 LIMIT 子句替代方案是啥?

mysql查的用法

如何改进 MySQL 中的 Limit 子句

Redshift 查询忽略 LIMIT 子句