【问题标题】:How to open a cursor a second time in a children loop in PL/SQL?如何在 PL/SQL 的子循环中第二次打开游标?
【发布时间】:2022-10-13 16:42:06
【问题描述】:

我需要一个项目来比较彼此之间的许多记录,但我之前在同一个选择的循环中做了一个选择,但我发现它太慢了,实际上我相信如果我可以将查询结果保存到中,我最多可以节省 2 秒一个光标并使用它,但我不知道该怎么做。

FUNCTION RES_DETP
(P_OBJET IN NUMBER
 ,P_DATE_DEBUT IN DATE
 ,P_DATE_FIN IN DATE
 ,P_SOCIETE IN VARCHAR2
) RETURN BOOLEAN
IS
CURSOR LISTE_RESERVATION IS SELECT
    NOM cur_nom,
    PRENOM cur_prenom,
    RESERVATIONS.DATE_DEBUT_PRECIS cur_ddp,
    RESERVATIONS.DATE_FIN_PRECIS cur_dfp,
    FROM CLIENTS,RESERVATIONS,LIGNES_RESERVATIONS
    WHERE
    LIGNES_RESERVATIONS.OBJ_NUMERO = P_OBJET AND
    LIGNES_RESERVATIONS.OBJ_SOCIETES_ID = P_SOCIETE AND
    LIGNES_RESERVATIONS.SOCIETES_ID = P_SOCIETE AND
    RESERVATIONS.SOCIETES_ID = P_SOCIETE AND
    LIGNES_RESERVATIONS.RES_NUMERO = RESERVATIONS.NUMERO AND
    LIGNES_RESERVATIONS.RES_SOCIETES_ID = RESERVATIONS.SOCIETES_ID AND
    CLIENTS.NUMERO = RESERVATIONS.CLI_NUMERO AND
    CLIENTS.SOCIETES_ID = RESERVATIONS.CLI_SOCIETES_ID AND
    CLIENTS.SOCIETES_ID = P_SOCIETE AND
    P_DATE_FIN > DATE_DEBUT_PRECIS AND 
    P_DATE_DEBUT < DATE_FIN_PRECIS
    order by RESERVATIONS.DATE_DEBUT_PRECIS;

CUR_RESERVATION     LISTE_RESERVATION%ROWTYPE;
COL_RESERVATION     LISTE_RESERVATION%ROWTYPE;

BEGIN

    OPEN LISTE_RESERVATION;
    LOOP
        FETCH LISTE_RESERVATION INTO CUR_RESERVATION;
        EXIT WHEN LISTE_RESERVATION%NOTFOUND;
        -- I want here to loop LISTE_RESERVATION again to compare each reservation together
    END LOOP;
END;

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    你不能;游标只能读取一次,不能倒带,所以不可能。

    你可以做什么用另一个DECLARE CURSOR LISTE_RESERVATION2 IS ... BEGIN ... END;块在循环的每次迭代中打开第二个游标:

    FUNCTION RES_DETP
    (P_OBJET IN NUMBER
     ,P_DATE_DEBUT IN DATE
     ,P_DATE_FIN IN DATE
     ,P_SOCIETE IN VARCHAR2
    ) RETURN BOOLEAN
    IS
      CURSOR LISTE_RESERVATION IS
        <your_query>;
    
      CUR_RESERVATION     LISTE_RESERVATION%ROWTYPE;
    BEGIN
      OPEN LISTE_RESERVATION;
      LOOP
        FETCH LISTE_RESERVATION INTO CUR_RESERVATION;
        EXIT WHEN LISTE_RESERVATION%NOTFOUND;
        DECLARE
          CURSOR LISTE_RESERVATION2 IS
            <your_query>;
    
          CUR_RESERVATION2 LISTE_RESERVATION2%ROWTYPE;
        BEGIN
          OPEN LISTE_RESERVATION2;
          LOOP
            FETCH LISTE_RESERVATION2 INTO CUR_RESERVATION;
            EXIT WHEN LISTE_RESERVATION2%NOTFOUND;
            -- compare the two values
          END LOOP;
        END;
      END LOOP;
    END;
    /
    

    然而,这将是缓慢的。

    在子查询因式分解子句中生成查询然后CROSS JOIN 自己生成查询可能会更好:

    FUNCTION RES_DETP
    (P_OBJET IN NUMBER
     ,P_DATE_DEBUT IN DATE
     ,P_DATE_FIN IN DATE
     ,P_SOCIETE IN VARCHAR2
    ) RETURN BOOLEAN
    IS
    CURSOR LISTE_RESERVATION IS
      WITH data (nom, prenom, ddp, dfp) AS (
        SELECT NOM,
               PRENOM,
               r.DATE_DEBUT_PRECIS,
               r.DATE_FIN_PRECIS
        FROM   CLIENTS c
               INNER JOIN RESERVATIONS r
               ON (   c.NUMERO = r.CLI_NUMERO
                  AND c.SOCIETES_ID = r.CLI_SOCIETES_ID)
               INNER JOIN LIGNES_RESERVATIONS l
               ON (   l.RES_NUMERO = r.NUMERO
                  AND l.RES_SOCIETES_ID = r.SOCIETES_ID)
        WHERE  l.OBJ_NUMERO = P_OBJET
        AND    l.OBJ_SOCIETES_ID = P_SOCIETE
        AND    l.SOCIETES_ID = P_SOCIETE
        AND    r.SOCIETES_ID = P_SOCIETE
        AND    c.SOCIETES_ID = P_SOCIETE
        AND    P_DATE_FIN > r.DATE_DEBUT_PRECIS
        AND    P_DATE_DEBUT < r.DATE_FIN_PRECIS
        order by r.DATE_DEBUT_PRECIS
      )
      SELECT d1.nom    AS nom1,
             d1.prenom AS prenom1,
             d1.ddp    AS ddp1,
             d1.dfp    AS dfp1,
             d2.nom    AS nom2,
             d2.prenom AS prenom2,
             d2.ddp    AS ddp2,
             d2.dfp    AS dfp2
      FROM   data d1
             CROSS JOIN data d2
      -- You can even add filters here
      -- WHERE ...
      ;
    
      CUR_RESERVATION     LISTE_RESERVATION%ROWTYPE;
    BEGIN
      OPEN LISTE_RESERVATION;
      LOOP
        FETCH LISTE_RESERVATION INTO CUR_RESERVATION;
        EXIT WHEN LISTE_RESERVATION%NOTFOUND;
        -- compare the two values
      END LOOP;
    END;
    /
    

    但是您可能想要做的是根本不使用任何游标或循环,并在单个 SQL 查询中进行所有比较,因为它会快得多(因为您不会在 PL/SQL 和SQL 范围)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-27
      • 2012-04-28
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多