מדריך PL-SQL – סמנים (Cursors)
סמן הינו סביבת עבודה ב-PL/SQL, אשר משמש לאיחסון זמני של נתונים אשר הוחזרו משאילתה. ערכה של כל עמודה נשמר ע"י מצביע (Pointer).
ניתן לתפעל ולבצע פעולות מסויימות על כל שדה בפני עצמו.
ישנם שני סוגי סמנים:
- Implicit – אשר נוצרים ע"י מנוע ה-Oracle בעצמו
- Explicit – נוצרים ע"י המשתמש.
סמנים משמשים בדרך כלל כדי לאחסן נתונים שאילתות שהחזירו יותר מאשר ערך יחיד.
מאפייני הסמן:
- %ISOPEN – מחזיר true אם הסמן פתוח, אחרת, מחזיר false
- %FOUND – מחזיר true אם הרשומה יובאה בהצלחה, false אם לא.
- %NOTFOUND – מחזיר true אם הרשומה לא יובאה בהצלחה, false אם כן.
- %ROWCOUNT – מחזיר את מספר הרשומות הנכללות בסמן.
--EXAMPLE OF SQL%FOUND (IMPLICIT CURSORS) begin update employee set salary=salary *0.15 where emp_code = &emp_code; if SQL%found then dbms_output.put_line('employee record modified successfully'); else dbms_output.put_line('employee no does not exist'); end if; end;
--EXAMPLE FOR SQL%NOTFOUND (IMPLICIT CURSORS) begin update employee set salary = salary*0.15 where emp_code = &emp_code; f SQL%notfound then dbms_output.put_line('employee no . does not exist'); else dbms_output.put_line('employee record modified successfully'); end if; end;
--EXAMPLE FOR SQL%ROWCOUNT (IMPLICIT CURSORS) declare rows_affected char(4); begin update employee set salary = salary*0.15 where job='programmers'; rows_affected := to_char(SQL%rowcount); if SQL%rowcount > 0 then dbms_output.put_line(rows_affected || 'employee records modified successfully'); else dbms_output.put_line('There are no employees working as programmers'); end if; end;
תפעול הסמן
תפעול הסמן נעשה ע"י שלוש פקודות פשוטות:
- Open – פותחת את הסמן ע"י שאילתה מסויימת
- Close – סוגרת את הסמן
- Fetch – מיבא את ערכי הרשומה הנוכחית לתוך משתנים.
תחביר
DECLARE CURSOR <cursor_name> IS <SQL_Statment>; -- variables declaration BEGIN OPEN <cursor_name>; FETCH <cursor_name> INTO <var1>,<var2>... CLOSE <cursor_name> END;
דוגמאות
--EXPLICIT CURSOR EG DECLARE CURSOR c1 is SELECT * FROM emp; str_empno emp.empno%type; str_ename emp.ename%type; str_job emp.job%type; str_mgr emp.mgr%type; str_hiredate emp.hiredate%type; str_sal emp.sal%type; str_comm emp.comm%type; str_deptno emp.deptno%type; rno number; BEGIN rno := &rno; FOR e_rec IN c1 LOOP IF c1%rowcount = rno THEN DBMS_OUTPUT.PUT_LINE (str_empno || ' ' || str_ename || ' ' || str_job || ' ' || str_mgr || ' ' || str_hiredate || ' ' || str_sal || ' ' || str_comm || ' ' || str_deptno); END IF; END LOOP; END;
--ANOTHER EG DISPLAYING VALUE OF A TABLE DECLARE CURSOR c1 IS SELECT * FROM emp; e_rec emp%rowtype; BEGIN OPEN c1; LOOP FETCH c1 INTO e_rec; DBMS_OUTPUT.PUT_LINE('Number: ' || ' ' || e_rec.empno); DBMS_OUTPUT.PUT_LINE('Name : ' || ' ' || e_rec.ename); DBMS_OUTPUT.PUT_LINE('Salary: ' || ' ' || e_rec.sal); EXIT WHEN c1%NOTFOUND; END LOOP; CLOSE c1; END;
-- Display details of Highest 10 salary paid employee DECLARE CURSOR c1 IS SELECT * FROM emp ORDER BY sal DESC; e_rec emp%rowtype; BEGIN FOR e_rec IN c1 LOOP DBMS_OUTPUT.PUT_LINE('Number: ' || ' ' || e_rec.empno); DBMS_OUTPUT.PUT_LINE('Name : ' || ' ' || e_rec.ename); DBMS_OUTPUT.PUT_LINE('Salary: ' || ' ' || e_rec.sal); EXIT WHEN c1%ROWCOUNT >= 10; END LOOP; END;
-- EXAMPLE OF CURSOR FOR LOOP declare cursor c1 is select * from somdutt; begin for outvariable in c1 loop exit when c1%notfound; if outvariable.age < 21 then dbms_output.put_line(outvariable.age || ' ' || outvariable.name); end if; end loop; end;
--ref STRONG CURSORS DECLARE TYPE ecursor IS REF CURSOR RETURN emp%ROWTYPE; ecur ecursor; e_rec emp%ROWTYPE; dn NUMBER; BEGIN dn := &deptno; OPEN ecur FOR SELECT * FROM emp WHERE deptno = dn; FOR e_rec IN ecur LOOP DBMS_OUTPUT.PUT_LINE ('Employee No : ' || e_rec.empno); DBMS_OUTPUT.PUT_LINE ('Employee Salary: ' || e_rec.salary); END LOOP; END;
--REF WEAK CURSORS DECLARE TYPE tcursor IS REF CURSOR; tcur tcursor; e1 emp%ROWTYPE; d1 dept%ROWTYPE; tname VARCHAR2(20); BEGIN tname := &tablename; IF tname = 'emp' THEN OPEN tcur FOR SELECT * FORM emp; DBMS_OUTPUT.PUT_LINE ('Emp table opened.'); close tcur; DBMS_OUTPUT.PUT_LINE ('Emp table closed.'); ELSE IF tname = 'dept' THEN OPEN tcur FOR SELECT * FROM dept; DBMS_OUTPUT.PUT_LINE ('Dept table opened.'); close tcur; DBMS_OUTPUT.PUT_LINE ('Emp table closed.'); ELSE RAISE_APPLICATION_ERROR (-20004, 'Table name is wrong'); END IF; END;
--CURSOR FOR LOOP WITH PARAMETERS Declare Cursor c1(Dno number) is select * from emp where deptno = dno; begin for empree in c1(10) loop; dbms_output.put_line(empree.ename); end loop; end;
תגובות בפייסבוק