简体   繁体   中英

How can I give parameter in PL/SQL cursor

I've a table of 8k of row, divide in subset of 1k.

The procedure will be called in this way EXEC BONIFICA_GECT(0); ie, i need run the command inside script only for subset=0 (field is called lotto)

INSERT INTO T_TEST_CI_CO (customerid,customercode) ValueS(v_cid,v_cod);

I've try to create the procedure, but i don't understand how give the input value on the cursor

CREATE OR REPLACE PROCEDURE BONIFICA_GECT(LOTTO IN NUMBER)
IS

CURSOR id IS
SELECT numero_pratica FROM bonifica1_GECT_2020 WHERE 1=1 lotto=LOTTO
                                               AND (new_status_gect IS NULL OR new_status_gect='PARTIAL_LOAD');

v_pratica bonifica1_GECT_2020.numero_pratica%TYPE;
v_cid     bonifica1_GECT_2020.customerid%TYPE;
v_cod      bonifica1_GECT_2020.customercode%TYPE;
v_lotto NUMBER;
V_CHECK_LOTTO NUMBER;

BEGIN

    OPEN id;
    LOOP
       fetch id INTO v_pratica;
       EXIT WHEN id%NOTFOUND;

       SELECT customerid,customercode INTO v_cid,v_cod
       FROM  bonifica1_GECT_2020
       WHERE numero_pratica=v_pratica;

       INSERT INTO T_TEST_CI_CO (customerid,customercode) ValueS(v_cid,v_cod);

    END LOOP;
    CLOSE id;

COMMIT;

EXCEPTION
    WHEN NO_DATA_FOUND
    THEN
        NULL;
    WHEN OTHERS
    THEN
        /* Consider logging the error and then re-raise */
        RAISE;

END BONIFICA_GECT;

You cursor currently has (ignoring the stray 1=1 ):

CURSOR id IS
SELECT numero_pratica FROM bonifica1_GECT_2020 WHERE lotto=LOTTO
                                               AND (new_status_gect IS NULL OR new_status_gect='PARTIAL_LOAD');

Both sides of the lotto=LOTTO refer to the column in the table, so that is always true (unless the column value is null); neither side is seeing the parameter argument with the same name.

You need to give the parameter a different name, eg:

CREATE OR REPLACE PROCEDURE BONIFICA_GECT(P_LOTTO IN NUMBER)
IS
  CURSOR id IS
    SELECT numero_pratica
    FROM bonifica1_GECT_2020
    WHERE lotto = P_LOTTO
    AND (new_status_gect IS NULL OR new_status_gect='PARTIAL_LOAD');
...

You could prefix with the object name(s) instead:

    WHERE bonifica1_GECT_2020.lotto = BONIFICA_GECT.LOTTO

but I prefer giving the argument and variable names simpler prefixes.

I'm not sure why you get just the ID from the cursor and then look up other values from the same table; you could do:

CREATE OR REPLACE PROCEDURE BONIFICA_GECT(P_LOTTO IN NUMBER)
IS
  CURSOR v_cursor IS
    SELECT numero_pratica, customerid, customercode
    FROM bonifica1_GECT_2020
    WHERE lotto = P_LOTTO
    AND (new_status_gect IS NULL OR new_status_gect='PARTIAL_LOAD');

  v_pratica bonifica1_GECT_2020.numero_pratica%TYPE;
  v_cid     bonifica1_GECT_2020.customerid%TYPE;
  v_cod     bonifica1_GECT_2020.customercode%TYPE;
BEGIN

  OPEN v_cursor;
  LOOP
     FETCH v_cursor INTO v_pratica, v_cid, v_cod;
     EXIT WHEN v_cursor%NOTFOUND;

     INSERT INTO T_TEST_CI_CO (customerid,customercode
     VALUES (v_cid, v_cod);

  END LOOP;
  CLOSE v_cursor;
END BONIFICA_GECT;

You can't get no-data-found with this (or with your original); and catching when others isn't a good idea unless you really do need to log it somewhere.

You could make the cursor itself parameterised; again picking a different prefix/name:

CREATE OR REPLACE PROCEDURE BONIFICA_GECT(P_LOTTO IN NUMBER)
IS
  CURSOR v_cursor (C_LOTTO NUMBER) IS
    SELECT numero_pratica, customerid, customercode
    FROM bonifica1_GECT_2020
    WHERE lotto = C_LOTTO
    AND (new_status_gect IS NULL OR new_status_gect='PARTIAL_LOAD');

  v_pratica bonifica1_GECT_2020.numero_pratica%TYPE;
  v_cid     bonifica1_GECT_2020.customerid%TYPE;
  v_cod     bonifica1_GECT_2020.customercode%TYPE;
BEGIN

  OPEN v_cursor (P_LOTTO);
...

or if you really want to not have prefixes you can specify the argument is from the cursor:

CREATE OR REPLACE PROCEDURE BONIFICA_GECT(LOTTO IN NUMBER)
IS
  CURSOR v_cursor (LOTTO NUMBER) IS
    SELECT numero_pratica, customerid, customercode
    FROM bonifica1_GECT_2020
    WHERE lotto = v_cursor.LOTTO
    AND (new_status_gect IS NULL OR new_status_gect='PARTIAL_LOAD');
...
  OPEN v_cursor (LOTTO);
  -- or: OPEN v_cursor (BONIFICA_GECT.LOTTO);
...

Either way that's only really useful if you'll reuse the cursor with different arguments within the same procedure.

You could also use an implicit cursor, which is simpler; but I assume this is an exercise in this kind of cursor.

Inserting in a loop isn't very efficient, and this can be done as a single insert.. select ; and doesn't even need PL/SQL. Again, I've assumed that's part of the exercise.

If you are looking for parameterised CURSOR you may try -

CURSOR id(LOTTO NUMBER) IS
SELECT numero_pratica
FROM bonifica1_GECT_2020 
WHERE 1=1
AND lotto=LOTTO
AND (new_status_gect IS NULL OR new_status_gect='PARTIAL_LOAD');

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM