Datensätze und Cursor verwenden
Der Skriptcontent auf dieser Seite ist ausschließlich für Navigationszwecke vorgesehen und bewirkt keinerlei Änderung des Contents.
Sie können Datenwerte in Records speichern und einen Cursor als Zeiger auf eine Ergebnismenge und zugehörige Verarbeitungsinformationen verwenden.
Siehe: Oracle Database PL/SQL-Sprachreferenz, um weitere Informationen zu Datensätzen zu erhalten
Info zu Datensätzen
Ein Datensatz ist eine zusammengesetzte PL/SQL-Variable, in der Datenwerte verschiedener Typen gespeichert werden können. Sie können interne Komponenten (Felder) wie skalare Variablen behandeln. Sie können ganze Records als Unterprogrammparameter übergeben. Datensätze eignen sich für die Speicherung von Daten in Tabellenzeilen oder aus bestimmten Spalten von Tabellenzeilen.
Ein Datensatz ist eine zusammengesetzte PL/SQL-Variable, die Datenwerte verschiedener Typen speichern kann, ähnlich wie ein Strukturtyp in C, C++ oder Java. Die internen Komponenten eines Datensatzes werden als Felder bezeichnet. Um auf ein Datensatzfeld zuzugreifen, verwenden Sie die Punktschreibweise: record_name.field_name.
Sie können die Datensatzfelder wie skalare Variablen verwenden. Sie können auch ganze Records als Unterprogrammparameter übergeben.
Datensätze eignen sich für die Speicherung von Daten in Tabellenzeilen oder aus bestimmten Spalten von Tabellenzeilen. Jedes Datensatzfeld entspricht einer Tabellenspalte.
Es gibt drei Möglichkeiten, einen Datensatz zu erstellen:
-
deklarieren Sie einen RECORD-Typ, und deklarieren Sie dann eine Variable dieses Typs.
Verwenden Sie folgende Syntax:
TYPE record_name IS RECORD ( field_name data_type [:= initial_value] [, field_name data_type [:= initial_value ] ]... ); variable_name record_name; -
Deklarieren Sie eine Variable vom Typ table_name%ROWTYPE.
Die Felder des Datensatzes haben die gleichen Namen und Datentypen wie die Spalten der Tabelle.
-
Deklarieren Sie eine Variable des Typs cursor_name%ROWTYPE.
Die Felder des Datensatzes haben die gleichen Namen und Datentypen wie die Spalten der Tabelle in der Klausel FROM der Cursoranweisung SELECT.
Siehe:
-
Oracle Database PL/SQL Language Reference für weitere Informationen zur Definition von RECORD-Typen und zur Deklarierung von Datensätzen dieses Typs
-
Oracle Database PL/SQL-Sprachreferenz für die Syntax einer RECORD-Typdefinition
-
Oracle Database PL/SQL Language Reference für weitere Informationen zum Attribut %ROWTYPE
-
Oracle Database PL/SQL Language Reference für die Syntax des Attributs %ROWTYPE
Tutorial: Einen RECORD-Typ deklarieren
In den folgenden Schritten wird erläutert, wie Sie mit SQL Developer-Tool "Bearbeiten" einen RECORD-Typ namens sal_info deklarieren können, dessen Felder Gehaltsinformationen für einen Mitarbeiter enthalten, wie etwa Job-ID, Mindest- und Höchstgehalt für diese Job-ID, aktuelles Gehalt und Gehaltserhöhung.
Schritte zum Deklarieren von RECORD type sal_info:
-
Blenden Sie im Schritt "Verbindungen" hr_conn ein.
Unter dem Symbol hr_conn wird eine Liste von Schemaobjekttypen angezeigt.
-
Erweitern Sie Packages.
Eine Liste der Packages wird angezeigt.
-
Klicken Sie mit die rechte Maustaste auf EMP_EVAL.
Eine Optionsliste wird angezeigt.
-
Wählen Sie Bearbeiten.
Der Fensterbereich EMP_EVAL wird geöffnet und zeigt die Anweisung
CREATE PACKAGE, mit der das Package erstellt wurde:CREATE OR REPLACE PACKAGE EMP_EVAL AS PROCEDURE eval_department(dept_id IN NUMBER); FUNCTION calculate_score(evaluation_id IN NUMBER , performance_id IN NUMBER) RETURN NUMBER; END EMP_EVAL; -
Fügen Sie im Bereich EMP_EVAL direkt vor
END EMP_EVALfolgenden Code hinzu:TYPE sal_info IS RECORD ( j_id jobs.job_id%type , sal_min jobs.min_salary%type , sal_max jobs.max_salary%type , sal employees.salary%type , sal_raise NUMBER(3,3) );Der Titel des Bereichs ist kursiv formatiert. Damit wird angegeben, dass die Änderungen noch nicht in der Datenbank gespeichert wurden.
-
Wählen Sie das Symbol Kompilieren.
Die geänderte Package-Spezifikation wird kompiliert und in die Datenbank gespeichert. Der Titel des Fensterbereichs EMP_EVAL wird nicht mehr kursiv dargestellt.
Nun können Sie Datensätze des Typs sal_info deklarieren, wie in "Tutorial: Unterprogramm mit Record-Parameter erstellen und aufrufen" erläutert.
Tutorial: Ein Unterprogramm mit einem Datensatzparameter erstellen und aufrufen
Die folgenden Schritte zeigen, wie Sie mit dem SQL Developer-Tool "Bearbeiten" ein Unterprogramm mit einem Parameter des Datensatztyps sal_info erstellen und aufrufen.
Der Datensatztyp sal_info wurde in "Tutorial: RECORD-Typ deklarieren" erstellt.
In diesem Tutorial wird gezeigt, wie Sie mit dem SQL Developer-Tool Edit die folgenden Aufgaben ausführen:
-
Erstellen Sie eine Prozedur, SALARY_SCHEDULE, die einen Parameter des Typs
sal_infoenthält. -
Funktion EVAL_FREQUENCY ändern, sodass sie den Record emp_sal des Typs
sal_infodeklariert, seine Felder auffüllen und ihn an die Prozedur SALARY_SCHEDULE übergibt.
Da EVAL_FREQUENCY die Prozedur SALARY_SCHEDULE aufruft, muss die Deklaration von SALARY_SCHEDULE vorangehen (anderweder kann das Package nicht kompiliert werden). Die Definition von SALARY_SCHEDULE kann jedoch an einer beliebigen Stelle innerhalb des Package-Bodys erfolgen.
Schritte zum Erstellen von SALARY_SCHEDULE und Ändern von EVAL_FREQUENCY:
-
Blenden Sie im Schritt "Verbindungen" hr_conn ein.
-
Blenden Sie in der Liste der Schemaobjekttypen die Option Packages ein.
-
Blenden Sie in der Liste der Pakete EMP_EVAL ein.
-
Klicken Sie in der Auswahlliste mit der rechten Maustaste auf EMP_EVAL Body.
-
Wählen Sie in der Auswahlliste Bearbeiten aus.
Der Hauptbereich von EMP_EVAL wird angezeigt. Er zeigt den Code für den Package Body.
-
Fügen Sie im Body-Fenster EMP_EVAL unmittelbar vor
END EMP_EVALdie folgenden Definitionen der Prozedur SALARY_SCHEDULE hinzu:PROCEDURE salary_schedule (emp IN sal_info) AS accumulating_sal NUMBER; BEGIN DBMS_OUTPUT.PUT_LINE('If salary ' || emp.sal || ' increases by ' || ROUND((emp.sal_raise * 100),0) || '% each year, it will be:'); accumulating_sal := emp.sal; WHILE accumulating_sal <= emp.sal_max LOOP accumulating_sal := accumulating_sal * (1 + emp.sal_raise); DBMS_OUTPUT.PUT_LINE(ROUND(accumulating_sal,2) ||', '); END LOOP; END salary_schedule;Der Titel des Bereichs ist kursiv formatiert. Damit wird angegeben, dass die Änderungen noch nicht in der Datenbank gespeichert wurden.
-
Geben Sie im Bereich EMP_EVAL Body die Funktion eval_frequency und die Prozeduren salary_schedule und add_eval an der folgenden Position ein:
CREATE OR REPLACE PACKAGE BODY EMP_EVAL AS FUNCTION eval_frequency (emp_id EMPLOYEES.EMPLOYEE_ID%TYPE) RETURN PLS_INTEGER; PROCEDURE salary_schedule(emp IN sal_info); PROCEDURE add_eval(employee_id IN employees.employee_id%type, today IN DATE); PROCEDURE eval_department (dept_id IN NUMBER) AS -
Bearbeiten Sie die Funktion
EVAL_FREQUENCY, und nehmen Sie die folgenden Änderungen vor:FUNCTION eval_frequency (emp_id EMPLOYEES.EMPLOYEE_ID%TYPE) RETURN PLS_INTEGER AS h_date EMPLOYEES.HIRE_DATE%TYPE; today EMPLOYEES.HIRE_DATE%TYPE; eval_freq PLS_INTEGER; emp_sal SAL_INFO; -- replaces sal, sal_raise, and sal_max BEGIN SELECT SYSDATE INTO today FROM DUAL; SELECT HIRE_DATE INTO h_date FROM EMPLOYEES WHERE EMPLOYEE_ID = eval_frequency.emp_id; IF ((h_date + (INTERVAL '120' MONTH)) < today) THEN eval_freq := 1; /* populate emp_sal */ SELECT j.JOB_ID, j.MIN_SALARY, j.MAX_SALARY, e.SALARY INTO emp_sal.j_id, emp_sal.sal_min, emp_sal.sal_max, emp_sal.sal FROM EMPLOYEES e, JOBS j WHERE e.EMPLOYEE_ID = eval_frequency.emp_id AND j.JOB_ID = eval_frequency.emp_id; emp_sal.sal_raise := 0; -- default CASE emp_sal.j_id WHEN 'PU_CLERK' THEN emp_sal.sal_raise := 0.08; WHEN 'SH_CLERK' THEN emp_sal.sal_raise := 0.07; WHEN 'ST_CLERK' THEN emp_sal.sal_raise := 0.06; WHEN 'HR_REP' THEN emp_sal.sal_raise := 0.05; WHEN 'PR_REP' THEN emp_sal.sal_raise := 0.05; WHEN 'MK_REP' THEN emp_sal.sal_raise := 0.04; ELSE NULL; END CASE; IF (emp_sal.sal_raise != 0) THEN salary_schedule(emp_sal); END IF; ELSE eval_freq := 2; END IF; RETURN eval_freq; END eval_frequency; -
Wählen Sie Kompilieren aus.
Info zu Cursorn
Wenn Oracle Database eine SQL-Anweisung ausrichtet, werden die Ergebnismenge und Verarbeitungsinformationen in einem unbenannten privaten SQL-Bereich gespeichert. Über einen Zeiger zu diesem unbenannten Bereich, der als Cursor bezeichnet ist, können Sie die Ergebnismenge einzeln abrufen. Cursorattribute geben Informationen über den Status des Cursors zurück.
Jedes Mal, wenn Sie eine SQL-DML-Anweisung oder eine PL/SQL SELECT INTO-Anweisung ausführen, öffnet PL/SQL einen impliziten Cursor. Informationen zu diesem Cursor können Sie seinen Attributen entnehmen. Sie können ihn jedoch nicht steuern. Nachdem die Anweisung ausgeführt wird, schließt die Datenbank den Cursor. Seine Attributwerte bleiben jedoch verfügbar, bis eine andere DML- oder SELECT INTO-Anweisung ausgeführt wird.
Mit PL/SQL können Sie auch Cursor deklarieren. Ein deklarierter Cursor hat einen Namen und ist mit einer Abfrage verknüpft (SQL SELECT-Anweisung), die in der Regel mehrere Zeilen zurückgibt. Nachdem Sie einen Cursor deklariert haben, müssen Sie ihn implizit oder explizit verarbeiten. Um den Cursor implizit zu verarbeiten, verwenden Sie einen Cursor FOR LOOP. Die Syntax lautet:
FOR record_name IN cursor_name LOOP
statement
[ statement ]...
END LOOP;
Um den Cursor explizit zu verarbeiten, öffnen Sie ihn (mit der OPEN-Anweisung), rufen Zeilen aus der Ergebnismenge entweder einzeln oder im Bulkverfahren (mit der FETCH-Anweisung) ab und schließen den Cursor (mit der CLOSE-Anweisung). Wenn Sie den Cursor geschlossen haben, können Sie weder Datensätze aus der Ergebnismenge abrufen noch die Cursorattributwerte sehen.
Die Syntax für den Wert eines impliziten Cursorattributs lautet SQL%attribute (z.B. SQL%FOUND). SQL%attribute bezieht sich immer auf die zuletzt ausgeführte DML- oder SELECT INTO-Anweisung.
Die Syntax für den Wert eines deklarierten Cursorattributs lautet cursor_name%attribute (z.B. c1%FOUND). In Tabelle 1 sind die Cursorattribute und die Werte, die sie zurückgeben können, aufgeführt. (Implizite Cursor verfügen über zusätzliche Attribute, die nicht in diesem Buch behandelt werden.)
Tabelle 1: Cursorattributwerte
| Attribut | Werte für deklarierten Cursor | Werte für impliziten Cursor |
|---|---|---|
| % GEFUNDEN | Wenn der Cursor offen ist (Fußnote 1), aber kein Fetch (Abruf) versucht wurde, NULL. Wenn der letzte Fetch eine Zeile zurückgegeben hat, TRUE. Wenn der letzte Fetch keine Zeile zurückgegeben hatte, FALSE. |
Wenn keine DML- oder SELECT INTO-Anweisung ausgeführt wurde, NULL. Wenn die letzte DML- oder SELECT INTO-Anweisung eine Zeile zurückgegeben hat, TRUE. Wenn die letzte DML- oder SELECT INTO-Anweisung keine Zeile zurückgegeben hatte, FALSE. |
| % NICHT GEFUNDEN | Wenn der Cursor offen ist (Fußnote 1), aber kein Fetch (Abruf) versucht wurde, NULL. Wenn der letzte Fetch eine Zeile zurückgegeben hat, FALSE. Wenn der letzte Fetch keine Zeile zurückgegeben hatte, TRUE. |
Wenn keine DML- oder SELECT INTO-Anweisung ausgeführt wurde, NULL. Wenn die letzte DML- oder SELECT INTO-Anweisung eine Zeile zurückgegeben hat, Wenn die letzte DML- oder SELECT INTO-Anweisung keine Zeile zurückgegeben haben, |
| % ZEILENANZAHL | Wenn der Cursor geöffnet ist (Fußnote 1), eine Zahl größer oder gleich Null. | NULL, wenn keine DML- oder SELECT INTO-Anweisung ausgeführt wurde; andernfalls eine Zahl größer oder gleich NULL. |
| %IST GEÖFFNET | Wenn der Cursor geöffnet ist, TRUE; wenn nicht, FALSE. | Immer falsch. |
Fußnote 1: Wenn der Cursor nicht geöffnet ist, löst das Attribut die vordefinierte Ausnahme INVALID_CURSOR aus.
Siehe:
-
Oracle Database PL/SQL-Sprachreferenz für weitere Informationen zur SELECT INTO-Anweisung
-
Oracle Database PL/SQL Language Reference, um weitere Informationen über die Verwaltung von Cursorn in PL/SQL
Verwendung eines deklarierten Cursors zum Abrufen von Ergebnismengenzeilen einzeln
Mit einem deklarierten Cursor können Sie Ergebnismengenzeilen nacheinander abrufen.
Die folgende Prozedur verwendet jede benötigte Anweisung in ihrer einfachsten Form, verweist jedoch auf ihre vollständige Syntax.
Schritte zur Verwendung eines deklarierten Cursors zum Abrufen von Ergebnismengenzeilen nacheinander:
-
Im deklarativen Teil:
-
Deklarieren Sie den Cursor:
CURSOR cursor_name IS query;Informationen zur vollständigen Deklarationssyntax für expliziten Cursor finden Sie in der Oracle Database PL/SQL Language Reference.
-
Deklarieren Sie einen Datensatz, der die vom Cursor zurückgegebene Zeile enthalten soll:
record_name cursor_name%ROWTYPE;Informationen zur vollständigen %ROWTYPE-Syntax finden Sie unter Oracle Database PL/SQL Language Reference.
-
-
Im ausführbaren Teil:
-
Öffnen Sie den Cursor:
OPEN cursor_name;Informationen zur vollständigen OPEN-Anweisungssyntax finden Sie unter Oracle Database PL/SQL Language Reference.
-
Zeilen (aus der Ergebnismenge) einzeln aus dem Cursor (Zeilen aus der Ergebnismenge) abrufen, wobei eine LOOP-Anweisung verwendet wird, die Syntax wie die folgende ausführt:
LOOP FETCH cursor_name INTO record_name; EXIT WHEN cursor_name%NOTFOUND; -- Process row that is in record_name: statement; [ statement; ]... END LOOP;Informationen zur vollständigen FETCH-Anweisungssyntax finden Sie unter Oracle Database PL/SQL Language Reference.
-
Schließen Sie den Cursor:
CLOSE cursor_name;
-
Informationen zur vollständigen CLOSE-Anweisungssyntax finden Sie unter Oracle Database PL/SQL Language Reference.
Tutorial: Einen deklarierten Cursor zum Abrufen von Ergebnismengenzeilen verwenden
Die folgenden Schritte zeigen, wie die Prozedur EMP_EVAL.EVAL_DEPARTMENT implementiert wird, die den deklarierten Cursor emp_cursor verwendet.
Schritte zur Implementierung der Prozedur EMP_EVAL.EVAL_DEPARTMENT:
-
Ändern Sie in der Package-Spezifikation EMP_EVAL die Deklaration der Prozedur EVAL_DEPARTMENT wie folgt:
PROCEDURE eval_department(dept_id IN employees.department_id%TYPE); -
Ändern Sie im Package Body EMP_EVAL die Definition der Prozedur EVAL_DEPARTMENT wie im folgenden Beispiel dargestellt:
PROCEDURE eval_department (dept_id IN employees.department_id%TYPE) AS CURSOR emp_cursor IS SELECT * FROM EMPLOYEES WHERE DEPARTMENT_ID = eval_department.dept_id; emp_record EMPLOYEES%ROWTYPE; -- for row returned by cursor all_evals BOOLEAN; -- true if all employees in dept need evaluations today DATE; BEGIN today := SYSDATE; IF (EXTRACT(MONTH FROM today) < 6) THEN all_evals := FALSE; -- only new employees need evaluations ELSE all_evals := TRUE; -- all employees need evaluations END IF; OPEN emp_cursor; DBMS_OUTPUT.PUT_LINE ( 'Determining evaluations necessary in department # ' || dept_id ); LOOP FETCH emp_cursor INTO emp_record; EXIT WHEN emp_cursor%NOTFOUND; IF all_evals THEN add_eval(emp_record.employee_id, today); ELSIF (eval_frequency(emp_record.employee_id) = 2) THEN add_eval(emp_record.employee_id, today); END IF; END LOOP; DBMS_OUTPUT.PUT_LINE('Processed ' || emp_cursor%ROWCOUNT || ' records.'); CLOSE emp_cursor; END eval_department;(Ein Beispiel für eine schrittweise Änderung eines Packagebodys finden Sie unter "Tutorial: Variablen und Konstanten in Unterprogrammen deklarieren".)
-
Kompilieren Sie die Package-Spezifikation EMP_EVAL.
-
Kompilieren Sie den Package Body EMP_EVAL.
Info zu Cursorvariablen
Eine Cursor-Variable ist wie ein Cursor, der nicht auf eine einzelne Abfrage beschränkt ist. Sie können eine Cursor-Variable für eine Abfrage öffnen, die Ergebnismenge verarbeiten und die Cursor-Variable anschließend für eine andere Abfrage wiederverwenden. Cursor-Variablen sind insbesondere für das Übergeben von Abfrageergebnissen zwischen Unterprogrammen nützlich.
Informationen zu Cursor finden Sie unter "Informationen zu Cursor".
Um eine CURSOR-Variable zu deklarieren, deklarieren Sie zunächst einen REF CURSOR-Typ und deklarieren anschließend eine Variable dieses Typs (daher wird CURSOR-Variablen häufig auch REF CURSOR genannt). Ein REF CURSOR-Typ kann schwach oder stark sein.
Ein starker REF CURSOR-Typ gibt einen Rückgabetyp an, bei dem es sich um den RECORD-Typ der Cursorvariablen handelt. Der PL/SQL-Compiler erlaubt die Verwendung dieser starken Cursorvariablen nicht für Abfragen, die Zeilen zurückgeben, welche nicht den Rückgabetyp aufweisen. Starke REF-CURSOR-Typen sind weniger fehleranfällig als schwache, doch schwache Arten bieten größere Flexibilität.
Ein schwacher REF CURSOR-Typ gibt keinen Rückgabetyp an. Der PL/SQL-Compiler akzeptiert schwache Cursor-Variablen in sämtlichen Abfragen. Schwache REF-Cursortypen sind austauschbar; statt schwache REF-Cursortypen zu erstellen, können Sie auch den vordefinierten schwachen Cursortyp SYS_REFCURSOR verwenden.
Nach dem Deklarieren einer Cursor-Variablen müssen Sie sie für eine spezifische Abfrage öffnen (mit der Anweisung OPEN FOR), die Zeilen einzeln aus der Ergebnismenge abrufen (mit der Anweisung FETCH) und ihn für eine weitere spezifische Abfrage öffnen (mit der Anweisung CLOSE) oder ihn für eine weitere spezifische Abfrage öffnen (mit der Anweisung OPEN FOR). Wenn Sie die Cursor-Variable für eine andere Abfrage öffnen, wird sie für die vorherige Abfrage geschlossen. Nach dem Schließen einer Cursor-Variablen für eine spezifische Abfrage können keine Records mehr aus der Ergebnismenge abgerufen werden, noch können die Cursor-Attributwerte für diese Abfrage angezeigt werden.
Siehe:
-
Oracle Database PL/SQL Language Reference für weitere Informationen über die Verwendung von Cursorvariablen
-
Oracle Database PL/SQL Language Reference für die Syntax bei der Deklaration von Cursorvariablen
Eine Cursorvariable zum Abrufen von einzelnen Ergebnismengenzeilen verwenden
Sie können Ergebnismengenzeilen mit einer Cursorvariablen einzeln abrufen.
Die folgende Prozedur verwendet die erforderlichen Anweisungen in der jeweils einfachsten Form, enthält jedoch Verweise auf die vollständige Syntax.
Schritte zur Verwendung einer Cursorvariablen zum Abrufen von Ergebnismengenzeilen einzeln:
-
Im deklarativen Teil:
-
Deklarieren Sie den Typ REF CURSOR:
TYPE cursor_type IS REF CURSOR [ RETURN return_type ];Die vollständige Syntax für die REF CURSOR-Typendeklaration finden Sie in Oracle Database PL/SQL Language Reference.
-
Deklarieren Sie eine Cursor-Variable dieses Typs:
cursor_variable cursor_type;Die vollständige Syntax der Deklaration von Cursor-Variablen finden Sie in Oracle Database PL/SQL Language Reference.
-
Deklarieren Sie einen Datensatz, der die vom Cursor zurückgegebene Zeile enthalten soll:
record_name return_type;Vollständige Informationen zur Syntax für die Record-Deklaration finden Sie in Oracle Database PL/SQL Language Reference.
-
-
Im ausführbaren Teil:
-
Öffnen Sie die Cursor-Variable für eine spezifische Abfrage:
OPEN cursor_variable FOR query;Vollständige Informationen zur Syntax für die Anweisung OPEN FOR finden Sie in Oracle Database PL/SQL Language Reference.
-
Rufen sie Zeilen (aus der Ergebnismenge) einzeln aus der Cursor-Variablen ab. Verwenden sie hierzu eine LOOP-Anweisung mit folgender Syntax:
LOOP FETCH cursor_variable INTO record_name; EXIT WHEN cursor_variable%NOTFOUND; -- Process row that is in record_name: statement; [ statement; ]... END LOOP;Vollständige Informationen zur Syntax für die FETCH-Anweisung finden Sie in Oracle Database PL/SQL Language Reference.
-
Schließen Sie die Cursor-Variable:
CLOSE cursor_variable;Alternativ dazu können Sie die Cursor-Variable auch für eine weitere Abfrage öffnen, wodurch sie für die aktuelle Abfrage geschlossen wird.
Vollständige Informationen zur Syntax für die Anweisung CLOSE finden Sie in Oracle Database PL/SQL Language Reference.
-
Tutorial: Eine Cursorvariable zum Abrufen von einzelnen Ergebnismengenzeilen verwenden
In den folgenden Schritten wird gezeigt, wie Sie die Prozedur EMP_EVAL.EVAL_DEPARTMENT so ändern, dass sie anstelle eines deklarierten Cursors eine Cursorvariable verwendet (mit der mehrere Abteilungen verarbeitet werden können) und wie Sie EMP_EVAL.EVAL_DEPARTMENT und EMP_EVAL.ADD_EVAL effizienter machen.
In diesem Tutorial wird außerdem gezeigt, wie Sie EMP_EVAL.EVAL_DEPARTMENT und EMP_EVAL.ADD_EVAL optimieren: Anstatt ein Feld eines Datensatzes an ADD_EVAL zu übergeben und mit ADD_EVAL drei Abfragen zu verwenden, um drei weitere Felder desselben Datensatzes zu extrahieren, übergibt EVAL_DEPARTMENT den gesamten Datensatz an ADD_EVAL, und ADD_EVAL verwendet Punktschreibweise, um auf Werte der anderen drei Felder zuzugreifen.
Schritte zum Ändern der Prozedur EMP_EVAL.EVAL_DEPARTMENT, um eine Cursorvariable zu verwenden:
-
Geben Sie in der Package-Spezifikation EMP_EVAL die Prozedurdeklaration und die Typdefinition für REF CURSOR an, wie im folgenden Beispiel dargestellt:
CREATE OR REPLACE PACKAGE emp_eval AS PROCEDURE eval_department (dept_id IN employees.department_id%TYPE); PROCEDURE eval_everyone; FUNCTION calculate_score(eval_id IN scores.evaluation_id%TYPE , perf_id IN scores.performance_id%TYPE) RETURN NUMBER; TYPE SAL_INFO IS RECORD ( j_id jobs.job_id%type , sal_min jobs.min_salary%type , sal_max jobs.max_salary%type , salary employees.salary%type , sal_raise NUMBER(3,3)); TYPE emp_refcursor_type IS REF CURSOR RETURN employees%ROWTYPE; END emp_eval; -
Fügen sie im Package Body EMP_EVAL eine Weiterleitungsdeklaration für die Prozedur EVAL_LOOP_CONTROL hinzu, und ändern sie die Deklaration der Prozedur ADD_EVAL wie dargestellt:
CREATE OR REPLACE PACKAGE BODY EMP_EVAL AS FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE) RETURN PLS_INTEGER; PROCEDURE salary_schedule(emp IN sal_info); PROCEDURE add_eval(emp_record IN EMPLOYEES%ROWTYPE, today IN DATE); PROCEDURE eval_loop_control(emp_cursor IN emp_refcursor_type); ...(Ein Beispiel für eine schrittweise Änderung eines Packagebodys finden Sie unter "Tutorial: Variablen und Konstanten in Unterprogrammen deklarieren".)
-
Ändern sie die Prozedur EVAL_DEPARTMENT, um drei separate Ergebnismengen für die Abteilung abzurufen und um die Prozedur EVAL_LOOP_CONTROL aufzurufen, wie im folgenden Beispiel dargestellt:
PROCEDURE eval_department(dept_id IN employees.department_id%TYPE) AS emp_cursor emp_refcursor_type; current_dept departments.department_id%TYPE; BEGIN current_dept := dept_id; FOR loop_c IN 1..3 LOOP OPEN emp_cursor FOR SELECT * FROM employees WHERE current_dept = eval_department.dept_id; DBMS_OUTPUT.PUT_LINE ('Determining necessary evaluations in department #' || current_dept); eval_loop_control(emp_cursor); DBMS_OUTPUT.PUT_LINE ('Processed ' || emp_cursor%ROWCOUNT || ' records.'); CLOSE emp_cursor; current_dept := current_dept + 10; END LOOP; END eval_department; -
Ändern Sie die Prozedur ADD_EVAL wie folgt:
PROCEDURE add_eval(emp_record IN employees%ROWTYPE, today IN DATE) AS -- (Delete local variables) BEGIN INSERT INTO EVALUATIONS ( evaluation_id, employee_id, evaluation_date, job_id, manager_id, department_id, total_score ) VALUES ( evaluations_sequence.NEXTVAL, -- evaluation_id emp_record.employee_id, -- employee_id today, -- evaluation_date emp_record.job_id, -- job_id emp_record.manager_id, -- manager_id emp_record.department_id, -- department_id 0 -- total_score ); END add_eval; -
Fügen Sie vor
END EMP_EVALdie folgende Prozedur hinzu, um die einzelnen Datensätze aus der Ergebnismenge abzurufen und zu verarbeiten:PROCEDURE eval_loop_control (emp_cursor IN emp_refcursor_type) AS emp_record EMPLOYEES%ROWTYPE; all_evals BOOLEAN; today DATE; BEGIN today := SYSDATE; IF (EXTRACT(MONTH FROM today) < 6) THEN all_evals := FALSE; ELSE all_evals := TRUE; END IF; LOOP FETCH emp_cursor INTO emp_record; EXIT WHEN emp_cursor%NOTFOUND; IF all_evals THEN add_eval(emp_record, today); ELSIF (eval_frequency(emp_record.employee_id) = 2) THEN add_eval(emp_record, today); END IF; END LOOP; END eval_loop_control; -
Fügen Sie vor
END EMP_EVALfolgende Prozedur hinzu, um eine Ergebnismenge abzurufen, die alle Mitarbeiter des Unternehmens enthält:PROCEDURE eval_everyone AS emp_cursor emp_refcursor_type; BEGIN OPEN emp_cursor FOR SELECT * FROM employees; DBMS_OUTPUT.PUT_LINE('Determining number of necessary evaluations.'); eval_loop_control(emp_cursor); DBMS_OUTPUT.PUT_LINE('Processed ' || emp_cursor%ROWCOUNT || ' records.'); CLOSE emp_cursor; END eval_everyone; -
Kompilieren Sie die Package-Spezifikation
EMP_EVAL. -
Kompilieren Sie den Package Body
EMP_EVAL.