Or15PLSQL

/*****************************

파일명 : Or15PLSQL.sql

PL/SQL

설명 : 오라클에서 제공하는 프로그래밍 언어

*****************************/


/*

PL/SQL(Procedural Langage)

:일반 프로그래밍 언어에서 가지고 있는 요소를 모두 가지고 있으며 DB업무를

처리하기 위해 최적화된 언어이다.


기본구조

-선언부(Declare) : 모든 변수나 상수를 선언하는 부분

-실행부 (Executable) : Begin - end /제어문, 반복문, 함수정의 등의 로직을

기술하는 부분

- 예외처리부(Exception) : 실행도중에 에러발생시 해결하기위한 명령들을

기술하는 부분


Declare, Begin, Exception 등과 같은 키워드들은 ;(세미콜론)을 붙이지 않는다.

나머지 문장들은 ; 으로 마무리한다.


-익명블록(Anonymous Black) : 주로 일회성으로 사용할 경우 사용된다.

-저장블록(Stared Block) : 서버에 저장해 놓고 주기적으로 반복해서 사용할

경우에 많이 사용된다.

*/

/

set serveroutput on;

--화면상에 내용을 출력할 때는 on으로 설정한다.

--set serveroutput off; --내용을 출력하지 않을때는 off로 설정한다.


--선언부는 declare로 시작함.

declare

    cnt integer;

--실행부는 begin --end; 사이임.

begin

    cnt := cnt +1; 

    -- 대입연산자로 PL/SQL에서는 = 대신 :=를 사용함.

    if cnt is null then 

    -- Java에서 System.out.println()과 동일한 역할로 화면에 문자열을 출력

        dbms_output.put_line('결과:cnt는 넓이다');

    else

        dbms_output.put_line('결과:cnt는 넓이 아니다');

    end if;

end;

--실행부의 종료부분

/


/

declare

    empNo number(20);

    empName varchar2(30);

begin

    -- select절에서 가져온 필드를 into절에서 변수에 할당한다.

    select employee_id, first_name

    into empNo, empName

    from employees

    where employee_id=120;

    

    dbms_output.put_line(empNo ||' '|| empName);

end

;

/


/*

변수

-변수의 생성규칙

1. 반드시 문자로 시작해야 한다.

2. 문자나 숫자, 특수문자를 포함할수 있다.

3. 변수명은 30byte이하여야 한다.

4. 예약어(키워드)를 사용할 수 없다.


-변수의 선언은 선언부(declare)에서 선언되고, 값으로 초기화가 가능하다.

-실행부에서 실행될경우 값이 할당된다.

-서브프로그램의 파라미터로 전달되기도 하며, 서브프로그램의 출력결과를

저장하기도 한다.


변수의선언예>

emp_no number(6,3) : 숫자를 저장하는 변수로 총 6자리, 소수점이하

3자리를 의미한다.

emp_name varchar2(5) : 문자를 저장하는 변수로 총 5바이트를 

저장할수있다.

emp_date date : 날자를 저장하는 변수이다.


변수의 데이터타입>

-char : 고정길이의 문자를 저장. 최소1 ~ 최대32,767바이트 저장.

기본최소값은 1

-varchar2 : 가변길이의 문자를 저장. 최대 32,767바이트 저장.

기본최소값 없음

-number(전체자리수, 소수점이하 자리수) : 전체자리수와 소수점이하

자리수를 가진 숫자를 저장. 전체자리수 범위는 1~38까지 가능함.

소수점 자리수의 범위는 -84~127까지 가능함.

-binary_double : 부동소수점 숫자를 저장. 9바이트 필요함.

-date : 날짜 및 시간을 저장. 초단위로 저장함.

날자의 범위는 4712 B.C ~ 9999 A.D

-timestamp : date타입의 확장. 연,월,일,시,분,초 및 소수로 표시되는

초단위를 저장. 


*참조변수*

형식 : 테이블명.필드명%Type


empNo employees.employee_id%Type

:employees 테이블의 employee_id와 동일한 데이터타입으로 선언


empRow employees%ROWTYPE

:employees 테이블의 모든 컬럼을 한꺼번에 저장하기 위한 변수로 선언

*/


--employees -> employees_copy로 스키마와 레코드까지 복사하기

create table employees_copy

as

select * from employees where 1=1;


desc employees_copy;

select * from employees_copy where department_id=10;



/*

하나의 컬럼을 지정하여 기존테이블의 동일한 자료형으로 변수 선언


예시] 부서번호 10인 사원의 사원번호, 급여, 부서번호를 가져와서

아래 변수에 대입후 화면상에 출력하는 PL/SQL문을 작성하시오.

단, 변수는 기존테이블의 자료형을 참조하는 참조변수로 선언하시오.

*/


--테이블명 컬럼%type : 특정테이블의 컬럼과 동일한 자료형으로 선언


declare

    empNo       employees_copy.employee_id%type;

    empSalary   employees_copy.salary%type;

    deptId      employees_copy.department_id%type;

begin

    select employee_id, salary, department_id

        into empNo, empSalary, deptId

        from employees_copy

        where department_id = 10;

        

        dbms_output.put_line(empNo ||' '|| empSalary || ' '|| deptId);

end;

/


/*

테이블의 전체 컬럼을 한꺼번에 가져와서 emp_row변수에 지정한 후 출력

예시] 사원번호가 100인 사원의 레코드를 가져와서 emp_row변수에 지정한 후

화면에 출력하시오.

단, emp_row는 employees_copy 테이블의 전체컬럼을 저장할 수 있는 형태의

참조변수로 선언해야 한다.

*/


--테이블명%rowtype : 특졍테이블의 전체컬럼을 대체하는 참조변수 선언

declare

    emp_row employees_copy%rowtype;

begin

    select * into emp_row

    from employees_copy

    where employee_id =100;

    

    dbms_output.put_line(

        emp_row.employee_id ||' '|| 

        emp_row.first_name ||' '||

        emp_row.email ||' '||

        emp_row.salary ||' '||

        emp_row.department_id);

end;

/


/*

PL/SQL에서 Select문장 사용시 주의사항


1. select문은 반드시 하나의 행만 return해야 한다. 하나이상 이거나 없을 경우

PL/SQL은 Too_many-rows 혹은 No_data_found 예외를 발생시킨다.

2. 만약 여러행을 Return해야 할 경우에는 Cursor를 사용해야 한다.

3. Select문장을 PL/SQL에서 사용시에는 into절을 사용해야 한다.

4. Into절에서는 테이블의 열과 Into절에서의 출력변수의 수가 일치해야 한다.

(1:1매칭되어 할당되어야 함)

*/



/*

-바인드변수

1. 호스트환경에서 선언된 변수로서 바 PL/SQL변수이다.

2. PL/SQL 프로그램의 내부나 외부에서 값을 전달하기 위해서 사용한다.

3. PL/SQL 문이 프로시저나 함수안에 있지 않는다면 호스트에서 선언된 변수

(바인드변수)를 PL/SQL문장에서 참조할 수 있다.

4. 바인드변수와 PL/SQL내에서의 변수를 구분하기 위해 바인드변수 앞에 :(콜론)을

붙인다.

5. 키워드는 VAR[IBLE]을 이용한다.

6. PL/SQL 블럭이 실행된 후에도 엑세스가 가능하다.

7. print명령을 이용하여 출력이 가능하다.


사용법 :

    VAR 변수명 자료형;

바인드변수가 1개인 경우

    PRINT 변수명

    or

    SELECT : 변수명 FROM 테이블명;


바인드변수가 2개이상인 경우

    PRINT 변수명1 변수명2 -> 스페이스바로 구분함

    or

    SELECT : 변수명1, :변수명2 FROM 테이블명;    

*/


--바인드(호스트)변수 변수선언

set serveroutput on;


var return_var number;


declare

begin

    :return_var := 300;

end;

/


print return_var;


-바인드변수 잠시 보류

/************************************************************/


--PL/SQL을 이용한 데이터 입력

--1.tb_member에 레코드 입력

insert into tb_member values (100,'gildong1','1234','홍길동','gildong@kosmo.co.kr');

insert into tb_member values (101,'gildong2','1234','최길동','choi@kosmo.co.kr');--1.tb_member에 레코드 입력

insert into tb_member values (102,'gildong3','1234','박길동','park@kosmo.co.kr');

--2.tb_member테이블을 스키마만 복사

create table tb_member_copy

as

select * from tb_member where 1=0;

--3.레코드확인

select * from tb_member;        --3개의 레코드 연출

select * from tb_member_copy;   --0개의 레코드 연출

--4.commit해서 영구저장

commit;


--update tb_member set member_idx=102

--where userid = 'gildong3'; 레코드에 아이디가 모두 같게 들어가서 변경하였음.


--5.데이터를 복사하여 저장하는 PL/SQL문 작성


declare

    c_rec tb_member%rowtype;

begin

    select * into c_rec

    from tb_member

    where member_idx=100;

    

    insert into tb_member_copy values c_rec;

end;

/

--6. 레코드 확인

select * from tb_member_copy;


--PL/SQL을 이용한 데이터 수정

/*

예시] tb_member테이블의 idx=101을 가져와서

      tb_member_copy 테이블의 100번 레코드 수정

*/


-- 하나의 레코드를 가져온 후 특정 컬럼만 다른값으로 수정하고 싶을 때

declare

    --테이블의 전체 행 참조한 참조변수 생성

    copy_row tb_member_copy%rowtype;

begin

    --member_idx가 101인 레코드를 가져와서 copy_row 변수에 할당

    select *

        into copy_row

    from tb_member

    where member_idx=101;

    

    

    --update문에서는 * 를 사용할 수 없으므로 전체컬럼을 대체할 수 있는

    --'row'라는 키워드를 제공하고 있다.

    --즉, 전체행을 tb_member_copy 테이블에 업데이트한다.

    update tb_member_copy

    set row=copy_row

    where member_idx =100;

end;

/

select * from tb_member_copy;




-- 하나의 레코드를 가져온 후 특정 컬럼만 다른값으로 수정하고 싶을 때

declare

    --테이블의 전체 행 참조한 참조변수 생성

    copy_row tb_member_copy%rowtype;

begin

    --member_idx가 101인 레코드를 가져와서 copy_row 변수에 할당

    select *

        into copy_row

    from tb_member

    where member_idx=102;

    

    --할당한 값중에 패스워드만 다른 값으로 변경하기

    copy_row.passward := '9999';

    

    update tb_member_copy

    set row=copy_row

    where member_idx =102;

end;

/

select * from tb_member_copy;

    

/*

    치환연산자

    : 사용자로부터 값을 입력받을 때 사용한다.

*/

declare

    /* 사용자로부터 입력을 받을 때 변수 앞에 엠퍼센트를 사용한다. */

    no1 number := #

    no2 number := #

    total number;

begin

    total := no1 + no2;

    dbms_output.put_line(

    '첫번째수:' || no1 ||', 두번째수:' || no2 ||', 합은:'|| total || '입니다.');

end;

/


/*

복합변수

    : class를 정의하듯 필요한 자료형을 묶어서 생성하는 변수

    사용법

    1. 복합변수 생성을 위한 자료형 정의

        Type 타입명 Is Record (

            자료형1,

            자료형2....

        );

    2. 자로형을 통한 복합변수 생성

    변수명 타입명;

*/

declare

    -- emp_type이라는 3개의 자료형을 가진 복합변수를 생성함

    type emp_type is record

    (

        emp_id employees.employee_id%type,

        emp_name employees.first_name%type,

        emp_job employees.job_id%type

    );

    --위에서 정의한 복합변수 emp_type을 이용하여 변수생성


   

    rec1 emp_type;

begin

    --select절에서 가져온 3개의 컬럼을 변수 rec1에 할당함.


    select employee_id, first_name, job_id

    into rec1

    from employees

    where department_id =10;

    

    --할당한 변수를 출력 -> 변수.컬럼명

    dbms_output.put_line('사번    이름    직무아이디');

    dbms_output.put_line('--------------------------');

    dbms_output.put_line(rec1.emp_id ||' '|| rec1.emp_name ||' '||

    rec1.emp_job);

end;

/


/*

문제] 아래 절차에 따라 PL/SQL 코드를 작성하시오.

아래 조건에 맞는 '복합변수'를 생성한다.

참조테이블 : employees의 각 컬럼을 참조하여 생성

복합변수 자료형 이름 : employees

    멤버1 : emp_id

    멤버2 : emp_name

    멤버3 : emp_email

    멤버4 : emp_salary

    멤버5 : emp_percent

생성한 복합변수 자료형으로 복합변수 rec2를 생성하고 사원번호 100번을

가져와서 할당한다

그리고 사번, 이름, 이메일, 급여, 보너스율을 출력한다.

단, 보너스율이 null이라면 0으로 표시한다.

*/


declare

    type emp_type is record

    (

        emp_id employees.employee_id%type,

        emp_name employees.first_name%type,

        emp_email employees.email%type,

        emp_salary employees.salary%type,

        emp_percent employees.commission_pct%type

    );

begin

    select employee_id, first_name, email, salary, nvl(commission_pct, 0)

    into rec2

    from employees

    where department_id =100;


    dbms_output.put_line('사번:' || rec2.emp_id);

    dbms_output.put_line('이름:' || rec2.emp_name);

    dbms_output.put_line('이메일:' || rec2.emp_email);

    dbms_output.put_line('급여:' || rec2.emp_salary);

    dbms_output.put_line('보너스율:' || rec2.emp_percent);

end;

/




declare

    --복합변수 자료형을 선언

    Type employTypes Is Record(

        emp_id employees.employee_id%Type,

        emp_name employees.last_name%Type,

        emp_email employees.email%Type,

        emp_salary employees.salary%Type,

        emp_percent employees.commission_pct%Type

    );

    --자료형을 통한 복합변수 선언

    rec2 employTypes;

    --사용자로부터 사원번호를 입력받아 출력하기

    vemp_id employees.employee_id%Type := &vemp_id;

begin

    select employee_id, last_name, email, salary, nvl(commission_pct,0)

        into rec2

    from employees

    where employee_id = vemp_id;

    

    dbms_output.put_line('사번:'|| rec2.emp_id);

    dbms_output.put_line('이름:'|| rec2.emp_name);

    dbms_output.put_line('이메일:'|| rec2.emp_email);

    dbms_output.put_line('급여:'|| rec2.emp_salary);

    dbms_output.put_line('보너스율:'|| rec2.emp_percent ||'%');

end;

/


/*

제어문 : if문, case문과 같은 조건문

    if문

      사용법]

          if 조건1 then

                  실행문1

                elsif 조건2 then

                  실행문2

                else

                  실행문3

                end if;

                #else if가 아니라 s가 빠진 elsif 라는 것을 주의할 것

*/


--홀수 짝수를 판단하는 if문

declare

    vNum number;

begin

    vNum := 10;

    

    if mod(vNum,2) =0 then

        dbms_output.put_line(vnum||'은 짝수');

    else

        dbms_output.put_line(vNum||'은 홀수');

    end if;

    --if문의 끝은 반드시 end if; 로 마무리 할것.

end;

/


--단일 if문으로 사원의 부서를 출력하는 PL/SQL문

declare

    emp_id employees.employee_id%type;

    emp_name employees.last_name%type;

    emp_dept employees.department_id%type;

    dept_name varchar2(30) := '부서정보없음'; --선언과 동시에 초기화

begin

    select employee_id,last_name,department_id

    into emp_id,emp_name,emp_dept

    from employees

    where employee_id=110;

    

    if emp_dept=50 then

    dept_name:='Shipping';

    end if;

    if emp_dept=60 then

    dept_name:='IT';

    end if;

    if emp_dept=70 then

    dept_name:='Public Relations';

    end if;

    if emp_dept=80 then

    dept_name:='Sales';

    end if;

    if emp_dept=90 then

    dept_name:='Executlive';

    end if;

    

    dbms_output.put_line('사원번호'|| emp_id || '의 정보');

    dbms_output.put_line('이름'|| emp_name || '부서번호:'|| dept_name);

    

end;

/


--위에서 만든 PL/SQL문을 if-elsif문으로 변경 및 사원번호를 입력받은 후 조회


declare

    emp_id employees.employee_id%type := &emp_id; --사용자로부터 입력받음

    emp_name employees.last_name%type;

    emp_dept employees.department_id%type;

    dept_name varchar2(30) := '부서정보없음'; --선언과 동시에 초기화

begin

    select employee_id,last_name,department_id

    into emp_id,emp_name,emp_dept

    from employees

    where employee_id= emp_id;

    

    --자바에서 사용하는 else if에서 e가 빠진 형태임을 주의

    if emp_dept=50 then

    dept_name:='Shipping';

    elsif emp_dept=60 then

    dept_name:='IT';

    elsif emp_dept=70 then

    dept_name:='Public Relations';

    elsif emp_dept=80 then

    dept_name:='Sales';

    elsif emp_dept=90 then

    dept_name:='Executlive';

    end if;

    

    dbms_output.put_line('사원번호'|| emp_id || '의 정보');

    dbms_output.put_line('이름'|| emp_name || '부서번호:'|| dept_name);

    

end;

/

set serveroutput on;


--사원번호를 통해 조히한 사원의 보너스율에 따른 조건문


declare

    emp_id employees.employee_id%type := &emp_id;

    emp_name employees.first_name%type ;

    emp_comm employees.commission_pct%type ;

begin

    select first_name, commission_pct

        into emp_name, emp_comm

    from employees

    where employee_id = emp_id;

    

    if emp_comm > 0 then

        dbms_output.put_line(emp_name||'의 보너스 율은 '|| emp_comm ||'입니다.');

    else

        dbms_output.put_line(emp_name||'은 보너스가 없습니다.');

    end if;

end;

/


/*

case문 : switch문과 비슷한 조건절

사용법]

    Case 변수

        When 값1 then 실행문1

        When 값2 then 실행문2

        ............

        When 값n then 실행문n

    End ;


*/


declare

    e_id employees.employee_id%type;

    e_name employees.first_name%type;

    e_dept employees.department_id%type;

    dept_name varchar2(30) := '부서모름';

begin

    select employee_id, first_name, department_id

        into e_id, e_name, e_dept

    from employees

    where employee_id = 100;

    

    --Case -When 문에 의한 분기

    dept_name := case e_dept

                    when 50 then 'Shipping'

                    when 60 then 'IT'

                    when 70 then 'Public Reations'

                    when 80 then 'Sales'

                    when 90 then 'Executive'

                end;

    dbms_output.put_line('사원번호'|| e_id || '의정보');

    dbms_output.put_line('부서아이디:'|| e_dept ||', 이름:'|| e_name ||',

    부서명:'|| dept_name);

end;

/


/*

반복문

- Basic Loop문 : do-while문과 비슷한 형태로 문장을 먼저 실행한 후

    조건을 검사한다. 즉, 무조건 한번은 실행이 되는 형태의 반복문.

- while문 : 반복문의 일종으로 조건이 맞는지 확인후 실행한다.

    Basic Loop문과 다른점은 조건에 따라 한번도 실행되지 않을 수도 있다.

- For문 : 반복의 횟수를 지정하여 사용할 수 있으며, 반복을 위한 변수는

따로 선언하지 않아도 된다.

*/


/*

1. Basic Loop문

    사용법]

    Loop

        실행문장 ;

        exit (Loop를 벗어날 조건);

    End Loop;

*/

declare

    num number := 0; --숫자타입으로 선언후 0으로 초기화

begin

    loop --조건검사없이 일단 loop 안으로 진입

        dbms_output.put_line(num);

        num := num + 1;

        exit when(num>10); -- num이 10을 초과할때 loop를 탈출

    end loop;

end;

/


/*

2. while문

    사용법]

     while 조건 Loop

        실행문;

     End Loop;

*/

declare

    num number := 0;

begin

    while num<11 loop

        dbms_output.put_line('이번숫자는: '||num);

        num := num +1;

    end loop;

end;

/


/*

3. For문

    사용법]

      For n[카운트 변수] In start[초기값] .. end[종료값] Loop

        실행문;

      End Loop;


*/


declare

    --반복을 위한 변수선언이 필요없다.

    --이 경우 declare는 생략 가능함.

begin

    for num1 in 0 .. 10 loop

        dbms_output.put_line('현재숫자는:'|| num1);

    end loop;

end;

/


--변수 선언이 필요 없으므로 declare 부분은 생략


begin

    for num2 in reverse 0 .. 10 loop

        dbms_output.put_line('거꾸로 반복되는 숫자는:'|| num2);

    end loop;

end;

/


/*

테이블 타입 변수

컬렉션 : 일반 프로그래밍 언어에서 사용하는 배열타입을 PL/SQL에서는

    컬렉션이라고 한다.


종류

1. 연관배열(Associative Array / Index-by Table)

2. VArray(Variable Array)

3. 중첩테이블(Nested Table)


* 연관배열 : 키와 갑싱 한쌍으로 구성된 컬렉션으로 Java의 해시테이블과

같은 개념이다.

    Key : 자료형은 주로 숫자를 사용하며 binary_integer, pis_integer가 사용된다.

        이 두가지 타입은 number보다 킉가 작고 산술연산에 빠른 자료형이다.

        단, 문자형(varchar2)으로 사용하는 것도 가능하다.

    Value : 자료형은 문자형이며 주로 varchar2가 사용된다.

사용법]

    Type 연관배열명 Is Table Of 연관배열_값_타입 Index by 연관배열_키_타입

*/


declare

    --변수명 : av_type

    --value(값)의 자료형 : varchar2(30)

    --key(키)의 자료형 : pls_integer

    type av_type is table of varchar2(30) index by pis_integer;

    

    -연관배열 변수를 생성

    var_test av_type;

begin

    var_test(10) := '10에 대한 할당값'; -- 키는 10, 값은 '10에 대한 할당값'

    var_test(20) := '20에 대한 할당값';

    

    dbms_output.put_line(var_test(10));

    dbms_output.put_line(var_test(20));

and;

/


/*

연관배열의 키를 문자형으로 선언한 경우

*/

declare

    tname varchar2(20);

    

    type t_emp_name

        is table of employees.last_name%type

        index by varchar2(4);

    v_name t_emp_name;

begin

    select last_name 

        into tname

    from employees

    where employee_id =100;

    

    v_name('CR01') := tname;

    

    dbms_output.put_line(v_name('CR01'));

end;

/


/*

VArray(Variable Array)

: 고정길이를 가진 배열로서 일반 프로그래밍 언어에서 사용하는 배열과

동일하다. 크기에 제한이 있어서 선언할 때 크기(요소의 갯수)지정하면

이보다 큰 배열로 만들 수 없다.


사용법]

    Type 배열명 Is Array(배열크기) Of 요소값_타입;

*/


declare

    --VArray의 이름 : va_type

    --값(value)의 자료형 : varchar2(20)

    

    type va_type is array(5) of varchar2(20);

    

    --VArray 변수 선언

    vArr va_type;

    

    --배열을 카운트하기 위한 변수선언

    vn_cnt number := 0;

begin

    --생성자를 통한 값의 초기화(총5개중 3개만 할당)

    vArr := va_type('First','Second','Third','','');

    

    --Basic Loop문을 통한 배열의 요소 출력(인덱스는 1부터 시작)

    loop

        vn_cnt := vn_cnt + 1;

        if vn_cnt>5 then

            exit; --5가 될때까지 반복하다가 6이 되었을때 탈출

        end if;

        --배열이 요소값 출력

        dbms_output.put_line(vArr(vn_cnt));

    end loop;

    

    --배열에 값을 재할당

    vArr(3) := '우리는';

    vArr(4) := 'JAVA';

    vArr(5) := '개발자다';

    

    vn_cnt := 0;

    loop

        vn_cnt := vn_cnt + 1;

        

        --5보다 커지면 Loop 탈출, if문과 동일한 조건문임.

        Exit when vn_cnt>5;

        dbms_output.put_line(vArr(vn_cnt));

    end loop;

end;

/


/*

중첩테이블(Nested Table)

    : VArray와 비슷한 구조의 배열로서 배열의 크기를 명시하지 않으므로

    동적으로 배열의 크기가 설정된다.

    여기서 말하는 테이블은 자료가 저장되는 실제테이블이 아니라

    컬렉션의 한 종류를 의미한다.

    

    사용법]

        Type 중첩테이블명 IS Type Of 값_타입;

*/

declare

    --중첩테이블 선언

    type nt_type is table of varchar2(30);

    --정의한 중첩테이블을 통해 변수 선언

    ntArray nt_type;

begin

    --생성자를통한 값 할당.(여기서는 크기가 4인 중첩테이블이 생성됨)

    ntArray := nt_type('첫번째', '두번째', '세번째', '');

    

    dbms_output.put_line(ntArray(1));

    dbms_output.put_line(ntArray(2));

    dbms_output.put_line(ntArray(3));

    ntArray(4) := '네번재값할당';

    dbms_output.put_line(ntArray(4));-- 4번째 값까지 저장할 수 있음.

    --ntArray(5) := '다섯번째값??할당??'; --5번째값을 저장할 경우 에러발생

    

    /* 오류내용 : 첨자가 개수를 넘었습니다. */

    

    --크기를 확정해야 할 때는 생성자를 통해 배열의 크기를 동적으로 확정한다.

    ntArray := nt_type('la','2b','3c','4d','5e','6f','7g');

    

    --변수 i가 1 ~ 7까지 증가하는 for문

    for i in 1 .. 7 loop

        dbms_output.put_line(ntArray(i));

    end loop;

end;

/


/*

반복문과 배열을 응용한 예제

예시] 다음 조건에 맞는 연관배열 자료형을 선언하시오.

    이름 : tbl_type

    값(value)의 자료형 : employees 의 last_name 컬럼 참조

    키(key)의 자료형 : binary_integer

위 자료형을 기반으로 v_tbl_array 변수를 생성한 후 사원테이블의

전체레코드 중 last_name을 가져와서 연관배열에 저장후 for문을 통해

출력하시오.



*/

declare

    --값의 자료형은 last_name 참조, 키의 자료형은 binary_integer로 선언

    type tbl_type

        is table of employees.last_name%type

        index by binary_integer;

    --배열변수선언

    v_tbl_array tbl_type;

    

    --배열의 인덱스로 사용할 변수 선언후 0으로 초기화

    cnt binary_integer := 0;

begin

    /*

    for문의 반복의 횟수를 정수의 구간이 아닌 조회되는 레코드의 갯수만큼

    반복하도록 설정함. 여기서는 조회된 last_name이 emp_name에 할당되면서

    레코드의 갯수만큼 반복됨.

    */

    for emp_name in (select last_name from employees) loop  

        cnt := cnt + 1;

        --반복의 요소에 접근할때는 변수 emp_name을 통해서 하게 된다.

        v_tbl_array(cnt) := emp_name.last_name;

    end loop;

    

    --위에서 저장된 배열의 값을 for문으로 반복하면서 출력형 (1~107까지 출력)

    for i in 1..cnt loop

        dbms_output.put_line(i || '>' || v_tbl_array(i));

    end loop;

end;

/



/*

continue 보조제어문 (11g부터 추가된 기능)

    : 해당 조건을 만족하면 반복문의 처음으로 이동하는 기능

    사용법]

        Continue When (조건);

*/


declare

    tot number := 0;

begin

    for i in 1..10 loop

    tot := tot +1;

    dbms_output.put_line('i='|| i ||', tot='|| tot);

    

    continue when(i>5);

    

    tot := tot + i;

    dbms_output.put_line('i='|| i ||', tot2->'|| tot);

  end loop;

end;

/


/*

커서(Cursor)

 : select 문장에 의해 여러행이 반환되는 경우 각 행에 접근하기 위한것.

 

    선언방법]

      Cursor 커서명 Is

        Select 문장(Into절이 없는 Select문)

Open Cursor

 : 질의를 수행하라는 의미, 즉 Open시에 Cursor 선언시의 Select문장이 실행되어

 결과셋을 얻게된다. Cursor는 그 결과셋의 첫번째 행의 의지하게 된다.

 

 Open 커서명

 

Fetch - Into -

 : 결과셋에서 하나의 행을 읽어들이는 작업, 결과셋의 인출(Fetch)후에

 Cursor는 다음 행으로 이동함.

 

 Fetch 커서명 Into (변수1, 변수2........)

 

Cursor닫기]

 : 결과셋의 자원을 반납. Select문장이 모두 처리된 후 Cursor을 Close해줌.

 

 Close 커서명;

 

Cursor의 속성]

 %Found : 가장 최근의 인출(Fetch)행을 Return하면 True, 아니면 False를

   반환

 %RowCount : 지금까지 Return된 행의 갯수

*/

declare

    --departments 테이블의 전체컬럼을 참조한 참조변수 선언

    v_dept departments%rowtype;

    

    --c1이라는 이름의 커서를 생성.

    cursor c1 is

        select department_id, department_name, location_id

        from departments;

begin

    dbms_output.put_line('부서번호 부서명 지역번호');

    dbms_output.put_line('------------------------');

    

    --커서Open : 질의를 수행하라는 의미

    open c1;

    

    loop

    --결과셋에서 하나의 행을 인출(Fetch)하여 변수에 할당

        fetch c1 into v_dept.department_id,

                                v_dept.department_name,

                                v_dept.location_id;

        --인출할 레코드가 더이상 없으면 loop 탈출 

        exit when c1%notfound;

        

        dbms_output.put_line(v_dept.department_id||' '||v_dept.department_name||' '||v_dept.location_id);

    end loop;

    

    --커서의 자원반납

    close c1;

end;

/



#PL/SQL

/*

1. 사원테이블에서 사원아이디를 통해 조회한 후 사원이름의 문자수만큼 #을 찍는 pl/sql문을 작성해보자.

*/


declare

--사원번호 입력받기

emp_id employees.employee_id%type:=&emp_id;

--사원의 이름을 저장하기 위한 변수

emp_name varchar2(40);

--이름의 길이를 저장할 변수

name_length number;

#을 줄바꿈없이 저장할변수

sharp_str varchar2(30);

begin

select last_name, length(last_name)

into emp_name, name_length

from employees

where employee_id = emp_id;


dbms_output.put_line('조회된 사원의 이름;'|| emp_name);

dbms_output.put_line('이름의 길이:'|| name_length);


for i in 1 .. name_length loop

sharp_str := sharp_str || '#';

end loop;

dbms_output.put_line(sharp_str);

end;



/*

2. Basic loop문으로 1부터 10까지의 정수의 합을 구하시오.

*/

declare

--1~10"까지증가시키기위한 변수

startNum number := 1;

--누적합을구하기 위한 변수

sumNum number := 0;

begin

loop

dbms_output.put_line('startNum'|| startNum);

--1씩 증가

--누적합 구함

sumNum := sumNum + startNum;

startNum :== startNum + 1;

exit when startNum>10;

end loop;


dbms_output.put.line('1~10까지의 합:' || sumNum);

end;





/*

3. For loop 문으로 구구단을 출력하시오.

*/


declare

    v_sum number(1) := 1; --초기화

begin

        for i in 1 .. 9 Loop       

         dbms_output.put_line('&곱셈*'|| I || '=' || &곱셈*I);

    end loop;

end;


begin

for i in 2 .. 9 loop --단에 해당하는 for문

for j in 1 .. 9 loop

dbms_output.put_linee(i || ' * ' || j || ' = ' || ((j*i));

end loop;

dbms_output.put_line('');

end loop;

end;



/*

4. While loop 문으로 다음과 같은 결과를 출력하시오.

*

**

***

****

*****

*/


declare

num1 number := 1; --while문 반복을 위한 변수

num2 number := 1;

starTxt varchar2(5);

begin

while num1 <= 5 loop

while num2 <= num1 loop --num2가 num1보다 작거나 같을때까지 루프 별을 찍어낸다.

starTxt := starTxt|| '*';

num2 := num2 + 1;

end loop;


num 1 := num1 + 1;

dbms_output.put_line(starTxt);

end loop;

end;


/*

5. Cursor를 사용하여 사원테이블에서 커미션이 null이 아닌 

사원의 사원번호, 이름, 급여를 오름차순(이름)으로 출력하시오. 

*/


declare

--사원테ㅐ이블의 전체컬럼을 대체할 수 있는 참조변수 생성

v_emp employees%rowtype;

--커서 생성

cursor cEmp is

select employee_id last_name, salary from employees

where commission_pct is not null

order by last_name asc;

begin

--커서 Open : 질의를 수행하라는 의미

open cEmp;


loop

fetch cEmp

into v_emp.employee_id, v_emp.last_name, v_emp salary;

exit when cEmp%notfound;

dbms_output.put_line(v_emp.employee_id ||' '|| v_emp.last_name ||' '|| v_emp.salary);

end loop;

close cEmp;

end;




declare

    v_emp employees%rowtype;

    cursor cEmp is

        select * from employees

        where commission_pct is not null

        order by first_name asc;

begin

    for v_emp in cEmp loop

        dbms_output.put_line(v_emp.employee_id||' '||v_emp.first_name||' '||v_emp.salary);

    end loop;

end;



























'프로그래밍 > Oracle' 카테고리의 다른 글

Or16SubProgram  (0) 2017.11.16
Or14View  (0) 2017.11.15
Or13Privileges  (0) 2017.11.15
Or12Sequenceindex  (0) 2017.11.15
Or11ConStraintRule  (0) 2017.11.15
TAGS.

Comments