1. 程式人生 > >oracle筆記pl/sql流程控制

oracle筆記pl/sql流程控制

/*

pl/sql流程控制

*/

/*
查詢出 150號 員工的工資, 若其工資大於或等於 10000 則列印 'salary >= 10000'; 
若在 5000 到 10000 之間, 則列印 '5000<= salary < 10000'; 否則列印 'salary < 5000'
*/
DECLARE
v_salary employees.salary%TYPE;
BEGIN
  SELECT salary INTO v_salary FROM employees WHERE employee_id = 150;
  dbms_output.put_line('150號員工的薪水為' || v_salary);
  IF v_salary >= 10000 THEN dbms_output.put_line('salary >= 10000');
  ELSIF v_salary >= 5000 THEN dbms_output.put_line('5000<= salary < 10000');
  ELSE dbms_output.put_line('salary < 5000');
  END IF; --END IF;相當於java中的結束大括號,pl/sql中使用END IF關鍵字充當結束大括號
END;

--
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  IF v_salary >= 10000 THEN dbms_output.put_line('salary >= 10000');
  ELSIF v_salary >= 5000 THEN dbms_output.put_line('5000<= salary < 10000');
  ELSE dbms_output.put_line('salary < 5000');
  END IF; --END IF;相當於java中的結束大括號,pl/sql中使用END IF關鍵字充當結束大括號
END;


--另外一種寫法
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
v_temp VARCHAR2(50);
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  IF v_salary >= 10000 THEN v_temp := 'salary >= 10000';
  ELSIF v_salary >= 5000 THEN v_temp := '5000<= salary < 10000';
  ELSE  v_temp := 'salary < 5000';
  END IF; --END IF;相當於java中的結束大括號,pl/sql中使用END IF關鍵字充當結束大括號
  dbms_output.put_line('薪水=' || v_salary || ',' || v_temp);
END;

--改成case的寫法
/*
--以下這種寫法是錯誤的,會報錯
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
v_temp VARCHAR2(50);
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  v_temp :=
  CASE v_salary WHEN v_salary >= 10000 THEN  'salary >= 10000'
                WHEN v_salary >= 5000 THEN '5000<= salary < 10000'
  ELSE  'salary < 5000'
  END;
  dbms_output.put_line('薪水=' || v_salary || ',' || v_temp);             
END;

*/

--以下寫法正確
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
v_temp VARCHAR2(50);
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  v_temp :=
  CASE WHEN v_salary >= 10000 THEN  'salary >= 10000'
                WHEN v_salary >= 5000 THEN '5000<= salary < 10000'
  ELSE  'salary < 5000'
  END;
  dbms_output.put_line('薪水=' || v_salary || ',' || v_temp);             
END;

/*

--以下這種寫法是錯誤的,會報錯
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
v_temp VARCHAR2(50);
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  
  (CASE WHEN v_salary >= 10000 THEN  v_temp := 'salary >= 10000'
                WHEN v_salary >= 5000 THEN v_temp := '5000<= salary < 10000'
  ELSE v_temp := 'salary < 5000'
  END);
  dbms_output.put_line('薪水=' || v_salary || ',' || v_temp);             
END;

--以下這種寫法是錯誤的,會報錯
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
v_temp VARCHAR2(50);
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  
  CASE WHEN v_salary >= 10000 THEN  v_temp := 'salary >= 10000'
                WHEN v_salary >= 5000 THEN v_temp := '5000<= salary < 10000'
  ELSE v_temp := 'salary < 5000'
  END;
  dbms_output.put_line('薪水=' || v_salary || ',' || v_temp);             
END;

*/

--以下寫法正確
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
v_temp VARCHAR2(50);
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  v_temp :=
  (CASE WHEN v_salary >= 10000 THEN  'salary >= 10000'
                WHEN v_salary >= 5000 THEN '5000<= salary < 10000'
  ELSE  'salary < 5000'
  END);
  dbms_output.put_line('薪水=' || v_salary || ',' || v_temp);             
END;

--
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
v_temp VARCHAR2(50);
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  v_temp :=
  CASE trunc(v_salary / 5000) 
    WHEN 0 THEN  'salary < 5000'
    WHEN 1 THEN '5000<= salary < 10000'
    ELSE 'salary >= 10000'
  END;
  dbms_output.put_line('薪水=' || v_salary || ',' || v_temp);             
END;

--
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
v_temp VARCHAR2(50);
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  v_temp :=
  CASE WHEN v_salary >= 10000 THEN 'salary >= 10000'
                WHEN v_salary >= 5000 THEN '5000<= salary < 10000'
  ELSE 'salary < 5000'
  END;
  dbms_output.put_line('薪水=' || v_salary || ',' || v_temp);             
END;

--
DECLARE
v_salary employees.salary%TYPE;
v_employee_id employees.employee_id%TYPE;
v_temp VARCHAR2(50);
BEGIN
  v_employee_id := 150; --給v_employee_id變數賦值
  SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id; --使用v_employee_id變數
  dbms_output.put_line(v_employee_id || '號員工的薪水=' || v_salary);
  v_temp :=
  (CASE WHEN v_salary >= 10000 THEN 'salary >= 10000'
                WHEN v_salary >= 5000 THEN '5000<= salary < 10000'
  ELSE 'salary < 5000'
  END);
  dbms_output.put_line('薪水=' || v_salary || ',' || v_temp);             
END;




/*

以前的知識回顧

*/
--以下這2種寫法都可以
--
SELECT (CASE department_id WHEN 80 THEN '80號部門' WHEN 90 THEN '90號部門' END) FROM employees
--
SELECT (CASE WHEN department_id = 80 THEN '80號部門' WHEN department_id = 90 THEN '90號部門' END) FROM employees

--
SELECT job_id FROM employees

/*

回顧知識點 CASE... WHEN... THEN... WHEN... THEN... ELSE... END

*/

--以下寫法正確
SELECT (CASE job_id WHEN 'IT_PROG' THEN 'IT崗位' WHEN 'SA_REP' THEN '銷售崗位' END) FROM employees

--以下寫法錯誤,會報錯
SELECT (CASE salary WHEN salary >= 5000  THEN '薪水大於5000' WHEN salary < 5000 THEN '薪水小於5000' END) FROM employees

--以下寫法正確
SELECT (CASE WHEN salary >= 5000  THEN '薪水大於5000' WHEN salary < 5000 THEN '薪水小於5000' END) FROM employees

--以下寫法錯誤
SELECT (CASE WHEN salary >= 5000  THEN salary = 10 WHEN salary < 5000 THEN salary = 20 END) FROM employees

--以下寫法正確
SELECT (CASE salary WHEN 24000  THEN '薪水等於24000' WHEN 8000 THEN '薪水等於8000' END) FROM employees


--以下寫法正確
SELECT (CASE salary WHEN 24000  THEN '薪水等於24000' WHEN 8000 THEN '薪水等於8000' ELSE 'hello world' END) FROM employees

--以下寫法正確
SELECT salary, (CASE salary WHEN 24000  THEN salary + 10 WHEN 8000 THEN salary + 20 ELSE salary + 30 END) FROM employees

--以下寫法錯誤,會報錯
SELECT salary, (CASE salary WHEN 24000  THEN salary = salary + 10 WHEN 8000 THEN salary = salary + 20 ELSE salary = salary + 30 END) FROM employees

--以下寫法錯誤,會報錯
SELECT salary, (CASE salary WHEN 24000  THEN salary = 10 WHEN 8000 THEN salary = 20 ELSE salary = 30 END) FROM employees

SELECT * FROM employees


-----------------------------------------
/*
查詢出 122 號員工的 JOB_ID, 若其值為 'IT_PROG', 則列印 'GRADE: A'; 
'AC_MGT', 列印 'GRADE B', 
'AC_ACCOUNT', 列印 'GRADE C'; 
否則列印 'GRADE D'
*/
--使用if ELSIF 
DECLARE 
v_job_id employees.job_id%TYPE;
v_grade VARCHAR2(50);
BEGIN
  SELECT job_id INTO v_job_id FROM employees WHERE employee_id = 122;
  IF v_job_id = 'IT_PROG' THEN v_grade := 'GRADE: A';
  ELSIF v_job_id = 'AC_MGT' THEN v_grade := 'GRADE: B';
  ELSIF v_job_id = 'AC_ACCOUNT' THEN v_grade := 'GRADE: C';
  ELSE v_grade := 'GRADE: D';
  END IF;
  dbms_output.put_line(v_job_id || ' ,grade = ' || v_grade);
END;

--使用CASE WHEN THEN
DECLARE 
v_job_id employees.job_id%TYPE;
v_grade VARCHAR2(50);
BEGIN
 SELECT job_id INTO v_job_id FROM employees WHERE employee_id = 122;
 v_grade := 
 CASE v_job_id 
   WHEN 'IT_PROG' THEN 'A'
   WHEN 'AC_MGT' THEN 'B'
   WHEN 'AC_ACCOUNT' THEN 'C'
   ELSE 'D'
 END;
 dbms_output.put_line(v_job_id || ' , ' || v_grade);
END;
 
 
/*

迴圈知識點

*/  

--使用迴圈列印數字1-100
-- 1初始化條件  2迴圈體  3迴圈條件  4迭代條件 
DECLARE
--1
v_number NUMBER(6) := 1;--定義一個變數並賦值 (:=是賦值符號)
BEGIN
  LOOP 
    --2
    dbms_output.put_line('數字' || v_number);
    --3
  EXIT WHEN v_number > 100;
  --4
  v_number := v_number + 1;
  END LOOP;
END;

--
DECLARE
v_number NUMBER(6) := 1;
BEGIN
  LOOP 
    dbms_output.put_line('數字' || v_number);
  EXIT WHEN v_number >= 100;
  v_number := v_number + 1; -- 可以放在這裡
  END LOOP;
END;

--以下這樣寫也可以
DECLARE
v_number NUMBER(6) := 1;
BEGIN
  LOOP 
    dbms_output.put_line('數字' || v_number);
    v_number := v_number + 1; --也可以放在這裡
  EXIT WHEN v_number >= 100;
  END LOOP;
  
END;

--
DECLARE
v_number NUMBER(6) := 1;
BEGIN
  LOOP 
    dbms_output.put_line('數字' || v_number);
    v_number := v_number + 1; --
  EXIT WHEN v_number > 100;
  END LOOP;
  
END;

--
DECLARE
v_number NUMBER(6) := 1;
BEGIN
  LOOP 
    dbms_output.put_line('數字' || v_number);
    v_number := v_number + 1; --
  EXIT WHEN v_number > 100;
  END LOOP;
  
END;


--第二種迴圈方式 while
DECLARE
v_number NUMBER(6) := 1;
BEGIN
 WHILE v_number <= 100 LOOP
   dbms_output.put_line('數字' || v_number);
   v_number := v_number + 1;
   END LOOP;
END;

/*
每迴圈一次,迴圈變數自動加1;使用關鍵字REVERSE,迴圈變數自動減1。
跟在IN REVERSE 後面的數字必須是從小到大的順序,而且必須是整數,
不能是變數或表示式。可以使用EXIT 退出迴圈
*/

--第三種迴圈方式 for迴圈
BEGIN
  FOR mynumber IN 1..100 LOOP
   dbms_output.put_line('數字' || mynumber); 
   END LOOP;
END;

--使用REVERSE(反轉)關鍵字
BEGIN
  FOR mynumber IN REVERSE 1..100 LOOP
   dbms_output.put_line('數字' || mynumber);
   END LOOP;
END;

--null語句
/*
NULL:在PL/SQL 程式中,可以用 null 語句來說明“不用做任何事情”的意思,相當於一個佔位符,可以使某些語句變得有意義,提高程式的可讀性
*/
--從employees表中查資料,如果薪水大於20000,則列印'土豪,我們做個朋友吧',如果薪水小於20000,不做任何處理
DECLARE v_salary employees.salary%Type ; 
BEGIN 
SELECT salary INTO v_salary FROM employees WHERE employee_id = 100; 
IF v_salary > 20000 THEN dbms_output.put_line('土豪,我們做個朋友吧');
ELSE NULL; --null語句
END IF; 
END;

--
SELECT SQRT(2), SQRT(3), SQRT(4), SQRT(16), SQRT(9), SQRT(36) FROM dual;
SELECT MOD(4, 2), MOD(36, 4), MOD(25, 6) FROM dual;
--

/*

輸出2-100之間的質數 (java的面試中很多時候都會考這道題目,不光可以考察多層巢狀迴圈,還可以考察break、sqrt()函式、
小演算法、條件判斷結構、效率效能等等知識點,而且題目還不算太大太難,所以大家最好要會寫)

*/
--使用while寫法
DECLARE
  V_I    NUMBER(5) := 2;
  V_J    NUMBER(5) := 2;
  V_FLAG NUMBER(1) := 1;
BEGIN
  WHILE V_I <= 100 LOOP
    WHILE V_J <= SQRT(V_I) LOOP
      IF MOD(V_I, V_J) = 0 THEN
        V_FLAG := 0;
      END IF;
      V_J := V_J + 1;
    END LOOP;
    IF V_FLAG = 1 THEN
      DBMS_OUTPUT.PUT_LINE('質數' || V_I);
    END IF;
    V_I    := V_I + 1;
    V_FLAG := 1;
   -- V_J    := 2; --這行程式碼註釋掉就無法求出正確的質數
   V_J    := 2;
  END LOOP;
  DBMS_OUTPUT.PUT_LINE('內層迴圈的V_J=' || V_J);
END;

--使用for迴圈的寫法,如下
DECLARE
  V_FLAG NUMBER(1) := 1;
  V_COUNT NUMBER(10) := 0;
BEGIN
  FOR i IN 2..100 LOOP
    
   FOR j IN 2..sqrt(i) LOOP 
     IF(MOD(i, j) = 0) THEN V_FLAG := 0;
     END IF;
     END LOOP;
     IF(V_FLAG = 1) THEN dbms_output.put_line('質數' || i);
     V_COUNT := V_COUNT + 1; --統計有幾個質數
     END IF;
     V_FLAG := 1;
   END LOOP;
   dbms_output.put_line('共有' || V_COUNT || '個質數');
END;

--改進上面的程式碼,使效率更高
DECLARE
  V_FLAG NUMBER(1) := 1;
  V_COUNT NUMBER(10) := 0;
BEGIN
  FOR i IN 2..100 LOOP
    
   FOR j IN 2..sqrt(i) LOOP 
     IF(MOD(i, j) = 0) THEN V_FLAG := 0;
     --PL/SQL中GOTO語句是無條件跳轉到指定的標號去的意思
     GOTO LABEL; --(這裡使用GOTO提高了效率效能)
     END IF;
     END LOOP;
     <<LABEL>>
     IF(V_FLAG = 1) THEN dbms_output.put_line('質數' || i);
     V_COUNT := V_COUNT + 1; --統計有幾個質數
     END IF;
     V_FLAG := 1;
   END LOOP;
   dbms_output.put_line('共有' || V_COUNT || '個質數');
END;

--使用 goto
--列印1——100的自然數,當列印到50時,跳出迴圈,輸出“列印結束”
--方式1
DECLARE
v_number NUMBER(5) := 100; --賦值
BEGIN
  FOR mynumber IN 1.. v_number LOOP
    IF mynumber = 50 THEN GOTO LABEL;
    END IF;
    dbms_output.put_line('自然數' || mynumber);
  END LOOP;
  <<LABEL>>
  dbms_output.put_line('列印結束');
END;

--
BEGIN
  FOR I IN 1 .. 100 LOOP
    DBMS_OUTPUT.PUT_LINE(I);
    IF (I = 50) THEN
      GOTO LABEL;
    END IF;
  END LOOP;

  <<LABEL>>
  DBMS_OUTPUT.PUT_LINE('列印結束');

END;

--方式2(使用exit關鍵字)
DECLARE
v_number NUMBER(5) := 100; --賦值
BEGIN
  FOR mynumber IN 1.. v_number LOOP
    IF mynumber = 50 THEN dbms_output.put_line('列印結束'); 
      EXIT; --使用exit關鍵字
    END IF;
    dbms_output.put_line('自然數' || mynumber);
  END LOOP;
END;

--(使用exit關鍵字)
DECLARE
v_number NUMBER(5) := 100; --賦值
BEGIN
  FOR mynumber IN 1.. v_number LOOP
    IF mynumber = 50 THEN EXIT; --使用exit關鍵字 
    END IF;
    dbms_output.put_line('自然數' || mynumber);
  END LOOP;
  dbms_output.put_line('列印結束');
END;