1. PL/SQL
- Procedural Language extension to SQL
- SQL์ ํ์ฅํ ์ ์ฐจ์ ์ธ์ด(Procedural Language)
1-1. PL/SQL ํน์ง
- ์ข
๋ฅ : Procedure, Function, Trigger
- ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฌ์ฉ๋๋ Oracle์ ํ์ค ๋ฐ์ดํฐ ์์ธ์ค ์ธ์ด๋ก, ํ๋ก์์ ์์ฑ์๋ฅผ SQL๊ณผ ์๋ฒฝํ๊ฒ ํตํฉ
- ์ ์ ํ๋ก์ธ์ค๊ฐ PL/SQL ๋ธ๋ก์ ๋ณด๋ด๋ฉด, ์๋ฒ ํ๋ก์ธ์๋ PL/SQL Engine์์ ํด๋น ๋ธ๋ก์ ๋ฐ๊ณ SQL๊ณผ Procedural๋ฅผ ๋๋ ์ SQL์ SQL Statement Executer๋ก ๋ณด๋
- ์ค๋ผํด์์ ์ง์ํ๋ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ํน์ฑ์ ์์ฉ, SQL์์๋ ์ฌ์ฉํ ์ ์๋ ์ ์ฐจ์ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ด SQL์ ๋จ์ ์ ๋ณด์
1-2. PL/SQL ์ฅ์
- ํ๋ก์์ ์์ฑ์์ SQL์ ํตํฉ
- ์ ๋ง๋ค์ด์ง PL/SQL ๋ช
๋ น๋ฌธ์ ์ฑ๋ฅ ํฅ์
- ๋ชจ๋์ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ ๊ฐ๋ฅ : ๋
ผ๋ฆฌ์ ์ธ ์์
์ ์งํํ๋ ์ฌ๋ฌ ๋ช
๋ น์ด๋ค์ ํ๋์ ๋ธ๋ก์ผ๋ก ๋ง๋ค ์ ์์
- ์ด์์ฑ์ด ์ข์
- ์์ธ ์ฒ๋ฆฌ ๊ฐ๋ฅ
- ์๋์ SQL ๋จ์ ํด๊ฒฐ ๊ฐ๋ฅ
- ๋ณ์๊ฐ ์์
- ํ๋ฒ์ ํ๋์ ๋ช
๋ น๋ฌธ๋ง ์ฌ์ฉ ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ํธ๋ํฝ์ด ์๋์ ์ผ๋ก ์ฆ๊ฐ
- ์ ์ด๋ฌธ ์ฌ์ฉ ๋ถ๊ฐ (IF, LOOP)
- ์์ธ ์ฒ๋ฆฌ๊ฐ ์์
- ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ์ฐ์ฐํด์ผ ํ ๋, WAS๋ฑ์ ์๋ฒ๋ก ์ ์กํด์ ์ฒ๋ฆฌํ๋ ค๋ฉด ๋คํธ์ํฌ์ ๋ถํ๊ฐ ๋ง์ด ๊ฑธ๋ฆด ์ ์์ > ํ๋ก์์ ธ๋ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ฐ์ฐํ๊ณ ๊ฐ๊ณตํ ํ, ์ต์ข
๊ฒฐ๊ณผ๋ง ์๋ฒ์ ์ ์กํ๋ฉด ๋ถ๋ด์ ์ค์ผ ์ ์์
- ๋ก์ง ์์ ์ ์ํด ์๋ฒ๋ฅผ ์
ง๋ค์ด ์ํค์ง ์์๋ ๋จ(์๋ฒ์์๋ ๋จ์ํ DB์ ํ๋ก์์ ๋ฅผ ํธ์ถํ์ฌ ์ฌ์ฉํ๋ฉด ๋จ)
- ์ฟผ๋ฆฌ๋ฌธ์ ์ง์ ๋
ธ์ถํ์ง ์์ผ๋ฏ๋ก SQL injection์ ์ํ์ฑ์ด ์ค์ด๋ฆ
- ๋ธ๋ก ๋จ์๋ก ์ ์ฐํ๊ฒ ์ฌ์ฉํ ์ ์์
1-3. PL/SQL ๋จ์
- ์ ์ง๋ณด์๊ฐ ํ๋ฆ
- ๋์ฉ๋ ์ฒ๋ฆฌ๊ฐ ๋ง์ ๊ฒฝ์ฐ, DB์ ๋ถํ๋ฅผ ์ค ์ ์์
- Git ๊ฐ์ ํ์ ๊ด๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์
2. PL/SQL ๋ฌธ๋ฒ
- ๋ธ๋ก ๋จ์์ ์คํ์ ์ ๊ณต
- BEGIN๊ณผ END;๋ฅผ ์ฌ์ฉ
- ๋ง์ง๋ง ๋ผ์ธ์ /๋ฅผ ์
๋ ฅํ์ฌ ํด๋น ๋ธ๋ก์ด ์คํ๋๋๋ก ํจ
- ๋ณ์, ์์ ๋ฑ์ ์ ์ธํ์ฌ SQL๊ณผ ์ ์ฐจํ ์ธ์ด์์ ์ฌ์ฉ
- ๋ณ์ ์ ์ธ์ DECLARE ์ ์์๋ง ๊ฐ๋ฅ
- BEGIN ์น์
์์ ์ ๊ฐ์ด ํ ๋น๋ ์ ์์
- IF๋ฌธ์ ์ฌ์ฉํ์ฌ ๋ฌธ์ฅ๋ค์ ๋ถ๊ธฐ, LOOP๋ฌธ์ ์ฌ์ฉํ์ฌ ์ผ๋ จ์ ๋ฌธ์ฅ์ ๋ฐ๋ณต ๊ฐ๋ฅ
- ์ปค์๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ํ ๊ฒ์ ๋ฐ ์ฒ๋ฆฌ
- PL/SQL์์ ์ฌ์ฉ ๊ฐ๋ฅํ SQL : Query, DML, TCL
- DDL(CREATE, DROP, ALTER, TRUNCATE โฆ), DCL(GRANT, REVOKE) ๋ช
๋ น์ด๋ ๋์ SQL์ ์ด์ฉํ ๋๋ง ์ฌ์ฉ ๊ฐ๋ฅ
- PL/SQL์ SELECT๋ฌธ์ ํด๋น SELECT์ ๊ฒฐ๊ณผ๋ฅผ PL/SQL Engine์ผ๋ก ๋ณด๋ธ๋ค.
- ์ด๋ฅผ ์บ์นํ๊ธฐ ์ํ ๋ณ์๋ฅผ DECLARE ํด์ผ ํจ
- INTO ์ ์ ์ ์ธํ์ฌ ๋ฃ์ ๋ณ์๋ฅผ ๊ผญ ํํํด์ฃผ์ด์ผ ํจ
- SELECT ๋ฌธ์ฅ์ ๋ฐ๋์ ํ ๊ฐ์ ํ์ด ๊ฒ์๋์ด์ผ ํจ
- INTO์ ์ด ๋๋ฝ๋๊ฑฐ๋, ๊ฒ์๋๋ ํ์ด ์์ผ๋ฉด ์๋ฌ ๋ฐ์
- ํ ๋ฌธ์ฅ์ด ์ข
๋ฃํ ๋๋ง๋ค ์ธ๋ฏธ์ฝ๋ก (;)์ ์ฌ์ฉ, ํ ๋ฌธ์ฅ์ด ๋๋ฌ๋ค๋ ๊ฒ์ ๋ช
์
- ๋จ์ผํ ์ฃผ์ -- / ์ฌ๋ฌ ํ ์ฃผ์ /* */
2-1. PL/SQL ๊ตฌ์กฐ
2-1-1. DECLARE(์ ์ธ๋ถ)
- PL/SQL์์ ์ฌ์ฉํ๋ ๋ชจ๋ ๋ณ์๋ ์์๋ฅผ ์ ์ธํ๋ ๋ถ๋ถ
- ๋ณ์/์์/์ปค์ ๋ฑ์ ์ ์ธ
2-1-2. BEGIN(์คํ๋ถ)
- ์ ์ฐจ์ ํ์์ผ๋ก SQL๋ฌธ์ ์คํํ ์ ์๋๋ก ์ ์ฐจ์ ์ธ์ด์ ์์์ธ ์ ์ด๋ฌธ, ๋ฐ๋ณต๋ฌธ, ํจ์ ์ ์ ๋ฑ ๋ก์ง์ ๊ธฐ์
- ํ์์ ์ผ๋ก ์กด์ฌํด์ผ ํจ
2-1-3. EXCEPTION(์์ธ ์ฒ๋ฆฌ๋ถ)
- PL/SQL๋ฌธ์ด ์คํ๋๋ ์ค์ ๋ฐ์๋๋ ์๋ฌ(์์ธ ์ฌํญ)๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฌธ์ฅ์ ๊ธฐ์
2-1-4. END(์คํ๋ฌธ ์ข
๋ฃ)
- END ๋ค์ ์ธ๋ฏธ์ฝ๋ก (;)์ ์ฌ์ฉํ์ฌ ํ๋์ ๋ธ๋ก์ด ๋๋ฌ๋ค๋ ๊ฒ์ ๋ช
์
- ํ์์ ์ผ๋ก ์กด์ฌํด์ผ ํจ
2-2. PL/SQL Block์ ์ข
๋ฅ
- ์ต๋ช
๋ธ๋ก : ์ด๋ฆ์ด ์๋ PL/SQL Block
- ์ด๋ฆ ์๋ ๋ธ๋ก : DB์ ๊ฐ์ฒด๋ก ์ ์ฅ๋๋ ๋ธ๋ก
- ํ๋ก์์ : ๋ฆฌํด ๊ฐ์ ํ๋ ์ด์ ๊ฐ์ง ์ ์๋ ํ๋ก๊ทธ๋จ
- ํจ์ : ๋ฆฌํด ๊ฐ์ ๋ฐ๋์ ๋ฐํํด์ผ ํ๋ ํ๋ก๊ทธ๋จ
- ํจํค์ง : ํ๋ ์ด์์ ํ๋ก์์ , ํจ์, ๋ณ์, ์์ธ ๋ฑ์ ๋ฌถ์
- ํธ๋ฆฌ๊ฑฐ : ์ง์ ๋ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ์๋์ผ๋ก ์คํ๋๋ PL/SQL ๋ธ๋ก
3. ์ค์ต ์ค๋น
3-1. PL/SQL ๊ฒฐ๊ณผ ์ถ๋ ฅ
- PUT_LINE ํ๋ก์์ ๋ฅผ ์ด์ฉ
- ํ๋ก์์ ๋ฅผ ์ฌ์ฉํ์ฌ ์ถ๋ ฅ๋๋ ๋ด์ฉ์ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด์๋ ํ๊ฒฝ ๋ณ์ SERVEROUTPUT(๋ํดํธ๊ฐ์ด OFF์ด๋ฏ๋ก) ON์ผ๋ก ๋ณ๊ฒฝ
SET serveroutput ON
BEGIN
dbms_output.put_line('ynjch');
END;
3-2. ํ
์คํธ์ฉ ํ
์ด๋ธ ์ค๋น
- USER_INFO ํ
์ด๋ธ ์์ฑ
CREATE TABLE USER_INFO
(
USER_NUM NUMBER(10) NOT NULL
, USER_NM VARCHAR2(20)
, USER_BIRTH VARCHAR2(8)
, CONSTRAINT user_info_pk PRIMARY KEY(USER_NUM)
);
SELECT * FROM USER_INFO;
DROP TABLE USER_INFO;
- USER_INFO ํ
์ด๋ธ ์ํ์ค ์์ฑ
CREATE SEQUENCE USER_NUM_SEQ START WITH 1 INCREMENT BY 1 MAXVALUE 10000000 CYCLE NOCACHE;
- ์ํ์ค ์กฐํ ๋ฐ ์ด๊ธฐํ
SELECT * FROM USER_SEQUENCES WHERE SEQUENCE_NAME = 'USER_NUM_SEQ';
ALTER SEQUENCE USER_NUM_SEQ INCREMENT BY -1000;
SELECT USER_NUM_SEQ.NEXTVAL FROM DUAL;
ALTER SEQUENCE USER_NUM_SEQ INCREMENT BY 1;
- USER_SCORE ํ
์ด๋ธ ์์ฑ
CREATE TABLE USER_SCORE
(
USER_NUM NUMBER(10) NOT NULL
, USER_GRADE VARCHAR(5)
, CONSTRAINT user_score_pk PRIMARY KEY(USER_NUM)
);
SELECT * FROM USER_SCORE;
DROP TABLE USER_SCORE;
- USER_INFO ๋ฐ์ดํฐ INSERT
INSERT INTO USER_INFO values(USER_NUM_SEQ.NEXTVAL, '์ฐจ์์ฐ', '19971026');
INSERT INTO USER_INFO values(USER_NUM_SEQ.NEXTVAL, '๊ฐํ์ค', '19971001');
INSERT INTO USER_INFO values(USER_NUM_SEQ.NEXTVAL, '์๊ฐ์ค', '19911022');
INSERT INTO USER_INFO values(USER_NUM_SEQ.NEXTVAL, '์ก๊ฐ', '20010107');
INSERT INTO USER_INFO values(USER_NUM_SEQ.NEXTVAL, '๋ก์ด', '19710606');
INSERT INTO USER_INFO values(USER_NUM_SEQ.NEXTVAL, '๊น์ํ', '19970714');
INSERT INTO USER_SCORE values(1, 'A');
INSERT INTO USER_SCORE values(2, 'C');
INSERT INTO USER_SCORE values(3, 'A');
INSERT INTO USER_SCORE values(4, 'D');
INSERT INTO USER_SCORE values(5, 'B');
INSERT INTO USER_SCORE values(6, 'C');
- STORE_INFO ํ
์ด๋ธ ์์ฑ
CREATE TABLE STORE_INFO
(
STORE_NUM NUMBER(10) NOT NULL
, STORE_NM VARCHAR2(30)
, STORE_TEL VARCHAR2(20)
, STORE_ADDR VARCHAR2(30)
, OWNER_NUM NUMBER(10)
, CONSTRAINT store_info_pk PRIMARY KEY(STORE_NUM)
, CONSTRAINT store_info_fk FOREIGN KEY(OWNER_NUM) REFERENCES USER_INFO (USER_NUM)
);
SELECT * FROM STORE_INFO;
DROP TABLE STORE_INFO;
- STORE_INFO ํ
์ด๋ธ ์ํ์ค ์์ฑ
CREATE SEQUENCE STORE_NUM_SEQ START WITH 1 INCREMENT BY 1 MAXVALUE 10000000 CYCLE NOCACHE;
- ์ํ์ค ์กฐํ ๋ฐ ์ด๊ธฐํ
SELECT * FROM USER_SEQUENCES WHERE SEQUENCE_NAME = 'STORE_NUM_SEQ';
ALTER SEQUENCE STORE_NUM_SEQ INCREMENT BY -1000;
SELECT STORE_NUM_SEQ.NEXTVAL FROM DUAL;
ALTER SEQUENCE STORE_NUM_SEQ INCREMENT BY 1;
- ์ํ์ค ์ฆ๊ฐ ํจ์ ๋ง๋ค๊ธฐ
CREATE FUNCTION FUNC_STORE_NUM_SEQ RETURN NUMBER IS
BEGIN
RETURN STORE_NUM_SEQ.NEXTVAL;
END;
/
SELECT * FROM USER_SOURCE WHERE TYPE = 'FUNCTION' AND NAME = 'FUNC_STORE_NUM_SEQ';
DROP FUNCTION FUNC_STORE_NUM_SEQ;
- STORE_INFO ๋ฐ์ดํฐ INSERT
INSERT INTO STORE_INFO (STORE_NUM, STORE_NM, STORE_TEL, STORE_ADDR, OWNER_NUM)
SELECT FUNC_STORE_NUM_SEQ, '์ฝ์คํธ์ฝ ๋์ ์ ', '033-345-5751', '๋์ ์ ์ค๊ตฌ', 1 FROM DUAL
UNION ALL SELECT FUNC_STORE_NUM_SEQ, '๊ด๋ช
IKEA', '02-111-4453', '๊ฒฝ๊ธฐ๋ ๊ด๋ช
์', 2 FROM DUAL
UNION ALL SELECT FUNC_STORE_NUM_SEQ, '๊ต๋ณด๋ฌธ๊ณ ๊ดํ๋ฌธ์ ', '02-2341-4277', '์์ธ์ ์ข
๋ก๊ตฌ', 3 FROM DUAL
UNION ALL SELECT FUNC_STORE_NUM_SEQ, '์ ์ธ๊ณ ์๋ฑํฌ์ ', '02-3245-8775', '์์ธ์ ์๋ฑํฌ๊ตฌ', 5 FROM DUAL
UNION ALL SELECT FUNC_STORE_NUM_SEQ, '63๋น๋ฉ ์์ฟ ์๋ฆฌ์', '02-2341-4277', '์์ธ์ ์๋ฑํฌ๊ตฌ', 5 FROM DUAL;
COMMIT;
4. ๋ณ์
- ์ ์ธ๋ถ(DECLARE) ๋ณ์๋ช
, ๋ฐ์ดํฐ ํ์
์ ๊ธฐ์
- identifier : ๋ณ์๋ช
(์๋ณ์)
- CONSTANT : ์์๋ก ์ง์ (์ด๊ธฐ์น๋ฅผ ๋ฐ๋์ ํ ๋นํด์ผ ํจ)
- datatype : ์๋ฃํ์ ๊ธฐ์
- NOT NULL : ๊ฐ์ ๋ฐ๋์ ํฌํจ
- expression : Literal, ๋ค๋ฅธ ๋ณ์, ์ฐ์ฐ์๋ ํจ์๋ฅผ ํฌํจํ๋ ํํ์
identifier [CONSTANT] datatype [NOT NULL] [:=|DEFAULT expression];
4-1. ๋ณ์ ์ ์ธ
DECLARE NAME VARCHAR2(10);
DECLARE NAME VARCHAR2(10) := 'ynjch';
DECLARE NAME VARCHAR2(10) DEFAULT 'ynjch';
DECLARE
NAME VARCHAR2(20);
AGE NUMBER(2);
GENDER VARCHAR(5) DEFAULT '์ฌ';
4-2. Type์ผ๋ก ๋ณ์ ์ ์ธ
4-2-1. %ROWTYPE
- ํด๋น ํ
์ด๋ธ์ด๋ ๋ทฐ์ ์ปฌ๋ผ ์์ฑ์ ๊ทธ๋๋ก ๋ค๊ณ ์ค๋ ํํ
- ๋ณ์๋ช
ํ
์ด๋ธ๋ช
%ROWTYPE
DECLARE
userNum NUMBER(5) := 1;
rowData USER_INFO%ROWTYPE;
BEGIN
SELECT * INTO rowData
FROM USER_INFO
WHERE USER_NUM = userNum;
dbms_output.put_line(rowData.USER_NUM||'. '||rowData.USER_NM);
END;
4-2-2. %TYPE
- ํด๋น ํ
์ด๋ธ์ ์ปฌ๋ผ ์์ฑ์ ์ง์ ํ์ฌ ๊ทธ๋๋ก ๋ค๊ณ ์ค๋ ํํ
- ๋ณ์๋ช
ํ
์ด๋ธ๋ช
.์ปฌ๋ผ๋ช
%TYPE
DECLARE
userNum NUMBER(5) := 1;
userNm USER_INFO.USER_NM%TYPE;
userBirth USER_INFO.USER_BIRTH%TYPE;
BEGIN
SELECT
USER_NM, USER_BIRTH INTO userNm, userBirth
FROM USER_INFO
WHERE USER_NUM = userNum;
dbms_output.put_line(userNm||'('||userBirth||')');
END;
- SELECT ๋ฌธ์ ์ด์ฉํ์ฌ ๊ฐ ๋์
- INTO ์ ์ ์กฐํ ๊ฒฐ๊ณผ ๊ฐ์ ์ ์ฅํ ๋ณ์๋ฅผ ๊ธฐ์
- SELECT ๋ฌธ์ INTO ์ ์ ์ํด ํ๋์ ํ๋ง์ ์ ์ฅ ๊ฐ๋ฅ
- SELECT ์ดํ ์์ฑํ ์ปฌ๋ผ์ INTO ์ ์ ์๋ ๋ณ์์ 1:1๋ก ๋์ํด์ผ ํจ > ๊ฐ์์ ๋ฐ์ดํฐ ํ์
, ๊ธธ์ด๋ฅผ ์ผ์น์์ผ์ผ ํจ
5. ๋ฐ๋ณต๋ฌธ
- FOR LOOP๋ฌธ, LOOP๋ฌธ์ผ๋ก ๋๋จ
5-1. FOR LOOP๋ฌธ
- index๋ ์๋ ์ ์ธ๋๋ binary_integerํ ๋ณ์์ด๋ฉฐ 1์ฉ ์ฆ๊ฐ
- REVERSE ์ต์
์ด ์ฌ์ฉ ๋ ๊ฒฝ์ฐ index๋ upper_bound์์ lower_bound๋ก 1์ฉ ๊ฐ์
- IN ๋ค์์๋ coursor๋ SELECT ๋ฌธ์ด ์ฌ ์ ์์
FOR index in [REVERSE] ์์๊ฐ .. END๊ฐ LOOP
STATEMENT 1
STATEMENT 2
...
END LOOP;
5-1-1. ์์
- ์ง์, ํ์ ํ๋ณ
- IF๋ฌธ์ ์ฌ์ฉํ์ฌ ๋ถ๊ธฐ์ฒ๋ฆฌ
BEGIN
FOR i IN 1..5 LOOP
IF MOD(i,2) = 0 THEN
dbms_output.put_line(i||'๋ ์ง์');
ELSE
dbms_output.put_line(i||'๋ ํ์');
END IF;
END LOOP;
END;
- USER_NUM 1~3 ๊น์ง์ ๋ฐ์ดํฐ ์ถ๋ ฅํ๊ธฐ
DECLARE
userNum NUMBER(5) := 1;
rowData USER_INFO%ROWTYPE;
BEGIN
FOR i IN 1..3 LOOP
userNum := i;
SELECT * INTO rowData
FROM USER_INFO
WHERE USER_NUM = userNum;
dbms_output.put_line(rowData.USER_NM||'('||rowData.USER_NUM||')');
END LOOP;
END;
- SELECT ๋ฌธ์ ์ด์ฉํ์ฌ ๋ณ๋์ ๋ณ์ ์ ์ธ ์์ด ์ฌ์ฉ ๊ฐ๋ฅ
BEGIN
FOR userList IN (
SELECT * FROM USER_INFO
) LOOP
dbms_output.put_line(userList.USER_NM||'('||userList.USER_NUM||')');
END LOOP;
END;
- ๋์ ๋์ด ๋น๊ตํ๊ธฐ
DECLARE
userNum NUMBER(5) := 1;
rowData USER_INFO%ROWTYPE;
BEGIN
SELECT * INTO rowData
FROM USER_INFO
WHERE USER_NUM = userNum;
FOR userList IN (
SELECT * FROM USER_INFO WHERE USER_NUM <> userNum
) LOOP
IF ( SUBSTR(rowData.USER_BIRTH,1,4) = SUBSTR(userList.USER_BIRTH,1,4) ) THEN
dbms_output.put_line(userList.USER_NM||'์(๋) '||rowData.USER_NM||'์ ์น๊ตฌ');
ELSIF ( SUBSTR(rowData.USER_BIRTH,1,4) > SUBSTR(userList.USER_BIRTH,1,4) ) THEN
dbms_output.put_line(userList.USER_NM||'์(๋) '||rowData.USER_NM||'๋ณด๋ค ๋์ด๊ฐ ๋ง๋ค');
ELSE
dbms_output.put_line(userList.USER_NM||'์(๋) '||rowData.USER_NM||'๋ณด๋ค ๋์ด๊ฐ ์ ๋ค');
END IF;
END LOOP;
END;
5-1-2. ์์
- ํ
์ด๋ธ JOINํ์ฌ ์ ์ ๋ค์ ์ ์ ์กฐํํ๊ธฐ 1
- USER_INFO, USER_SCORE ํ
์ด๋ธ์ ์ปฌ๋ผ์ ๋ด์ ํธ๋์ญ์
GTT ์์ฑ(TX_USER_INFO_SCORE)
- WITH๋ฌธ, FOR LOOP๋ฌธ ์ฌ์ฉ
CREATE GLOBAL TEMPORARY TABLE TX_USER_INFO_SCORE (
USER_NUM NUMBER(10) NOT NULL
, USER_NM VARCHAR2(20)
, USER_BIRTH VARCHAR2(8)
, USER_GRADE VARCHAR(5)
)
ON COMMIT DELETE ROWS;
DECLARE
userCnt NUMBER;
rowData TX_USER_INFO_SCORE%ROWTYPE;
BEGIN
-- 1. userCnt ๊ตฌํ๊ธฐ
SELECT COUNT(1) INTO userCnt FROM USER_INFO;
dbms_output.put_line('userCnt : '||userCnt);
-- 2. for loop
FOR i IN 1..userCnt LOOP
WITH TEMP_USER_INFO_SCORE AS -- WITH ๋ฌธ
(
SELECT I.USER_NUM, I.USER_NM, I.USER_BIRTH, S.USER_GRADE
FROM USER_INFO I
LEFT JOIN USER_SCORE S
ON I.USER_NUM = S.USER_NUM
)
SELECT * INTO rowData FROM TEMP_USER_INFO_SCORE WHERE USER_NUM = i;
dbms_output.put_line(rowData.USER_NM ||'('|| rowData.USER_NUM ||')''s score : ' || rowData.USER_GRADE);
END LOOP;
END;
- ํ
์ด๋ธ JOINํ์ฌ ์ ์ ๋ค์ ์ ์ ์กฐํํ๊ธฐ 2
FOR [๋ณ์๋ช
] IN [์ฟผ๋ฆฌ] LOOP
์ฌ์ฉ
- WITH๋ฌธ, FOR LOOP๋ฌธ ์ฌ์ฉ
DECLARE
BEGIN
FOR userList IN (
WITH TEMP_USER_INFO_SCORE AS -- WITH ๋ฌธ
(
SELECT I.USER_NUM, I.USER_NM, I.USER_BIRTH, S.USER_GRADE
FROM USER_INFO I
LEFT JOIN USER_SCORE S
ON I.USER_NUM = S.USER_NUM
)
SELECT * FROM TEMP_USER_INFO_SCORE ORDER BY USER_NUM
) LOOP
dbms_output.put_line(userList.USER_NM ||'('|| userList.USER_NUM ||')''s score : ' || userList.USER_GRADE);
END LOOP;
END;
5-2. LOOP๋ฌธ
- EXIT : ๋ฌด์กฐ๊ฑด LOOP ๋ฌธ์ ๋น ์ ธ๋๊ฐ
- EXIT WHEN : WHEN ์ ์์ LOOP๋ฅผ ๋น ์ ธ๋๊ฐ๋ ์กฐ๊ฑด์ ์ ์ด
LOOP
STATEMENT 1
๋ค๋ฅธ LOOP๋ฅผ ํฌํจํ์ฌ ์ค์ฒฉ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅ
EXIT [WHEN CONDITION]
END LOOP;
5-2-1. ์์
- 1์์ 5๊น์ง ์ซ์ ์ถ๋ ฅํ๊ธฐ
DECLARE
startNum NUMBER := 1;
endNum NUMBER := 5;
loopCnt NUMBER := 0;
BEGIN
LOOP
dbms_output.put_line('ํ์ฌ ์ซ์ : '||startNum);
loopCnt := loopCnt + 1;
startNum := startNum + 1;
EXIT WHEN loopCnt >= endNum;
END LOOP;
dbms_output.put_line('๋ฐ๋ณต ํ์ : '||loopCnt);
END;
5-2-2. WHILE LOOP๋ฌธ
- 5-2-1. ์ ์์ ๋ฅผ WHILE LOOP๋ฌธ์ผ๋ก ํํ
DECLARE
startNum NUMBER := 1;
endNum NUMBER := 5;
loopCnt NUMBER := 0;
BEGIN
WHILE loopCnt < endNum LOOP
dbms_output.put_line('ํ์ฌ ์ซ์ : '||startNum);
loopCnt := loopCnt + 1;
startNum := startNum + 1;
END LOOP;
dbms_output.put_line('๋ฐ๋ณต ํ์ : '||loopCnt);
END;
6. ์ ์ด๋ฌธ
- ์ผ๋ฐ์ ์ธ ํ๋ก๊ทธ๋๋ฐ์์ ์ฌ์ฉ๋๋ IF๋ฌธ, CASE๋ฌธ ๋ฑ์ ์ ์ด๋ฌธ(์กฐ๊ฑด์ ) ์ฌ์ฉ ๊ฐ๋ฅ
6-1. IF๋ฌธ
- ELSE IF๋ฅผ ELSIF๋ก ์ฐ๋ ๊ฒ์ ์ฃผ์
IF ์กฐ๊ฑด1 THEN
์ฒ๋ฆฌ๋ฌธ1
ELSIF ์กฐ๊ฑด2 THEN
์ฒ๋ฆฌ๋ฌธ2
ELSE
์ฒ๋ฆฌ๋ฌธ
END IF;
6-1-1. ์์
DECLARE
userNum NUMBER := 1;
userBirthYear VARCHAR(4);
rowData USER_INFO%ROWTYPE;
BEGIN
SELECT * INTO rowData
FROM USER_INFO
WHERE USER_NUM = userNum;
userBirthYear := SUBSTR(rowData.USER_BIRTH, 1, 4);
IF (2022 - userBirthYear + 1) > 49 THEN
DBMS_OUTPUT.PUT_LINE(rowData.USER_NM||'๋์ 50์ธ ์ด์์
๋๋ค.');
ELSIF (2022 - userBirthYear + 1) > 29 THEN
DBMS_OUTPUT.PUT_LINE(rowData.USER_NM||'๋์ 30์ธ ์ด์์
๋๋ค.');
ELSIF (2022 - userBirthYear + 1) > 19 THEN
DBMS_OUTPUT.PUT_LINE(rowData.USER_NM||'๋์ 20์ธ ์ด์์
๋๋ค.');
ELSE
DBMS_OUTPUT.PUT_LINE(rowData.USER_NM||'๋์ 20์ธ ๋ฏธ๋ง์
๋๋ค.');
END IF;
END;
6-2. CASE๋ฌธ
- ์กฐ๊ฑด์ ๋ฐ๋ฅธ ๊ฐ์ ๋์
ํ๊ฑฐ๋, PL/SQL ๋ช
๋ น๋ฌธ ์คํ ์ ์ฌ์ฉ
6-2-1. ์์
DECLARE
userNum NUMBER := 1;
userGrade USER_SCORE.USER_GRADE%TYPE;
resultStr VARCHAR(30);
BEGIN
SELECT USER_GRADE INTO userGrade
FROM USER_SCORE
WHERE USER_NUM = userNum;
resultStr :=
CASE userGrade
WHEN 'A' THEN 'Perfect'
WHEN 'B' THEN 'Very Good'
WHEN 'C' THEN 'Good'
ELSE 'Hmm...'
END;
DBMS_OUTPUT.PUT_LINE(userGrade||' is '||resultStr);
END;
7. ์์ธ ์ฒ๋ฆฌ
- ์์คํ
์์ธ : Oracle์์ ์์ธ ์ํฉ์ ๋ํด ๋ฏธ๋ฆฌ ์ ์ํด๋์ ์์ธ
- ์ฌ์ฉ์ ์ ์ ์์ธ : ์์๋๋ ํน์ ์์ธ ์ํฉ์ ๋ํด ๊ฐ๋ฐ์๊ฐ ์ง์ ์ ์ํ ์์ธ
- ์ฒ๋ฆฌํ ์์ธ๋ค์ ์ฐจ๋ก๋ก ์ ์ธํ ๋ค, ๋ง์ง๋ง์ OTHERS๋ฅผ ์ ์ธํ์ฌ ๋๋จธ์ง ์์ธ๋ฅผ ์ฒ๋ฆฌํ๋๋ก ํจ
EXCEPTION WHEN [์์ธ๋ช
1] THEN [์์ธ์ฒ๋ฆฌ ๊ตฌ๋ฌธ1]
WHEN [์์ธ๋ช
2] THEN [์์ธ์ฒ๋ฆฌ ๊ตฌ๋ฌธ2];
7-1. ์์ธ ์ฒ๋ฆฌ
- ํ๋ก์์ ์คํ ํ ์์ธ๊ฐ ๋ฐ์ํ๋๋ผ๋ ๋ก์ง์ ์ ์ ์๋๋๋๋ก ์์ธ ์ฒ๋ฆฌ ๊ตฌ๋ฌธ ์์ฑ
CREATE OR REPLACE PROCEDURE PROC_TEST
IS
v_num NUMBER := 0;
BEGIN
v_num := 10/0;
EXCEPTION WHEN OTHERS THEN
dbms_output.put_line('์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค!');
dbms_output.put_line('์๋ฌ์ฝ๋ : ' || SQLCODE);
dbms_output.put_line('์๋ฌ๋ฉ์์ง : ' || SQLERRM);
dbms_output.put_line('๋งค๊ฐ๋ณ์ ์๋ ์๋ฌ๋ฉ์์ง : ' || SQLERRM(SQLCODE));
END;
/
EXEC PROC_TEST();
/* ๊ฒฐ๊ณผ
์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค!
์๋ฌ์ฝ๋ : -1476
์๋ฌ๋ฉ์์ง : ORA-01476: ์ ์๊ฐ 0 ์
๋๋ค
๋งค๊ฐ๋ณ์ ์๋ ์๋ฌ๋ฉ์์ง : ORA-01476: ์ ์๊ฐ 0 ์
๋๋ค */
7-2. ์์คํ
์์ธ
- Oracle์์ ์ง์ํ๋ ๋ํ์ ์์คํ
์์ธ ๋ชฉ๋ก
์์ธ๋ช
|
์์ธ ์ฝ๋ |
์ค๋ช
|
PROGRAM_ERROR |
ORA-06501 |
PL/SQL ์ฝ๋์์์ ๋ด๋ถ ์ค๋ฅ๋ฅผ ๋ง๋ฌ์ ๊ฒฝ์ฐ |
STORAGE_ERROR |
ORA-06500 |
ํ๋ก๊ทธ๋จ ์ํ ์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ถ์กฑํ ๊ฒฝ์ฐ |
TIMEOUT_ON_RESOURCE |
ORA-00051 |
๋ฐ์ดํฐ๋ฒ ์ด์ค ์์์ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ํ์์์ ๋ฐ์ ์ |
NO_DATA_FOUND |
ORA-01403 |
SELECT INTO ์ ๋ฐ์ดํฐ๊ฐ ํ ๊ฑด๋ ์์ ๊ฒฝ์ฐ |
TOO_MANY_ROWS |
ORA-01422 |
SELECT INTO ์ ์ฌ์ฉํ ๋ ๊ฒฐ๊ณผ๊ฐ ํ ๋ก์ฐ ์ด์์ผ ๋ |
VALUE_ERROR |
ORA-06502 |
์์น ๋๋ ๊ฐ ์ค๋ฅ |
ZERO_DIVIDE |
ORA-01476 |
0์ผ๋ก ๋๋ ๋ |
INVALID_NUMBER |
ORA-01722 |
๋ฌธ์๋ฅผ ์ซ์๋ก ๋ณํํ ๋ ์คํจํ ๊ฒฝ์ฐ |
DUP_VAL_ON_INDEX |
ORA-00001 |
์ ์ผ ์ธ๋ฑ์ค๊ฐ ์๋ ์ปฌ๋ผ์ ์ค๋ณต๊ฐ์ผ๋ก INSERT, UPDATE ์ํ |
CASE_NOT_FOUND |
ORA-06592 |
CASE๋ฌธ ์ฌ์ฉ ์ ๊ตฌ๋ฌธ ์ค๋ฅ |
ACCESS_INTO_NULL |
ORA-06530 |
LOB๊ณผ ๊ฐ์ ๊ฐ์ฒด ์ด๊ธฐํ ๋์ง ์์ ์ํ์์ ์ฌ์ฉ |
CURSOR_ALREADY_OPEN |
ORA-06511 |
์ปค์๊ฐ ์ด๋ฏธ OPEN ๋ ์ํ์ธ๋ฐ OPEN ํ๋ ค๊ณ ์๋ |
INVALID_CURSOR |
ORA-01001 |
์กด์ฌํ์ง ์๋ ์ปค์๋ฅผ ์ฐธ์กฐ |
NOT_LOGGED_ON |
ORA-01012 |
๋ก๊ทธ์จ๋์ง ์์๋๋ฐ DB๋ฅผ ์ฐธ์กฐํ ๋ |
LOGIN_DENIED |
ORA-01017 |
์๋ชป๋ ์ฌ์ฉ์ ์ด๋ฆ์ด๋ ๋น๋ฐ๋ฒํธ๋ก ๋ก๊ทธ์ธ์ ์๋ |
7-3. ์ฌ์ฉ์ ์ ์ ์์ธ
- ์
๋ ฅ ๋ฐ์ ๊ฐ์ด ์ ํจํ์ง ์์ ๊ฒฝ์ฐ ์์ธ ์ฒ๋ฆฌํ๋๋ก ํ๋ก์์ ๊ตฌ์ฑ
RAISE
: ์ง์ ์ ์ํ ์์ธ, ์์คํ
์์ธ๋ฅผ ๋ฐ์์ํค๊ธฐ ์ํด ์์ฑ
ex_not_exist_num EXCEPTION;
: ์ ์ธ๋ถ์ ์์ฑํ์ฌ ์์ธ๋ฅผ ์ ์
RAISE NO_DATA_FOUND;
: ์์คํ
์์ธ๋ฅผ ๋ฐ์์ํค๋๋ก ํจ
CREATE OR REPLACE PROCEDURE PROC_CHK_USER_NUM (p_user_num USER_INFO.USER_NUM%TYPE)
IS
v_cnt NUMBER := 0;
ex_not_exist_num EXCEPTION;
BEGIN
SELECT COUNT(1)
INTO v_cnt
FROM USER_INFO
WHERE USER_NUM = p_user_num;
-- ์
๋ ฅ ๋ฐ์ดํฐ์ ๋ฐ๋ฅธ ๊ฒฐ๊ณผ๊ฐ ์กฐ๊ฑด ์ฒ๋ฆฌ
IF p_user_num = 1 THEN
RAISE NO_DATA_FOUND;
ELSIF v_cnt > 0 THEN
dbms_output.put_line('๋ฑ๋ก๋ ์ฌ์ฉ์์
๋๋ค.');
ELSE
RAISE ex_not_exist_num;
END IF;
-- ์์ธ ์ฒ๋ฆฌ
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('NO_DATA_FOUND!!');
WHEN ex_not_exist_num THEN
dbms_output.put_line('๋ฑ๋ก๋ ์ฌ์ฉ์๊ฐ ์์ต๋๋ค.');
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
END;
/
-- ๊ฒฐ๊ณผ
EXEC PROC_CHK_USER_NUM(1); /* NO_DATA_FOUND!! */
EXEC PROC_CHK_USER_NUM(2); /* ๋ฑ๋ก๋ ์ฌ์ฉ์์
๋๋ค. */
EXEC PROC_CHK_USER_NUM(111); /* ๋ฑ๋ก๋ ์ฌ์ฉ์๊ฐ ์์ต๋๋ค. */
EXEC PROC_CHK_USER_NUM('YNJCH');
/* ORA-06502: PL/SQL: ์์น ๋๋ ๊ฐ ์ค๋ฅ: ๋ฌธ์๋ฅผ ์ซ์๋ก ๋ณํํ๋๋ฐ ์ค๋ฅ์
๋๋ค */
7-4. ์์ธ ๋ด์ฉ ํ์ธ
- Oracle์์ ๊ธฐ๋ณธ ์ ๊ณตํ๋ ๋นํธ์ธ(built-in) ํจ์ ์ด์ฉ
SQLCODE
: ์คํ๋ถ์์ ๋ฐ์ํ ์์ธ์ ํด๋นํ๋ ์ฝ๋๋ฅผ ๋ฐํ
SQLERRM
: ์์ธ์ ๋ํ ์ ๋ณด๋ฅผ ๋ด์ ๋ฉ์์ง ๋ฐํ
- ์์ธ ์ ๋ณด๋ฅผ ํ์ํ๊ธฐ ์ํด dbms_utility ์ด์ฉ
dbms_utility.format_call_stack
dbms_utility.format_error_stack
dbms_utility.format_error_backtrace
7-4-1. ํจ์จ์ ์ธ ์์ธ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ
- ์์คํ
์์ธ์ธ ๊ฒฝ์ฐ OTHERS ์ฌ์ฉ
- ์์ธ ์ฒ๋ฆฌ ๋ฃจํด์ ๊ณตํต ๋ชจ๋ํํ์ฌ, ์์ธ ๋ฐ์ ์ ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํ๋๋ก ํ
์ด๋ธ์ ๋ง๋ค์ด ๊ด๋ฆฌ
- ์ฌ์ฉ์ ์ ์ ์์ธ๋ ๋ณ๋ ํ
์ด๋ธ์ ๋ง๋ค์ด ๊ด๋ฆฌ