2017-05-10 2 views
0

Gibt es eine Möglichkeit, eine Variable in der Cursor-Deklaration sql zu verwenden? Beispiel-Verwenden von Variablen in der Cursor-Deklarationsabfrage in Oracle

create or replace PROCEDURE PRD (IN_VAR IN VARCHAR2) 
IS 

    V_V1 TABLE.DATE_COL%TYPE; 

    /* Cursor decleration */ 
    CURSOR CUR_DUMMY 
    IS 
     SELECT COL1,COL2,COL3 
      FROM TABLE 
      WHERE DATE_COL BETWEEN V_V1 
        AND V_V1+1; 

BEGIN 
    FOR REC IN CUR_DUMMY 
    LOOP 

    SELECT TO_DATE(TO_CHAR(sysdate, 'DD-MON-YY') ||' '||(SELECT TO_CHAR(DAY_BEGIN,'HH24:MI:SS') FROM TABLE2),'DD-MON-YY HH24:MI:SS') INTO V_V1 from DUAL; 

-- other stuffs 
    END LOOP; 
END; 

Hier wird der Cursor holen nicht über die erforderlichen Aufzeichnungen. Kann ich den V_V1-Wert irgendwo vor der Cursor-Deklaration zuweisen? Obwohl ich Daten im Cursor sql selbst erhalten kann, aber es wird redundante Select-Abfrage geben. Gibt es einen besseren Weg?

+0

Sie eaxmple wird nicht funktionieren. Weil Sie bereits den 'select'-Befehl ausgeführt haben, bevor Sie einen Wert auf' V_V1' setzen. Also in Ihrer Auswahl ist V_V1 NULL. – Tenzin

Antwort

1

Sie müssen V_V1 einen Wert zuweisen, bevor Sie den Cursor durchlaufen. Außerdem müssen Sie die Variable in der Cursor-Definition (Cursor c_dummy (V_V1 Datum)) und geben es definieren, wenn Sie den Cursor FOR REC IN CUR_DUMMY (V_V1) Aufruf

create or replace PROCEDURE PRD (IN_VAR IN VARCHAR2) 
IS 

    V_V1 TABLE.DATE_COL%TYPE; 

    /* Cursor decleration */ 
    CURSOR CUR_DUMMY(V_V1 date) 
    IS 
     SELECT COL1,COL2,COL3 
      FROM TABLE 
      WHERE DATE_COL BETWEEN V_V1 
        AND V_V1+1; 

BEGIN 
    SELECT TO_DATE(TO_CHAR(sysdate, 'DD-MON-YY') ||' '||(SELECT TO_CHAR(DAY_BEGIN,'HH24:MI:SS') FROM TABLE2),'DD-MON-YY HH24:MI:SS') INTO V_V1 from DUAL; 
    FOR REC IN CUR_DUMMY(V_V1) 
    LOOP 

-- do stuffs 

    END LOOP; 
END; 
0

Wie folgt auf meinem Kommentar, vielleicht dieses Arbeitsbeispiel Ihnen eine Idee nicht geben:

DECLARE 
     CURSOR c1(nId IN NUMBER) IS 
       SELECT * 
       FROM  TableA 
       WHERE Id = nId; 
BEGIN 
     FOR r1 IN c1(nId => 3) LOOP 
       --Do something here 
       DBMS_OUTPUT.PUT_LINE('A'); 
     END LOOP; 
END; 
/

So in Sie zB holt V_V1 zuerst, dann diesen Wert verwenden, um einen Cursor zu öffnen.

1

Als jemand hat bereits gesagt, Sie müssen sich bewegen Ihre Variable V_V1 außerhalb der FOR-Schleife. Sobald der Cursor geöffnet ist, ist die Ergebnismenge festgelegt. Das Ändern von V_V1 innerhalb der Schleife macht keinen Unterschied.

Der folgende Code entfernt auch von der Auswahl von Dual, die Sie nicht tun müssen (und sollte Einfachheit und Leistung zu vermeiden) und benennt die Variablen mit ein bisschen mehr Bedeutung (schwer zu tun, wenn ich nicht weiß wofür der Code ist - aber ich hoffe, dass Sie sie für Ihren Beitrag umbenannt haben und dass sie nicht so in Ihrem tatsächlichen Code sind)

Auch wieder ohne Wissen von Ihnen Codes Zweck, denken Sie daran, dass BETWEEN ist inklusive, so dass BETWEEN the_date AND the_date +1 möglicherweise Datensätze enthält, die Sie nicht möchten. Ich vermute ein wenig, aber >= the_date AND < the_date + 1 ist möglicherweise die richtige Klausel.

Als Best-Practice-Empfehlungen, kann ich auch vorschlagen, dass, wenn Sie nicht bereits Ihre Prozedur in einem Paket machen, und dass Kommentare in Code nur für verwendet werden soll, warum der Code so ist, wie es ist nicht was es ist. ein Kommentar, der sagt Cursor-Deklaration ist von Vorteil für die Lesbarkeit Ihres Codes. Abhängig von der Verarbeitung in der Schleife sollten Sie auch die Verwendung von BULK COLLECT in Erwägung ziehen, die an anderer Stelle gut dokumentiert ist.

CREATE OR REPLACE PROCEDURE my_procedure (in_var IN VARCHAR2) 
IS  
    today_begin TABLE.DATE_COL%TYPE; 
    the_day_begin TABLE2.DAY_BEGIN%TYPE; 

    CURSOR todays_records(the_date DATE) 
    IS 
     SELECT COL1,COL2,COL3 
     FROM TABLE 
     WHERE DATE_COL BETWEEN the_date AND the_date + 1; 

BEGIN 

    SELECT DAY_BEGIN 
    INTO the_day_begin 
    FROM TABLE2; 

    today_begin := TO_DATE(TO_CHAR(sysdate, 'DD-MON-YY') ||' '|| TO_CHAR(the_day_begin,'HH24:MI:SS'),'DD-MON-YY HH24:MI:SS') 

    FOR rec IN todays_records(today_begin) 
    LOOP 
     -- other stuffs 
    END LOOP; 

END; 
+0

danke für all Ihre Vorschläge. Ja, ich habe sie für diesen Beitrag umbenannt. – Maverick