Sie sind auf Seite 1von 31

Definition A subquery is basically a select clause which is used instead of another statement.

For example : Have a look at the following 2 tables : DEPT and EMP

SQL> select * from dept order by deptno; DEPTNO ---------10 20 30 40 DNAME -------------ACCOUNTING RESEARCH SALES OPERATIONS LOC ------------NEW YORK DALLAS CHICAGO BOSTON

SQL> select empno,ename,job,sal,deptno from emp; EMPNO ---------7369 7499 7521 7566 7654 7698 7782 7788 7839 7844 7876 7900 7902 7934 ENAME ---------SMITH ALLEN WARD JONES MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER JOB SAL DEPTNO --------- ---------- ---------CLERK 800 20 SALESMAN 1600 30 SALESMAN 1250 30 MANAGER 2975 20 SALESMAN 1250 30 MANAGER 2850 30 MANAGER 2450 10 ANALYST 3000 20 PRESIDENT 5000 10 SALESMAN 1500 30 CLERK 1100 20 CLERK 950 30 ANALYST 3000 20 CLERK 1300 10

14 rows selected.

Simple Oracle subquery A simple subquery is evaluated once for each table. You would like to select all employees whose department is located in Chicago. A join would be a better solution for this select, but for the purposes of illustration we will use a subquery.

SQL> select empno,ename,job,sal,deptno from emp where

deptno in (select deptno from dept where loc = 'CHICAGO'); EMPNO ---------7900 7844 7698 7654 7521 7499 ENAME ---------JAMES TURNER BLAKE MARTIN WARD ALLEN JOB SAL DEPTNO --------- ---------- ---------CLERK 950 30 SALESMAN 1500 30 MANAGER 2850 30 SALESMAN 1250 30 SALESMAN 1250 30 SALESMAN 1600 30

6 rows selected.

You can use a subquery in the place of a table name in the 'from' clause.

SQL> Select ename, deptno from (select ename, deptno from emp where job = 'CLERK' ) where deptno > 20; ENAME DEPTNO ---------- ---------JAMES 30

You can even replace a column name with a subquery:


SQL> select ename, (select max(sal) from emp) "maxsal" , sal, ((select max(sal) from emp ) - sal ) "difference" from emp; ENAME maxsal SAL difference ---------- ---------- ---------- ---------SMITH 5000 800 4200 ALLEN 5000 1600 3400 WARD 5000 1250 3750 JONES 5000 2975 2025 MARTIN 5000 1250 3750 BLAKE 5000 2850 2150 CLARK 5000 2450 2550 SCOTT 5000 3000 2000 KING 5000 5000 0 TURNER 5000 1500 3500 ADAMS 5000 1100 3900

JAMES FORD MILLER 14 rows selected.

5000 5000 5000

950 3000 1300

4050 2000 3700

Correlated Oracle subquery A correlated Oracle subquery is evaluated once FOR EACH ROW as opposed to a normal subquery which is evaluated only once for each table. You can reference the outer query inside the correlated subquery using an alias which makes it so handy to use. Let's select all employees whose salary is less than the average of all the employees' salaries in the same department.
SQL> select ename ,sal ,deptno from emp a where a.sal < (select avg(sal) from emp b where a.deptno = b.deptno) order by deptno; ENAME SAL DEPTNO ---------- ---------- ---------CLARK 2450 10 MILLER 1300 10 SMITH 800 20 ADAMS 1100 20 WARD 1250 30 MARTIN 1250 30 TURNER 1500 30 JAMES 950 30 8 rows selected.

Using a correlated subquery in an update Let's give these people (whose salary is less than their department's average) a raise.

SQL> select ename, sal, deptno order by deptno, ename;

from emp

ENAME SAL DEPTNO ---------- ---------- ---------CLARK 2450 10 KING 5000 10 MILLER 1300 10 ADAMS 1100 20 FORD 3000 20 JONES 2975 20 SCOTT 3000 20 SMITH 800 20 ALLEN 1600 30 BLAKE 2850 30 JAMES 950 30 MARTIN 1250 30 TURNER 1500 30 WARD 1250 30 14 rows selected.

SQL>

UPDATE emp a set sal = (select avg(sal) from emp b where a.deptno = b.deptno) where sal < (select avg(sal) from emp c where a.deptno = c.deptno);

8 rows updated. SQL> select ename, sal, deptno order by deptno, ename; ENAME SAL DEPTNO ---------- ---------- ---------CLARK 2916.67 10 KING 5000 10 MILLER 2916.67 10 ADAMS 2175 20 FORD 3000 20 JONES 2975 20 SCOTT 3000 20 SMITH 2175 20 ALLEN 1600 30 BLAKE 2850 30 JAMES 1566.67 30 MARTIN 1566.67 30 TURNER 1566.67 30 WARD 1566.67 30 14 rows selected. SQL> commit; Commit complete. from emp

Using a correlated subquery in a delete Let's delete the highest earning employees in each department.

SQL>

delete from emp a where a.sal = (select max(sal) from emp b where a.deptno = b.deptno);

4 rows deleted. SQL> select ename, sal, deptno order by deptno, ename; ENAME SAL DEPTNO ---------- ---------- ---------CLARK 2916.67 10 MILLER 2916.67 10 ADAMS 2175 20 JONES 2975 20 SMITH 2175 20 ALLEN 1600 30 JAMES 1566.67 30 MARTIN 1566.67 30 TURNER 1566.67 30 WARD 1566.67 30 10 rows selected. SQL> commit; Commit complete. from emp

General
Data Dictionary Objects

dba_triggers System Privileges create trigger create any trigger administer database trigger alter any trigger drop any trigger

trigger$

all_triggers

user_triggers

Notes on Updatable Views An updatable view is one you can use to insert, update, or delete base table rows. You can create a view to be inherently updatable, or you can create an INSTEAD OF trigger on any view to make it updatable. To learn whether and in what ways the columns of an inherently updatable view can be modified, query the USER_UPDATABLE_COLUMNS data dictionary view. The information displayed by this view is meaningful only for inherently updatable views. For a view to be inherently updatable, the following conditions must be met: Each column in the view must map to a column of a single table. For example, if a view column maps to the output of a TABLE clause (an unnested collection), then the view is not inherently updatable. The view must not contain any of the following constructs: o A set operator o A DISTINCT operator o An aggregate or analytic function o A GROUP BY, ORDER BY, MODEL, CONNECT BY, or START WITH clause o A collection expression in a SELECT list o A subquery in a SELECT list o A subquery designated WITH READ ONLY o Joins, with some exceptions, as documented in Oracle Database Administrator's Guide In addition, if an inherently updatable view contains pseudocolumns or expressions, then you cannot update base table rows with an UPDATE statement that refers to any of these pseudocolumns or expressions. If you want a join view to be updatable, then all of the following conditions must be true: 1. The DML statement must affect only one table underlying the join. 2. For an INSERT statement, the view must not be created WITH CHECK OPTION, and all columns into which values are inserted must come from a key-preserved table. A keypreserved table is one for which every primary key or unique key value in the base table is also unique in the join view. 3. For an UPDATE statement, all columns updated must be extracted from a keypreserved table. If the view was created WITH CHECK OPTION, then join columns and columns taken from tables that are referenced more than once in the view must be shielded from UPDATE. For a DELETE statement, if the join results in more than one key-preserved table, then Oracle Database deletes from the first table named in the FROM clause, whether or not the view was created WITH CHECK OPTION.

Demo Tables
Instead Of Demo Tables And Constraints CREATE

TABLE employee (

employee_no last_name first_name

VARCHAR2(8), VARCHAR2(25) NOT NULL, VARCHAR2(10) NOT NULL,

dept_code active_flag mod_user_id mod_user_date

VARCHAR2(3) NOT NULL, VARCHAR2(1) DEFAULT 'Y', VARCHAR2(30) DEFAULT USER, DATE DEFAULT SYSDATE);

CREATE TABLE permission_code ( pcode VARCHAR2(2), pcode_description VARCHAR2(40) NOT NULL, mod_user_id VARCHAR2(30) DEFAULT USER, mod_user_date DATE DEFAULT SYSDATE); CREATE TABLE user_role ( dept_code VARCHAR2(3), pcode VARCHAR2(2), access_level VARCHAR2(1) DEFAULT 'R', mod_user_id VARCHAR2(30) DEFAULT USER, mod_user_date DATE DEFAULT SYSDATE); CREATE TABLE user_permission ( employee_no VARCHAR2(8), pcode VARCHAR2(2), access_level VARCHAR2(1) DEFAULT 'R', mod_user_id VARCHAR2(30) DEFAULT USER, mod_user_date DATE DEFAULT SYSDATE); CREATE TABLE dept_code ( dept_code VARCHAR2(3), dept_name VARCHAR2(30)); CREATE TABLE test ( test VARCHAR2(20)); Instead Of Trigger Demo Data -- employee table INSERT INTO employee (employee_no, last_name, first_name, dept_code, active_flag) VALUES ('5001', 'Mark', 'Townsend', 'LCR', 'Y'); INSERT INTO employee (employee_no, last_name, first_name, dept_code, active_flag) VALUES ('3996', 'Dacko', 'Carol', 'ESR', 'Y'); INSERT INTO employee (employee_no, last_name, first_name, dept_code, active_flag) VALUES ('6842', 'Morgan', 'Daniel', 'ADM', 'Y');

-- permission_code table data INSERT INTO permission_code VALUES ('BO', 'BILLING OPTIONS', USER, SYSDATE); INSERT INTO permission_code VALUES ('CL', 'CLASS CODES', USER, SYSDATE); INSERT INTO permission_code VALUES ('CR', 'CREWS', USER, SYSDATE); INSERT INTO permission_code VALUES ('CT', 'CREW TYPES', USER, SYSDATE); INSERT INTO permission_code VALUES ('CU', 'CUSTOMER TYPES', USER, SYSDATE); INSERT INTO permission_code VALUES ('DH', 'WORKORDER DASH NUMBERS', USER, SYSDATE); INSERT INTO dept_code (dept_code, dept_name) VALUES ('ADM', 'ADMINISTRATION'); INSERT INTO dept_code (dept_code, dept_name) VALUES ('COO', 'COORDINATOR'); INSERT INTO dept_code (dept_code, dept_name) VALUES ('ESE', 'ELECTRICAL SERVICE'); INSERT INTO dept_code (dept_code, dept_name) VALUES ('ESR', 'ELECTRICAL SERVICE REP'); INSERT INTO dept_code (dept_code, dept_name) VALUES ('ENG', 'ENGINEER'); INSERT INTO dept_code (dept_code, dept_name) VALUES ('LCR', 'LINE CREW'); INSERT INTO dept_code (dept_code, dept_name) VALUES ('MCR', 'METER CREW'); INSERT INTO dept_code (dept_code, dept_name) VALUES ('NWE', 'NETWORK ENGINEER'); INSERT INTO dept_code (dept_code, dept_name) VALUES ('SKA', 'SKETCH ARTIST'); INSERT INTO user_role

(dept_code, pcode, access_level) SELECT r.dept_code, p.pcode, 'R' FROM dept_code r, permission_code p; INSERT INTO user_permission (employee_no, pcode, access_level) SELECT e.employee_no, r.pcode, r.access_level FROM employee e, user_role r WHERE e.dept_code = r.dept_code; COMMIT;

Non Key-Preserved Relational Views


Build these views for later use in demonstrating Instead-Of Triggers --

word "view" used in naming for demo purposes only CREATE OR REPLACE VIEW role_permission_view AS SELECT r.dept_code, r.pcode, p.pcode_description, r.access_level FROM user_role r, permission_code p WHERE r.pcode = p.pcode; desc role_permission_view col data_type format a15 SELECT column_name, data_type, data_length FROM user_tab_cols WHERE table_name = 'ROLE_PERMISSION_VIEW'; col type format a30 SELECT column_name, nullable, data_type || '(' || data_length || ')' TYPE FROM user_tab_cols WHERE table_name = 'ROLE_PERMISSION_VIEW'; SELECT column_name, DECODE(nullable, 'N', 'NOT NULL', NULL) "Null?", data_type || '(' || data_length || ')' TYPE FROM user_tab_cols WHERE table_name = 'ROLE_PERMISSION_VIEW'; -- this will fail

INSERT INTO role_permission_view (dept_code, pcode, pcode_description, access_level) VALUES ('DAN', 'DM', 'Morgan', 'W'); -- this will fail too UPDATE role_permission_view SET access_level = 'W' WHERE dept_code = 'SKA'; -- another relational view CREATE OR REPLACE VIEW employee_permission_view AS SELECT e.employee_no, e.first_name || ' ' || e.last_name NAME, e.dept_code, r.pcode, r.access_level DEFACCLVL, u.access_level, p.pcode_description FROM employee e, user_role r, user_permission u, permission_code p WHERE e.dept_code = r.dept_code AND e.employee_no = u.employee_no AND r.pcode = u.pcode AND r.pcode = p.pcode ORDER BY 1,3; desc employee_permission_view SELECT column_name, DECODE(nullable, 'N', 'NOT NULL', NULL) "Null?", data_type || '(' || data_length || ')' TYPE FROM user_tab_cols WHERE table_name = 'EMPLOYEE_PERMISSION_VIEW'; SELECT * FROM employee_permission_view; -- this will fail too DELETE FROM employee_permission_view WHERE dept_code = 'LCR'; Instead Of Insert Trigger Demo CREATE OR REPLACE TRIGGER ioft_insert_role_perm INSTEAD OF INSERT ON role_permission_view FOR EACH ROW DECLARE x INTEGER; BEGIN SELECT COUNT(*) INTO x

FROM permission_code WHERE pcode = :NEW.pcode; IF x = 0 THEN INSERT INTO permission_code (pcode, pcode_description, mod_user_id, mod_user_date) VALUES (:NEW.pcode, 'New Code', USER, SYSDATE); END IF; SELECT COUNT(*) INTO x FROM dept_code WHERE dept_code = :NEW.dept_code; IF x = 0 THEN INSERT INTO dept_code (dept_code, dept_name) VALUES (:NEW.dept_code, 'New Dept'); END IF; INSERT INTO user_role (dept_code, pcode, mod_user_id) VALUES (:NEW.dept_code, :NEW.pcode, 'Morgan'); INSERT INTO test (test) VALUES ('Z'); END ioft_insert_role_perm; / SELECT * FROM permission_code WHERE pcode = 'DM'; SELECT * FROM dept_code WHERE dept_code = 'DAN'; SELECT * FROM user_role WHERE dept_code = 'DAN'; SELECT * FROM test;

-- insert works INSERT INTO role_permission_view (dept_code, pcode, pcode_description, access_level) VALUES ('DAN', 'DM', 'Morgan', 'W'); -- view results SELECT * FROM permission_code WHERE pcode = 'DM'; SELECT * FROM dept_code WHERE dept_code = 'DAN'; SELECT * FROM user_role WHERE dept_code = 'DAN'; SELECT * FROM test;
Instead Of Update Trigger Demo CREATE

OR REPLACE TRIGGER

ioft_role_perm INSTEAD OF UPDATE ON role_permission_view FOR EACH ROW BEGIN UPDATE user_role SET access_level = :NEW.access_level, mod_user_id = USER, mod_user_date = SYSDATE WHERE dept_code = :OLD.dept_code AND permission_code = :OLD.permission_code; END ioft_role_perm; / SELECT trigger_name, trigger_type, action_type, description FROM user_triggers; SELECT * FROM employee_permission_view; UPDATE role_permission_view SET access_level = 'W' WHERE dept_code = 'SKA'; SELECT * FROM employee_permission_view;

UPDATE employee_permission SET access_level = 'Z'; Instead Of Delete Trigger Demo /* what does it mean to delete LCR from employee_permission_view? Does it mean delete the LCR department from the dept_code table? Does it mean delete all employees that are in department LCR? Does it mean set to null the dept_code for employees in department LCR? */ SELECT * FROM employee_permission_view; SELECT * FROM dept_code; SELECT * FROM employee; -- let's delete the parent record and set the child to null -- and update two other columns CREATE OR REPLACE TRIGGER ioft_emp_perm INSTEAD OF DELETE ON employee_permission_view FOR EACH ROW BEGIN DELETE FROM dept_code WHERE dept_code = :OLD.dept_code; UPDATE employee SET dept_code = NULL, mod_user_id = USER, mod_user_date = SYSDATE WHERE dept_code = :OLD.dept_code; DELETE FROM test WHERE test = 'Z'; END ioft_emp_perm; / SELECT * FROM employee_permission_view; DELETE FROM employee_permission_view WHERE dept_code = 'LCR'; desc employee

DELETE FROM employee_permission_view WHERE dept_code = 'LCR';

Instead-Of Trigger with Referencing Clause


Referencing Clause with Nested Tables conn

scott/tiger

CREATE OR REPLACE TYPE emp_type AS OBJECT ( empno NUMBER(4), ename VARCHAR2(10), job VARCHAR2(9), mgr NUMBER(4), hiredate DATE, sal NUMBER(7, 2), comm NUMBER(7, 2)); / CREATE OR REPLACE TYPE emp_tab_type AS TABLE OF emp_type; / CREATE deptno dname loc emps / OR REPLACE TYPE dept_type AS OBJECT ( NUMBER(2), VARCHAR2(14), VARCHAR2(13), emp_tab_type);

CREATE OR REPLACE VIEW dept_or OF dept_type WITH OBJECT IDENTIFIER (deptno) AS SELECT deptno, dname, loc, CAST(MULTISET( SELECT empno, ename, job, mgr, hiredate, sal, comm FROM emp WHERE emp.deptno = dept.deptno) AS emp_tab_type) FROM dept; / CREATE OR REPLACE TRIGGER dept_emplist_tr INSTEAD OF UPDATE ON NESTED TABLE emps OF dept_or REFERENCING NEW AS NEW PARENT AS PARENT FOR EACH ROW BEGIN dbms_output.put_line('New: ' || :NEW.job); dbms_output.put_line('Parent: ' || :PARENT.dname); END;

/ set serveroutput on UPDATE TABLE ( SELECT p.emps FROM dept_or p WHERE deptno = 10) SET ename = LOWER(ename);

Object-Relational View Instead Of Trigger


Object View Instead Of Trigger --

demo table and data: See Object-

Relational Views INSERT INTO ov_empdept (empno, ename, dept) VALUES (4, 'D. Morgan', t_dept(7, 'MKT', 'Houston'));

CREATE OR REPLACE TRIGGER ioft_ov_empdept INSTEAD OF INSERT ON ov_empdept FOR EACH ROW BEGIN INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES (:NEW.empno, :NEW.ename, :NEW.job, :NEW.mgr, :NEW.hiredate, :NEW.sal, :NEW.comm, :NEW.dept.deptno); INSERT INTO dept (deptno, dname, location) VALUES (:NEW.dept.deptno, :NEW.dept.dname, :NEW.dept.location); END ioft_ov_empdept; / INSERT INTO ov_empdept (empno, ename, dept)

VALUES (4, 'D. Morgan', t_dept(7, 'MKT', 'Houston')); COMMIT;


-Constants DECLARE <constant name> CONSTANT <data type> := <value>; <constant name> CONSTANT <data type> DEFAULT <value>; BEGIN <valid statement>; EXCEPTION <exception handler>; END; / SET serveroutput ON DECLARE counter CONSTANT NUMBER(10,8) := 2; pi CONSTANT NUMBER(8,7) DEFAULT 3.1415926; BEGIN DBMS_OUTPUT.put_line(counter); DBMS_OUTPUT.put_line(pi); END; / --Variables DECLARE <variable name> <data type>; <variable name> CONSTANT <data type> := <value>; <variable name> CONSTANT <data type> NOT NULL := <value>; BEGIN <valid statement>; EXCEPTION <exception handler>; END; / SET serveroutput ON DECLARE counter NUMBER(10,8) := 2; pi NUMBER(8,7) := 3.1415926; test NUMBER(10,8) NOT NULL := 10; BEGIN counter := pi/counter; pi := pi/3; DBMS_OUTPUT.put_line(counter); DBMS_OUTPUT.put_line(pi); END; / REM REM CREATE stored functions required FOR the applications discussed IN REM "Developing Oracle Forms Applications."

REM PROMPT PROMPT CREATE the functions used BY the applicationS. PROMPT CREATE OR REPLACE FUNCTION Days_Between (first_dt second_dt DATE) DATE,

RETURN NUMBER IS dt_one NUMBER; dt_two NUMBER; BEGIN dt_one := TO_NUMBER(TO_CHAR(first_dt, 'DDD')); dt_two := TO_NUMBER(TO_CHAR(second_dt, 'DDD')); RETURN (dt_two - dt_one); END Days_Between; / CREATE OR REPLACE FUNCTION Compute_Movie_Revenue (from_dt to_dt DATE, movie_id NUMBER) RETURN NUMBER IS days NUMBER; revenue NUMBER := 0; CURSOR movie_rentals IS SELECT RETURN_DT, RENT_DT, DAILY_RATE FROM RENTALS WHERE RENT_DT >= from_dt AND RETURN_DT <= to_dt AND RENTALS.TAPE_ID IN ( SELECT TAPES.TAPE_ID FROM TAPES WHERE TAPES.MOVIE_ID = movie_id); BEGIN FOR rental IN movie_rentals LOOP days := Days_Between(rental.RENT_DT, rental.RETURN_DT); revenue := revenue + days * rental.DAILY_RATE; END LOOP; RETURN revenue; EXCEPTION WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20002, 'Movie revenue cannot be computed.'); END Compute_Movie_Revenue; / CREATE OR REPLACE FUNCTION Compute_Customer_Revenue (from_dt to_dt DATE, customer_id NUMBER) RETURN NUMBER IS DATE, DATE,

days revenue

NUMBER; NUMBER := 0;

CURSOR customer_rentals IS SELECT RETURN_DT, RENT_DT, DAILY_RATE FROM RENTALS WHERE RENT_DT >= from_dt AND RETURN_DT <= to_dt AND RENTALS.CUSTOMER_ID = customer_id; BEGIN FOR rental IN customer_rentals LOOP days := Days_Between(rental.RETURN_DT, rental.RENT_DT); revenue := revenue + days * rental.DAILY_RATE; END LOOP; RETURN revenue; EXCEPTION WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20001, Customer revenue cannot be computed.'); END Compute_Customer_Revenue; / CREATE OR REPLACE FUNCTION Get_Sequence_Id RETURN NUMBER IS seq_id NUMBER; BEGIN SELECT MRD_SEQ.NEXTVAL INTO seq_id FROM DUAL; RETURN seq_id; END; CREATE UNIQUE INDEX rb_call_activities_u1 ON rb_call_activities(tape_id,record_id) storage (initial 50m next 50m pctincrease 0) parallel (degree 4) tablespace rb_index02 / CREATE INDEX rb_call_activities_n2 ON rb_call_activities(tape_id,pre_status) storage (initial 50m next 50m pctincrease 0) parallel (degree 4) tablespace rb_index02 / CREATE INDEX rb_call_activities_n3 ON rb_call_activities(account_id) storage (initial 50m next 50m pctincrease 0) parallel (degree 4) tablespace rb_index02 / CREATE INDEX rb_call_activities_n4 ON rb_call_activities(billing_batch_id,account_id,agreement_id) storage (initial 50m next 50m pctincrease 0) parallel (degree 4)

tablespace rb_index02 / COMMIT; CREATE OR REPLACE PACKAGE test_pkg AS PROCEDURE add_test (col1_in NUMBER, col2_in CHAR); PROCEDURE del_test (col1_in NUMBER); END test_pkg; / CREATE OR REPLACE PACKAGE BODY test_pkg AS PROCEDURE add_test(col1_in IN NUMBER,col2_in IN CHAR) AS BEGIN INSERT INTO test VALUES (col1_in,col2_in); END add_test; PROCEDURE del_test(col1_in IN NUMBER) AS BEGIN DELETE FROM test WHERE col1_in = col1; END del_test; END test_pkg; /

Snippet Name: Create Sequence Description: This is the basic create statement for sequences. Comment: INCREMENT can be by any integer. START WITH can be any integer. If you set a max number and choose CYCLE the sequence will start again at your STARTWITH value. Language: Highlight Mode: PLSQL Last Modified: March 02nd, 2009
CREATE SEQUENCE test_seq INCREMENT BY 1 START WITH 1 NOMINVALUE NOMAXVALUE NOCYCLE NOCACHE NOORDER USE OF sequence

INSERT INTO test_table (fld1, fld2, fld3)

VALUES (test_seq.NEXTVAL, SYSDATE, 'somestring') After a sequence generates a VALUE BY using test_seq.NEXTVAL, you can USE test_seq.CURRVAL TO reuse that VALUE.

SELECT CURRENT_TIMESTAMP FROM dual; returns something LIKE 17-Sep-09 10.50.24.853421 PM -07:00 ADD_MONTHS(<date>, <number OF months_integer> SELECT ADD_MONTHS(SYSDATE, 2) FROM dual; SELECT ADD_MONTHS(TO_DATE('27-JAN-2007'), 1) FROM dual; SELECT ADD_MONTHS(TO_DATE('28-JAN-2007'), 1) FROM dual; SELECT ADD_MONTHS(TO_DATE('29-JAN-2007'), 1) FROM dual; SELECT ADD_MONTHS(TO_DATE('30-JAN-2007'), 1) FROM dual; SELECT ADD_MONTHS(TO_DATE('31-JAN-2007'), 1) FROM dual; SELECT ADD_MONTHS(TO_DATE('01-FEB-2007'), 1) FROM dual; INSERT INTO EMPLOYEE_TEMP (SELECT * FROM EMPLOYEE AS OF TIMESTAMP ('13-SEP-04 8:50:58','DD-MON-YY HH24: MI: SS')); -- alternate date format (mm/dd/yyy) INSERT INTO EMPLOYEE_TEMP (SELECT * FROM EMPLOYEE AS OF TIMESTAMP TO_TIMESTAMP('10/04/2008 11:00:00', 'MM/DD/YYYY HH24:MI:SS'));

-----

using the System Change Number: obtain the System Change Number before the transaction is initiated by using the GET_SYSTEM_CHANGE_NUMBER function of the DBMS_FLASHBACK utility:

SELECT DBMS_FLASHBACK. GET_SYSTEM_CHANGE_NUMBER FROM dual; -- recover the data using the SCN number: INSERT INTO EMPLOYEE_TEMP (SELECT * FROM EMPLOYEE AS OF SCN 10280403339);

-----

Using the DBMS_FLASHBACK package (prior to Oracle 9i release 2): use the ENABLE_AT_TIME function of the DBMS_FLASHBACK package to enter the flashback mode, followed by a DISABLE function to resume normal operation:

DECLARE CURSOR emp_cur IS SELECT * FROM EMPLOYEE; v_rec emp_cur%ROWTYPE; BEGIN DBMS_FLASHBACK.ENABLE_AT_TIME ('13-SEP-04 08:10:58'); OPEN emp_cur; DBMS_FLASHBACK.DISABLE; LOOP FETCH emp_cur INTO v_rec; EXIT WHEN emp_cur%NOTFOUND; INSERT INTO EMPLOYEE_TEMP VALUES (v_rec.emp_id, v_rec.name, v_rec.age ); END LOOP; CLOSE emp_cur; COMMIT; END; -- to use the SCN instead, change the ENABLE_AT_TIME line to this: DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER (10280403339); /* Notice that once we have entered into the flashback query mode, DML statements INSERT, UPDATE, or DELETE are not allowed until we exit flashback query mode by issuing DBMS_FLASHBACK.DISABLE. Because of this limitation the cursor for loop cannot be used in using the DBMS_FLASHBACK if we are using any of the above DML statements inside the loop. Also, Flashback mode can be entered only at the beginning of a transaction. If a DML statement has been issued, it must be committed before we can enter the flashback mode. */ Initialization Parameters Setting the location OF the flashback recovery area db_recovery_file_dest=/oracle/flash_recovery_area Setting the size OF the flashback recovery area db_recovery_file_dest_size=2147483648 Setting the retention TIME FOR flashback files (IN minutes) -- 2 days db_flashback_retention_target=2880 Turning flashback off AND ON -

ALTER database flashback off; ALTER database flashback ON; -------------------------------SET Retention Target IN minutes ALTER system SET DB_FLASHBACK_RETENTION_TARGET = 2880; START flashback ON a tablespace ALTER tablespace tblspc_test flashback ON; Stop flashback ON a tablespace ALTER TABLESPACE <tablespace_name> FLASHBACK OFF; ALTER tablespace tblspc_test flashback off; FORALL <index_name> IN <lower_boundary> .. <upper_boundary> CREATE TYPE books_nt IS TABLE OF book%ROWTYPE; / CREATE OR REPLACE PROCEDURE add_books ( books_in IN books_nt) IS BEGIN FORALL book_index IN books_in.FIRST .. books_in.LAST INSERT INTO book VALUES books_in(book_index); ... END; CREATE OR REPLACE FUNCTION time_diff(DATE_1 IN DATE, DATE_2 IN DATE) RETURN NUMBER IS NDATE_1 NUMBER; NDATE_2 NUMBER; NSECOND_1 NUMBER(5, 0); NSECOND_2 NUMBER(5, 0); BEGIN -- Get Julian date number from -- first date (DATE_1) NDATE_1 := TO_NUMBER(TO_CHAR(DATE_1, 'J')); -- Get Julian date number from -- second date (DATE_2) NDATE_2 := TO_NUMBER(TO_CHAR(DATE_2, 'J')); -- Get seconds since midnight -- from first date (DATE_1) NSECOND_1 := TO_NUMBER(TO_CHAR(DATE_1, 'SSSSS')); -- Get seconds since midnight -- from second date (DATE_2) NSECOND_2 := TO_NUMBER(TO_CHAR(DATE_2, 'SSSSS')); RETURN (((NDATE_2 - NDATE_1)*86400)+(NSECOND_2 - NSECOND_1));

END time_diff; /

CREATE OR REPLACE FUNCTION test1 (inparm IN NUMBER) RETURN NUMBER IS BEGIN RETURN inparm; END test1; / DESC user_plsql_object_settings SELECT name, TYPE, plsql_debug FROM user_plsql_object_settings; ALTER FUNCTION test1 COMPILE DEBUG;

ALTER ANY PROCEDURE CREATE ANY PROCEDURE CREATE PROCEDURE debug ANY PROCEDURE DROP ANY PROCEDURE EXECUTE ANY PROCEDURE -- these are granted and revokes by GRANT EXECUTE ON <function_name> TO <schema_name>;

- syntax: ALTER INDEX <index_name> - example: SELECT SUM(bytes), SUM(blocks) FROM user_extents WHERE segment_name = 'IDX_SALES_REGION'; ALTER INDEX idx_sales_region ALLOCATE EXTENT; SELECT SUM(bytes), SUM(blocks) FROM user_extents WHERE segment_name = 'IDX_SALES_REGION'; ALTER INDEX idx_sales_region ALLOCATE EXTENT; SELECT SUM(bytes), SUM(blocks) FROM user_extents WHERE segment_name = 'IDX_SALES_REGION'; ALTER INDEX idx_sales_region ALLOCATE EXTENT;

SELECT SUM(bytes), SUM(blocks) FROM user_extents WHERE segment_name = 'IDX_SALES_REGION'; ALTER INDEX idx_sales_region ALLOCATE EXTENT; ALTER INDEX idx_sales_region ALLOCATE EXTENT; ALTER INDEX idx_sales_region ALLOCATE EXTENT; SELECT SUM(bytes), SUM(blocks) FROM user_extents WHERE segment_name = 'IDX_SALES_REGION';

Recompile PACKAGE ALTER PACKAGE <package_name> COMPILE; SELECT object_name FROM user_objects WHERE object_type = 'PACKAGE'; ALTER PACKAGE test_pkg COMPILE; ====================== DROP PACKAGE Header AND BODY DROP PACKAGE test_pkg; ====================== DROP PACKAGE BODY Only DROP PACKAGE BODY test_pkg;

*+ hint */ /*+ hint(argument) */ /*+ hint(argument-1 argument-2) */ SELECT /*+ FIRST_ROWS(10) */ table_name FROM dba_tables WHERE owner = 'SYS' AND table_name LIKE '%$' ORDER BY 1; SELECT /*+ index(table_alias f_name) */ ... FROM TABLE.test table_alias -- Hint List: /*+ ALL_ROWS */

Explicitly chooses the cost-based approach TO optimize a statement block WITH a goal OF best throughput (that IS, minimum total resource consumption) /*+ CHOOSE */ Causes the optimizer TO choose BETWEEN the rule-based approach AND the cost-based approach FOR a SQL statement based ON the presence OF statistics FOR the tables accessed BY the statement /*+ FIRST_ROWS */ Explicitly chooses the cost-based approach TO optimize a statement block WITH a goal OF best response TIME (minimum resource usage TO RETURN FIRST ROW). It will also force the optimizer TO make USE OF INDEX, IF available. There are other versions OF FIRST_ROWS hints. This hint IS useful IN an OLTP environment WHEN the USER cannot wait till the LAST ROW IS fetched. This IS mainly used IN JAVA lookup screens. IF there are some calculations THEN this hint should NOT be used. Test your PL/SQL knowledge, Which code runs faster? /*+ RULE */ Explicitly chooses rule-based optimization FOR a statement block /*+ AND_EQUAL(table index) */ Explicitly chooses an execution plan that uses an access PATH that merges the scans ON several single-column indexes /*+ CLUSTER(table) */ Explicitly chooses a CLUSTER scan TO access the specified TABLE /*+ FULL(table) */ Explicitly chooses a full TABLE scan FOR the specified TABLE /*+ HASH(table) */ Explicitly chooses a hash scan TO access the specified TABLE /*+ HASH_AJ(table) */ Transforms a NOT IN sub query INTO a hash anti join TO access the specified TABLE /*+ HASH_SJ (table) */ Transforms a NOT IN sub query INTO a hash anti-join TO access the specified TABLE /*+ INDEX(table index) */ Explicitly chooses an INDEX scan FOR the specified TABLE

/*+ INDEX_ASC(table index) */ Explicitly chooses an ascending-RANGE INDEX scan FOR the specified TABLE /*+ INDEX_COMBINE(table index) */ IF no indexes are given AS arguments FOR the INDEX_COMBINE hint, the optimizer uses whatever BOOLEAN combination OF bitmap indexes has the best cost estimate. IF particular indexes are given AS arguments, the optimizer tries TO USE some BOOLEAN combination OF those particular bitmap indexes. /*+ INDEX_DESC(table index) */ Explicitly chooses a descending-RANGE INDEX scan FOR the specified TABLE /*+ INDEX_FFS(table index) */ Causes a fast full INDEX scan TO be performed rather than a full TABLE scan /*+ MERGE_AJ (table) */ Transforms a NOT IN sub query INTO a merge anti-join TO access the specified TABLE /*+ MERGE_SJ (table) */ Transforms a correlated EXISTS sub query INTO a merge semi-join TO access the specified TABLE /*+ ROWID(table) */ Explicitly chooses a TABLE scan BY ROWID FOR the specified TABLE /*+ USE_CONCAT */ Forces combined OR conditions IN the WHERE clause OF a query TO be transformed INTO a compound query using the UNION ALL SET OPERATOR /*+ ORDERED */ Causes Oracle TO join tables IN the ORDER IN which they appear IN the FROM clause /*+ STAR */ Forces the large TABLE TO be joined using a nested-LOOP join ON the INDEX /*+ DRIVING_SITE (table) */

Forces query execution TO be done AT a different site FROM that selected BY Oracle /*+ USE_HASH (table) */ Causes Oracle TO join each specified TABLE WITH another ROW source WITH a hash join /*+ USE_MERGE (table) */ Causes Oracle TO join each specified TABLE WITH another ROW source WITH a sort-merge join /*+ USE_NL (table) */ Causes Oracle TO join each specified TABLE TO another ROW source WITH a nested-loops join using the specified TABLE AS the inner TABLE /*+ APPEND */ , /*+ NOAPPEND */ Specifies that data IS simply appended (OR NOT) TO a TABLE; existing free SPACE IS NOT used. USE these hints only following the INSERT keyword. /*+ NOPARALLEL(table) */ Disables parallel scanning OF a TABLE, even IF the TABLE was created WITH a PARALLEL clause /*+ PARALLEL(table, instances) */ This allows you TO specify the desired NUMBER OF concurrent slave processes that can be used FOR the operation. DELETE, INSERT, AND UPDATE operations are considered FOR parallelization only IF the session IS IN a PARALLEL DML enabled MODE. (USE ALTER SESSION PARALLEL DML TO enter this MODE.) /*+ PARALLEL_INDEX */ Allows you TO parallelize fast full INDEX scan FOR partitioned AND non-partitioned indexes that have the PARALLEL attribute /*+ NOPARALLEL_INDEX */ Overrides a PARALLEL attribute setting ON an INDEX /*+ CACHE */ Specifies that the blocks retrieved FOR the TABLE IN the hint are placed AT the most recently used END OF the LRU list IN the buffer cache WHEN a full TABLE scan IS performed

/*+ NOCACHE */ Specifies that the blocks retrieved FOR this TABLE are placed AT the LEAST recently used END OF the LRU list IN the buffer cache WHEN a full TABLE scan IS performed /*+ MERGE (table) */ Causes Oracle TO evaluate complex views OR sub queries before the surrounding query /*+ NO_MERGE (table) */ Causes Oracle NOT TO merge mergeable views /*+ PUSH_JOIN_PRED (table) */ Causes the optimizer TO evaluate, ON a cost basis, whether OR NOT TO push individual join predicates INTO the VIEW /*+ NO_PUSH_JOIN_PRED (table) */ Prevents pushing OF a join predicate INTO the VIEW /*+ PUSH_SUBQ */ Causes non merged sub queries TO be evaluated AT the earliest possible place IN the execution plan /*+ STAR_TRANSFORMATION */ Makes the optimizer USE the best plan IN which the transformation has been used.

Free Oracle Magazine Subscriptions and Oracle White Papers

SQL University.net courses meet the most demanding needs of the business world for advanced education in a cost-effective manner. SQL University.net courses are available immediately for IT professionals and can be taken without disruption of your workplace schedule or processes.

Compared to traditional travel-based training, SQL University.net saves time and valuable corporate resources, allowing companies to do more with less. That's our mission, and that's what we deliver. Click here to find out more
SQL Loader Data Types CHAR DECIMAL EXTERNAL INTEGER EXTERNAL Modes APPEND INSERT REPLACE TRUNCATE INFILE INFILE * OR INFILE '<file_name>' [RECSIZE <integer> BUFFERS <integer>] INFILE 'mydata.dat' "RECSIZE 80 BUFFERS 8" INTO INTO <table_name> INTO TABLE emp BADFILE Records WITH formatting errors OR that cause Oracle errors BADFILE '<file_name>' BADFILE 'sample.bad' DISCARDFILE Records NOT satisfying a WHEN clause DISCARDFILE '<file_name>' DISCARDMAX <integer> DISCARDFILE 'sample.dsc' CHARACTERSET CHARACTERSET <character_set_name> CHARACTERSET WE8MSWIN1252 LENGTH LENGTH SEMANTICS <BYTE | CHAR> LENGTH SEMANTICS BYTE -- this is the default for all character sets except UTF16 LOAD TYPES APPEND INSERT REPLACE TRUNCATE APPEND OPTIONS CLAUSE BINDSIZE = n COLUMNARRAYROWS = n DIRECT = {TRUE | FALSE} ERRORS = n LOAD = n MULTITHREADING = {TRUE | FALSE} PARALLEL = {TRUE | FALSE} READSIZE = n RESUMABLE = {TRUE | FALSE} RESUMABLE_NAME = 'text string' RESUMABLE_TIMEOUT = n ROWS = n SILENT = {HEADER | FEEDBACK | ERRORS | DISCARDS | PARTITIONS | ALL} SKIP = n SKIP_INDEX_MAINTENANCE = {TRUE | FALSE} SKIP_UNUSABLE_INDEXES = {TRUE | FALSE} STREAMSIZE = n OPTIONS (BINDSIZE=100000, SILENT=(ERRORS, FEEDBACK))

PATHS CONVENTIONAL PATH DIRECT PATH ALL loads demonstrated below are convention WITH the EXCEPTION OF demo 6. TERMINATORS Comma ',' Tab 0x'09' TRAILING NULLCOLS TRAILING NULLCOLS -- assuming this data 10 Accounting -- the following INTO TABLE dept TRAILING NULLCOLS ( deptno CHAR TERMINATED BY " ", dname CHAR TERMINATED BY WHITESPACE, loc CHAR TERMINATED BY WHITESPACE) -- would generate an error without TRAILING NULLCOLS -- as it doesn't have loc data WHEN WHEN <condition> See Demo 5 below Assembling Logical Records CONCATENATE CONCATENATE <number_of_physical_records> CONCATENATE 3 CONTINUEIF CONTINUEIF THIS [PRESERVE] (start_position:end_position) = VALUE CONTINUEIF THIS (1:2) = '%%' CONTINUEIF THIS PRESERVE (1:2) = '%%' CONTINUEIF CONTINUEIF NEXT [PRESERVE] (start_position:end_position) = VALUE CONTINUEIF NEXT (1:2) = '%%' CONTINUEIF NEXT PRESERVE (1:2) = '%%' CONTINUEIF CONTINUEIF LAST (start_position:end_position) = VALUE -- Tests against the last non-blank character. -- Allows only a single character for the test PRESERVE Preserves the CONTINUEIF characters

SELECT object_name, created FROM user_objects WHERE ROWNUM < 11; clear screen short form cl scr

Column Separators SET colsep ',' SELECT * FROM user_tables WHERE ROWNUM < 5 /

Display Headers SELECT * FROM user_tables; SET head off SELECT * FROM user_tables; SET head ON

Line Size SET LINESIZE <integer> SELECT text FROM all_source WHERE ROWNUM < 11; SET linesize 121 SELECT text FROM all_source WHERE ROWNUM < 11; SELECT COUNT(*) FROM all_objects WHERE SUBSTR(object_name,1,1) BETWEEN 'A' AND 'W'; SET timing ON

envoke editor TO edit previous command ed

CREATE TABLE test2 ( id NUMBER(6), f_name VARCHAR2(25), l_name VARCHAR2(25));

Das könnte Ihnen auch gefallen