1.    Cấu trúc tuần tự
Thực hiện lần lượt từng lệnh một.
dbms_output.put_line('Excellent 1');
dbms_output.put_line('Excellent 2');
2.    Cấu trúc rẽ nhánh
Rẽ nhánh không đầy đủ (if) 
 | 
  
IF ename = 'SCOTT' THEN  
beam_me_up := 'YES';  
COMMIT;  
 | 
 
Rẽ nhánh đầy đủ (if…else) 
 | 
  
 IF sales > (quota + 200) THEN 
      bonus := (sales - quota)/4; 
   
  ELSE 
      bonus := 50; 
   
  END IF; 
---- 
IF monthly_value <= 4000 THEN 
ILevel := 'Low Income'; 
ELSIF monthly_value > 4000 and monthly_value <= 7000 THEN 
ILevel := 'Avg Income'; 
ELSIF monthly_value > 7000 and monthly_value <= 15000 THEN 
ILevel := 'Moderate Income'; 
ELSE 
ILevel := 'High Income'; 
END IF; 
 | 
 
Case 
 | 
  
CASE v_grade 
WHEN 'A' THEN dbms_output.put_line('Excellent'); WHEN 'B' THEN dbms_output.put_line('Very Good'); WHEN 'C' THEN dbms_output.put_line('Good'); WHEN 'D' THEN dbms_output.put_line('Fair'); WHEN 'F' THEN dbms_output.put_line('Poor'); ELSE dbms_output.put_line('Error: No such grade'); END CASE  | 
 
SELECT TRANS_DATE,CASE 
WHEN
  TRIM(TO_CHAR(trans_date,'DAY')) IN ('SATURDAY','SUNDAY') THEN 'weekend' 
ELSE 'weekday' 
END "Day Type" 
FROM transactions; 
 | 
 |
3.    Cấu trúc lặp
·        
LOOP không định trước
x := 0;  
y := 1000;  
LOOP  
x := x + 1;  
y := y - x;  
EXIT x > y;  
END LOOP;  
 | 
  |
·        
  Fetch 1 dòng dữ liệu dau tien từ cursor: (phải mở, đóng
  cursor) 
·        
  SET SERVEROUTPUT ON 
DECLARE 
CURSOR emp_cursor IS 
SELECT employee_id, last_name FROM
  employees 
WHERE department_id =30; 
empno employees.employee_id%TYPE; 
lname employees.last_name%TYPE; 
BEGIN 
OPEN emp_cursor; 
FETCH emp_cursor INTO empno,
  lname; 
DBMS_OUTPUT.PUT_LINE(empno ||'
  '||lname); 
CLOSE emp_cursor; 
END; 
/ 
 | 
  
Con trỏ emp_cursor trả về 6
  employees có department_id=30 nhưng câu lệnh FETCH sẽ lấy về chỉ 1 row, muốn
  lấy tất cả các row thì phải dùng vòng lặp (for) 
 | 
 
·        
  Fetch lấy all row từ cursor: LOOP...FETCH (phải
  mở, đóng cursor) 
DECLARE  
-- Khai báo cursor để
  truy vấn dữ liệu  
CURSOR c_Emp IS  
SELECT *  
FROM emp  
WHERE dept_id = 10;  
-- Khai báo biến
  cursor tương ứng để chứa dòng dữ liệu  
v_Emp c_EMP%rowtype;   -- v_Emp giống như kiểu record 
BEGIN  
-- Mở cursor  
OPEN c_Emp;  
LOOP  
-- Lấy dòng dữ liệu từ
  cursor  
FETCH c_Emp INTO
  v_Emp;  
-- Thoát khỏi vòng lặp
  nếu đã lấy hết dữ liệu trong cursor  
EXIT WHEN
  c_Emp%notfound;  
-- Bổ sung dữ liệu vào
  Emp_ext với dữ liệu lấy được từ cursor  
INSERT INTO Emp_ext
  (empno, ename, job) VALUES (v_Emp.empno, v_Emp.ename, v_Emp.job);  
END LOOP;  
-- Đóng cursor  
CLOSE c_Emp;  
END; 
REM ===================================c 
REM Grant on commit refresh system
  privilege to the owner of on  
REM commit refresh materialized
  view which references tables 
REM outside of the owner schema 
REM =================================== 
declare 
 
  owner varchar(30); 
 
  cursor c_mv_owner is 
     select distinct u.name 
        from sum$ s, sumdep$ d, obj$ o1, obj$
  o2, user$ u 
        where s.obj# = d.sumobj# and 
              bitand(s.mflags, 65536) != 0 and 
              d.p_obj# = o1.obj# and 
              s.obj# = o2.obj# and 
              o1.owner# != o2.owner# and 
              o2.owner# = u.user#; 
begin 
  
  open c_mv_owner; 
  
  loop 
     fetch c_mv_owner into owner; 
     exit when c_mv_owner%NOTFOUND; 
 
     execute immediate 'GRANT ON
  COMMIT REFRESH TO ' ||  
                      
  dbms_assert.enquote_name(owner, FALSE); 
  
  end loop; 
  
  close c_mv_owner; 
end; 
/ 
 | 
  
·        
FOR-LOOP: Loop đã định trước
declare 
   
  cursor c1 is select  distinct
  tablespace_name  from
  dba_data_files  where   tablespace_name like 'DATA200%' or
  tablespace_name like 'INDX200%' order by tablespace_name; 
begin 
   
  for r1 in c1 loop 
        dbms_output.put_line('SQL '''||'alter
  tablespace ' || r1.tablespace_name || ' read only'';'); 
        dbms_output.put_line('SQL '''||'alter
  tablespace ' || r1.tablespace_name || ' offline'';');         
   
  end loop; 
end; 
 | 
 
--
  Switch all existing users to new temp tablespace. 
BEGIN FOR cur_user IN (SELECT username FROM dba_users WHERE temporary_tablespace = 'TEMP') LOOP EXECUTE IMMEDIATE 'ALTER USER ' || cur_user.username || ' TEMPORARY TABLESPACE temp2'; END LOOP; END; 
-- Không sử dụng
  CURSOR 
BEGIN 
  FOR
  loop_emp IN 
  (SELECT * 
    FROM 
      employees 
    WHERE
  salary>15000) 
  LOOP 
    dbms_output.put_line('Number
  of rows processed: '||nvl(to_char(sql%rowcount),'Null')); 
  END LOOP
  loop_emp; 
END; 
 for r1 in (select trunc(completion_time) completion_time,
  round(sum(blocks*block_size)/1024/1024/1024,2) as archived_log_gb from
  V$ARCHIVED_LOG 
                        where
  trunc(completion_time) >= trunc(sysdate-7) 
                        --and
  trunc(completion_time)>= to_date(trunc(sysdate),'dd/mm/yyyy') 
                        and dest_id=1 
                        group by
  trunc(completion_time) 
                        order by
  trunc(completion_time) desc) loop 
                tAll:=tAll||'<tr> 
                            <td>'||r1.completion_time||'</td> 
                           
  <td>'||r1.archived_log_gb||'</td> 
                         </tr>' ; 
           end loop; 
           tAll:=tAll|| 
 | 
 
PROCEDURE           auto_drop_partition (v_date DATE) 
IS 
   
  date_num1        INT := 40;                         -- Chi luu giu 40
  ngay, PROM_CHARGE_DAILY_HIS 
   
  date_num2        INT := 70;                         -- Chi luu giu 40
  ngay, LOG_WS_999 
   
  date_num3        INT :=
  180;                        -- Chi luu
  giu 180 ngay, reg_sms_log 
   
  --date_num4        INT :=
  300;                        --log dau
  noi, Dungnd 
   
  CURSOR c_partition 
   
  IS 
        SELECT   table_name, partition_name 
          FROM   user_tab_partitions 
         WHERE   (sysdate -
  to_date(SUBSTR(partition_name,length(partition_name)-7,8),'yyyy/mm/dd') >
  date_num1 
                        AND table_name IN 
                           
  ('PROM_CHARGE_DAILY_HIS')) 
                       OR    
                        (sysdate - to_date(SUBSTR(partition_name,5,6),'yyyymm')
  > date_num2 
                        AND table_name IN 
                           
  ('LOG_PROCESS'))   
                      OR    
                       (sysdate -
  to_date(SUBSTR(partition_name,length(partition_name)-7,8),'yyyy/mm/dd') >
  date_num3 
                        AND table_name IN 
                            ('CP_SUM_LOG')) 
                       OR    
                        (sysdate -
  to_date(SUBSTR(partition_name,5,6),'yyyymm') > date_num3 
                        AND table_name IN 
                           
  ('REG_SMS_LOG'))   
                      OR 
                       (sysdate -
  to_date(SUBSTR(partition_name,length(partition_name)-7,8),'yyyy/mm/dd') >
  365 
                        AND table_name IN 
                            ('LOG_WS_999')) 
                       OR 
                       (sysdate -
  to_date(SUBSTR(partition_name,length(partition_name)-7,8),'yyyy/mm/dd') >
  365 
                        AND table_name IN 
                            ('SEND_999_LOG','SUB_TRANSACTION_LOG'))    ; 
   
  v_sql_command   VARCHAR2 (2400); 
BEGIN 
   
  -- add partitions 
   
  FOR v_data IN c_partition 
   
  LOOP 
        BEGIN 
            EXECUTE IMMEDIATE   ' Alter table ' 
                             || v_data.table_name 
                             || ' drop
  partition ' 
                             ||
  v_data.partition_name; 
        EXCEPTION 
            WHEN OTHERS 
            THEN 
                DBMS_OUTPUT.put_line
  (SQLERRM); 
        END; 
   
  END LOOP; 
END; 
 | 
 
-- Chạy cả khi exception 
declare   
   
  cursor c1 is  
        SELECT a.INST_ID,count(1)
  CountSession 
        FROM gv$session a, gv$process b   
        WHERE b.ADDR = a.paddr  
            AND a.inst_id=b.inst_id    
            and a.status='INACTIVE' 
            and A.USERNAME  in ('NEIF_OWNER') 
            and prev_exec_start > sysdate
  - 5/24*60 
            and type='USER'  
        group by a.inst_id; 
   
  cursor c2 is  
        SELECT 'ALTER SYSTEM KILL SESSION
  '''||a.sid||','||a.serial#||',@'||a.inst_id||''' immediate' sqltext,
  a.inst_id 
        FROM gv$session a, gv$process b   
        WHERE b.ADDR = a.paddr  
            AND a.inst_id=b.inst_id    
            and a.status='INACTIVE' 
            and A.USERNAME  in ('USER1_OWNER') 
            and prev_exec_start > sysdate
  - 5/24*60 
            and type='USER' order by
  a.inst_id;        
   
  vInst varchar2(20); 
   
  vSession number; 
begin 
     for r1 in c1 loop 
         begin 
            if r1.CountSession > 100 then 
                vInst:=r1.inst_id; 
               
  --dbms_output.put_line(vInst); 
                for r2 in c2 loop 
                    begin 
                        if r2.inst_id=vInst
  then 
                            dbms_output.put_Line(r2.sqltext); 
                            execute immediate
  r2.sqltext;                         
                        end if; 
                    EXCEPTION 
                        WHEN OTHERS
  THEN 
                           dbms_output.put_Line('Error
  but CONTINUE'); 
                           CONTINUE; 
                    end; 
                end loop;                 
            end if; 
         end; 
     end loop; 
     insert into dba_tc_logs (id, content)
  values (dba_tc_seq.nextval,'Complted to Kill NEIF_OWNER INACTIVE sesssions
  after 5 minutes'); 
     commit; 
end; -- Tạo dữ liệu test create table t (name1 varchar2(100), name2 varchar2(100)); alter table t rename to spct; declare      t number; begin      for t in 1..20000 loop           insert into spct values (Null,'a');           commit;      end loop; end; /  | 
 
·        
WHILE-LOOP
DECLARE 
countryid
  locations.country_id%TYPE := 'CA'; 
loc_id locations.location_id%TYPE; 
new_city locations.city%TYPE :=
  'Montreal'; 
counter NUMBER := 1; 
BEGIN 
SELECT MAX(location_id) INTO
  loc_id FROM locations 
WHERE country_id = countryid; 
WHILE counter <= 3 LOOP 
INSERT INTO locations(location_id,
  city, country_id) 
VALUES((loc_id + counter),
  new_city, countryid); 
counter := counter + 1; 
END LOOP; 
END; 
/ 
 | 
 
Notes:
·        
To exit a loop use the EXIT WHEN statement;
·        
To skip to the next iteration of the loop, use
the CONTINUE WHEN statement (Oracle
11g and above).
·        
Ngoài ra:
·        
Goto:
goto the_end; 
<<the_end>> 
dbms_output.put_line ('The End.');  |