【问题标题】:Getting the corresponding record of a Cursor/Select when in a Cursor LOOP statement在 Cursor LOOP 语句中获取 Cursor/Select 的对应记录
【发布时间】:2022-06-29 17:55:25
【问题描述】:

这个问题似乎很简单。我已经建立了一个包,其中有一个相当大的光标,假设在我公司全年的所有发票上。

    CURSOR c_invoices(p_year IN INTEGER) IS
    SELECT     all_invoices.invoicenumber,   
               all_invoices.invoicedate,
               all_invoices.customernumber
    FROM       all_invoices
    WHERE      all_invoices.year = p_year 
    ;

打开它并使用 LOOP 语句后,我想从另一个表 (forbidden_​​customers) 中获取一些数据,但前提是客户在最后一个表中。

我想做的是在我的包的最开始打开另一个游标(或 SELECT ?),浏览整个表(forbidden_​​customers),然后在我的发票循环中获取相应的记录.

所以,类似:

        CURSOR     c_forbidden_customers IS
        SELECT     forbidden_customers.customernumber,   
                   forbidden_customers.customeradress
        FROM       forbidden_customers
        ;

然后:

OPEN    c_invoices(v_year);
        LOOP FETCH c_invoices INTO invoices_cursor;
        BEGIN
        EXIT WHEN c_invoices%NOTFOUND; 
             *IF invoices_cursor.customernumber IS FOUND IN c_forbidden_customers ...
                 THEN ...* 

这就是我同时做的(我知道这很糟糕):

SELECT COUNT(*)
INTO v_exist /*INTEGER*/
FROM forbidden_customers
WHERE forbidden_customers.customernumber= p_customernumber

IF v_exist <> 0 
    THEN...

我尽量说清楚。感谢您的宝贵时间

【问题讨论】:

  • edit 包含minimal reproducible example 的问题:CREATE TABLE 表的语句;一些样本数据的INSERT 语句;您的代码的 MINIMAL 示例(或与您的代码类似的问题);您的代码的问题/错误;和预期的输出。

标签: oracle plsql database-cursor


【解决方案1】:

不要做两次;在同一个游标中加入两个表并使用它。此外,如果您切换到游标 FOR 循环,您将免于打字,因为 Oracle 将为您完成大部分 无聊 的工作(声明游标变量、打开游标、关闭游标、退出循环...):

create or replace procedure p_test (p_year in integer) is
begin
  for c_invoices in 
    (select a.invoicenumber,
            a.invoicedate,
            a.customernumber,
            c.customeraddress
     from all_invoices a join forbidden_customers c on c.customernumber = a.customernumber
     where a.year = p_year)
  loop
    -- do something
  end loop;
end;

【讨论】:

  • 最好使用外连接,因为并非所有客户都在forbidden_​​customers 表中。
  • 也许,@Michael。按照我的理解,OP 只想为匹配的行“做某事”。如果不是,那么是的 - 外连接会更好。
  • 感谢@Littlefoot。不幸的是,我不能这样做 1. 我必须在多个表上执行此操作,并且查询会很大,以及 2. 我以前尝试过,但它会使查询变得非常非常慢。
  • 单独获取 FORBIDEEN_CUSTOMERS 数据不会加快速度。您是否正确索引了连接中涉及的所有列?您是否定期收集架构统计信息(以便 Oracle 能够使用最佳执行计划)?
  • 是的,围绕数据库本身的一切都已正确完成。每天至少收集一次统计信息。问题是,如果我这样做,我的程序将看起来像一个巨大的查询,这不是我真正想要做的。
【解决方案2】:

如果forbidden_​​customers 表不大并且适合oracle 的会话内存,您可以使用pl/sql 表存储来自forbidden_​​customers 的所有id 并稍后检查。检查仅在内存中完成,因此比任何常规选择都要快。

create table all_invoices
(id number,
year number,
customer_number number);

create table forbidden_customers
(customer_number number);

CREATE OR REPLACE TYPE t_number_table IS TABLE OF number
/

CREATE OR REPLACE PROCEDURE test23
IS
    forbidden_customers_list   t_number_table;

    CURSOR c_invoices (p_year IN INTEGER)
    IS
        SELECT all_invoices.customer_number
          FROM all_invoices
         WHERE all_invoices.year = p_year;
BEGIN
   SELECT customer_number
   BULK   COLLECT INTO forbidden_customers_list
   FROM   forbidden_customers;
   
    FOR rec_invoices  in c_invoices(2022) loop
        if forbidden_customers_list.exists(rec_invoices.customer_number) then
    null;
        end if;
    end loop;
end;
/

【讨论】:

    猜你喜欢
    • 2018-04-07
    • 1970-01-01
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多