2. WHILE LOOP 문
- 조건이 TRUE인 동안 반복 작업을 수행하는 문

DECLARE
    i number := 1;
BEGIN
    WHILE i <= 10 LOOP
        DBMS_OUTPUT.PUT_LINE(i);
        i := i + 1;
    END LOOP;
END;
/

 

[문제] 1부터 10까지 출력해주세요. 단, 4,8 제외

DECLARE
    i number := 0;
BEGIN
    WHILE i < 10 LOOP
        i := i + 1;
        CONTINUE WHEN i IN (4,8);
        DBMS_OUTPUT.PUT_LINE(i);
    END LOOP;
END;
/

 

[문제] 1부터 100까지 합을 출력해주세요.

DECLARE
    i number := 1;
    total number := 0;

BEGIN
    WHILE i <= 100 LOOP
        total := total + i;
        i := i + 1;
    END LOOP;

    DBMS_OUTPUT.PUT_LINE('1부터 100까지 합 : '||total);
END;
/

 

 

3. FOR 
- 반복횟수를 알고 있을 때 사용하는 루프문

BEGIN
    FOR i IN 1..10 LOOP     -- i : 카운트용으로 선언없이 사용가능
        DBMS_OUTPUT.PUT_LINE(i);
    END LOOP;
END;
/

 

BEGIN
    FOR i IN 1..10 LOOP
        CONTINUE WHEN i = 4;
        DBMS_OUTPUT.PUT_LINE(i);
        EXIT WHEN i = 5;
    END LOOP;
END;
/

 

DECLARE
    v_start number := 1;
    v_end number := 10;
BEGIN
    FOR i IN v_start..v_end LOOP
        DBMS_OUTPUT.PUT_LINE(i);
    END LOOP;
END;
/

 

[문제] 1부터 10까지 출력해주세요. 단, 4,8 제외

BEGIN
    FOR i IN 1..10 LOOP
        CONTINUE WHEN i IN (4,8);
        DBMS_OUTPUT.PUT_LINE(i);
    END LOOP;
END;
/

 

[문제] 구구단 2단 출력.
1) 기본 LOOP
DECLARE
    num number := 1;
BEGIN
    LOOP
        DBMS_OUTPUT.PUT_LINE('2 * '||num||' = '||2 * num);
        num := num + 1;
        EXIT WHEN num = 10;
    END LOOP;
END;
/
2) WHILE LOOP
DECLARE
    num number := 1;
BEGIN
    WHILE num < 10 LOOP
        DBMS_OUTPUT.PUT_LINE('2 * '||num||' = '||2 * num);
        num := num + 1;
    END LOOP;
END;
/
3) FOR LOOP
BEGIN
    FOR i IN 1..9 LOOP
        DBMS_OUTPUT.PUT_LINE('2 * '||i||' = '||2 * i);
    END LOOP;
END;
/

 

 

# 중첩 반복문

[문제] 구구단 출력. 
1) 기본 LOOP
DECLARE
    dan number := 2;
    j number;
BEGIN
    LOOP            -- 단 반복
        J := 1;
        
        LOOP            -- 지수 반복
            DBMS_OUTPUT.PUT_LINE(dan||' * '||j||' = '||dan * j);
            EXIT WHEN j= 9;
            j := j + 1;
        END LOOP;
        
        EXIT WHEN dan= 9;
        dan := dan + 1;
        DBMS_OUTPUT.PUT_LINE('');
    END LOOP;
END;
/
2) WHILE LOOP
DECLARE
    dan number := 2;
    j number;
BEGIN
    WHILE dan <= 9 LOOP            -- 단 반복
        J := 1;
        
        WHILE j <= 9 LOOP            -- 지수 반복
            DBMS_OUTPUT.PUT_LINE(dan||' * '||j||' = '||dan * j);
            j := j + 1;
        END LOOP;
        
        dan := dan + 1;
        DBMS_OUTPUT.PUT_LINE('');
    END LOOP;
END;
/
3) FOR LOOP
DECLARE
    dan number;
    j number;
BEGIN
    FOR dan IN 2..9 LOOP            -- 단 반복
        FOR j IN 1..9 LOOP            -- 지수 반복
            DBMS_OUTPUT.PUT_LINE(dan||' * '||j||' = '||dan * j);
        END LOOP;

        DBMS_OUTPUT.PUT_LINE('');
    END LOOP;
END;
/

 

[문제] 급여를 입력값으로 받아서 1000당 * 하나를 출력해주세요.
<화면출력>
급여는 5500 당신의 별은 *****

-- 바인드변수에서는 길이지정 안함
VAR sal number      
EXECUTE :sal := 5500

DECLARE
    num number := trunc(:sal / 1000);
    star varchar2(10);
BEGIN
    FOR i IN 1..num LOOP
        star := star||'*';
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('급여는 '||:sal||' 당신의 별은 '||star);
END;
/

 


 

■ PL/SQL의 SQL문
- SELECT문을 이용해서 데이터베이스에 있는 데이터를 추출할 수 있다.
DML(INSERT,UPDATE,DELETE,MERGE)문을 이용해서 데이터베이스에 있는 데이터를 조작할 수 있다.
COMMIT, ROLLBACK, SAVEPOINT문을 이용해서 트랜젝션을 처리할 수 있다.

cursor : SQL문 실행 메모리 영역(parse - bind - execute - fetch 단계 수행)
- 암시적커서 : 오라클이 SQL문을 처리하기 위해서 내부적으로 생성하고 관리한다.
- 명시적커서 : 프로그래머가 명시적으로 관리한다.(여러개의 row를 fetch해야 할 때 사용)


# 암시적커서
SELECT ... INTO (fetch) 절 : 반드시 1개 row만 fetch 해야한다.
    데이터 0개 : NO_DATA_FOUND
          2개이상 : TOO_MANY_ROWS
- DML, COMMIT, ROLLBACK, SAVEPOINT

DECLARE
    v_name varchar2(30);
    v_sal number;
BEGIN
    SELECT last_name, salary
    INTO v_name, v_sal          -- fetch 절
    FROM hr.employees
    WHERE department_id = 10;   -- 데이터 row 1개.
    
    DBMS_OUTPUT.PUT_LINE(v_name);
    DBMS_OUTPUT.PUT_LINE(v_sal);
END;
/
DECLARE
    v_name varchar2(30);
    v_sal number;
BEGIN
    SELECT last_name, salary
    INTO v_name, v_sal          -- fetch 절
    FROM hr.employees
    WHERE department_id = 20;   -- 오류 : 1개 이상의 데이터row를 가지고 있다. 
    
    DBMS_OUTPUT.PUT_LINE(v_name);
    DBMS_OUTPUT.PUT_LINE(v_sal);
END;
/

>> ORA-01422: exact fetch returns more than requested number of rows
var b_id number
execute :b_id := 100

DECLARE
    v_name varchar2(30);
    v_sal number;
BEGIN
    SELECT last_name, salary
    INTO v_name, v_sal
    FROM hr.employees
    WHERE employee_id = :b_id;
    
    DBMS_OUTPUT.PUT_LINE(v_name);
    DBMS_OUTPUT.PUT_LINE(v_sal);
END;
/
var b_avg_sal number

BEGIN
    SELECT avg(salary)
    INTO :b_avg_sal
    FROM hr.employees;
    
    DBMS_OUTPUT.PUT_LINE('전체 사원의 평균 값은 '||:b_avg_sal);
END;
/

SELECT * FROM hr.employees WHERE salary > :b_avg_sal;

 

# 유저.테이블.컬럼%type : 컬럼의 type, size를 가져다 사용한다.
# 후에 컬럼의 type과 size가 변경되더라도 프로그램을 수정할 필요가 없다.

DECLARE
    v_name hr.employees.last_name%type;
    v_sal hr.employees.salary%type;
BEGIN
    SELECT last_name, salary
    INTO v_name, v_sal
    FROM hr.employees
    WHERE employee_id = 100;
    
    DBMS_OUTPUT.PUT_LINE(v_name);
    DBMS_OUTPUT.PUT_LINE(v_sal);
END;
/
DECLARE
    v_hire_date hr.employees.hire_date%type;
    v_sal hr.employees.salary%type;
BEGIN
    SELECT hire_date, salary
    INTO v_hire_date, v_sal
    FROM hr.employees
    WHERE employee_id = 100;
    
    DBMS_OUTPUT.PUT_LINE('입사일 : '||to_char(v_hire_date,'yyyy"년" mon dd"일"'));
    DBMS_OUTPUT.PUT_LINE('급여는 : '||ltrim(to_char(v_sal,'l999,999.00')));
END;
/

 

 

DROP TABLE hr.test;
CREATE TABLE hr.test(id number, name varchar2(30), day date);
desc hr.test

 

BEGIN
    INSERT INTO hr.test(id,name,day) VALUES(1,'홍길동',sysdate); -- 트랜젝션 실행
END;
/

SELECT * FROM hr.test;
ROLLBACK;       -- 트랜젝션 종료. 위치 선정 중요!
DECLARE
    v_id hr.test.id%type := 1;
    v_name hr.test.name%type := '홍길동';
    v_day hr.test.day%type := sysdate;

BEGIN
    INSERT INTO hr.test(id,name,day) VALUES(v_id,v_name,v_day);
    COMMIT;
END;
/

SELECT * FROM hr.test;
var b_id number
var b_name varchar2(30)
var b_day varchar2(30)

execute :b_id := 3
execute :b_name := 'james'
execute :b_day := '2002-01-01'

BEGIN
    INSERT INTO hr.test(id,name,day) 
    VALUES(:b_id,upper(:b_name),to_date(:b_day,'yyyy-mm-dd'));
END;
/

COMMIT;

SELECT * FROM hr.test;

 

sql%rowcount : 암시적커서 속성, 영향을 입은 ROW 건수를 리턴. DML 작업 후 많이 사용.

BEGIN
    DELETE FROM hr.test WHERE id = 1;
    DBMS_OUTPUT.PUT_LINE('삭제된 행의 수는 '|| sql%rowcount);
    
    UPDATE hr.test SET day = sysdate + 100;
    DBMS_OUTPUT.PUT_LINE('수정된 행의 수는 '|| sql%rowcount);
END;
/

SELECT * FROM hr.test;
ROLLBACK;

 

DROP TABLE hr.emp PURGE;

CREATE TABLE hr.emp
AS
SELECT * FROM hr.employees;

 

BEGIN
    DELETE FROM hr.emp 
    WHERE department_id = 20;
    DBMS_OUTPUT.PUT_LINE('삭제된 행의 수는 '||sql%rowcount);
    
    UPDATE hr.emp 
    SET salary = salary * 1.1
    WHERE department_id = 30;
    DBMS_OUTPUT.PUT_LINE('수정된 행의 수는 '||sql%rowcount);
END;
/
SELECT * FROM hr.emp;
ROLLBACK;

 

sql%found : 영향을 입은 ROW가 있으면 TRUE, 없으면 FALSE를 리턴하는 속성.

DECLARE
    v_id hr.emp.employee_id%type := 0;

BEGIN
    UPDATE hr.emp
    SET salary = salary * 1.1
    WHERE employee_id = v_id;
    
    IF sql%found THEN
        DBMS_OUTPUT.PUT_LINE(v_id||'사원으로 수정된 데이터가 있습니다.');
    ELSE
        DBMS_OUTPUT.PUT_LINE(v_id||'사원으로 수정된 데이터가 없습니다.');
    END IF;
END;
/

SELECT * FROM hr.emp;
ROLLBACK;

 

sql%notfound : 영향을 입은 ROW가 없으면 TRUE, 있으면 FALSE 리턴하는 속성.

DECLARE
    v_id hr.emp.employee_id%type := 0;

BEGIN
    UPDATE hr.emp
    SET salary = salary * 1.1
    WHERE employee_id = v_id;
    
    IF sql%notfound THEN
        DBMS_OUTPUT.PUT_LINE(v_id||'사원으로 수정된 데이터가 없습니다.');
    ELSE
        DBMS_OUTPUT.PUT_LINE(v_id||'사원으로 수정된 데이터가 있습니다.');
    END IF;
END;
/

 

'Oracle SQL' 카테고리의 다른 글

17 PL/SQL Nested Table, VARRAY, Explicit Cursor  (0) 2023.10.30
16 PL/SQL RECORD, Array  (0) 2023.10.27
14 PL/SQL Variable, CASE, LOOP  (0) 2023.10.25
13-1 SAVEPOINT  (0) 2023.10.24
12 Sequence, Synonym, Extract, 날짜함수, 분석함수, Rank  (0) 2023.10.23