2016년 7월 5일 화요일

04day PL/SQL

1.
--구구단 프로시저 입력받아서 내보내기
create or replace procedure gugudan (
 p_dan1  in number,
 p_dan2  in number,
 v_result  out varchar2

)
is
 dan1_dan2_big EXCEPTION;
begin
 IF p_dan1>p_dan2 then
  RAISE dan1_dan2_big;
 ELSE
  FOR i_col in p_dan1..p_dan2 LOOP
   FOR j in 1..9 LOOP
    v_result := v_result|| i_col || '*' || j || ' = '|| i_col*j || ' '||chr(9);
   END LOOP;
   v_result := v_result|| chr(10);
  END LOOP;
 END IF;
EXCEPTION
 WHEN dan1_dan2_big THEN
  dbms_output.put_line('첫단이 끝단보다 높습니다');

end;
/

SQL> @c:\oracle\gugudan
SQL> variable g_result varchar2(2000);
SQL> exec gugudan(3,2, :g_result);
SQL> exec gugudan(2,9, :g_result);
SQL> print :g_result;

--익명 실행문 main99
set serveroutput on

--start와 end를 accept로 받아줄 수 있음
declare
 v_start  number :=1;
 v_end  number :=2;
 v_result varchar2(2000); 
begin
 gugudan(v_start,v_end,v_result => v_result);
 dbms_output.put_line(v_result);
end;
/
set serveroutput off

2. 동이름 입력받아 주소를 출력하는 프로시저

--디렉토리 권한부여
SQL> conn system/123456
SQL> grant create any directory to scott;
--외부파일 읽어드릴 폴더이름 지정
SQL> create directory zip_dir as 'c:\oracle';
--외부 zipcode파일을 읽어서 태이블로 만듦
SQL> create table zipcode(
  2          zipcode char(7),
  3          sido varchar2(6),
  4          gugun varchar2(27),
  5          dong varchar2(39),
  6          ri varchar(67),
  7          bunji varchar2(18),
  8          seq number(5))
  9     organization external(
 10          type oracle_loader
 11          default directory zip_dir
 12          access parameters(
 13                  records delimited by newline
 14                  badfile 'BAD_ZIP'
 15                  logfile 'LOG_ZIP'
 16                  fields terminated by ','(
 17                          zipcode char,
 18                          sido char,
 19                          gugun char,
 20                          dong char,
 21                          ri char,
 22                          bunji char,
 23                         seq char)
 24                 )
 25         location('zipcode.csv')
 26         )
 27       parallel 7
 28       reject limit 200;

--동이름 입력 받아서 우편번호를 출력하는 저장 프로시저 생성
create or replace procedure zipsearch (
 p_dong  in varchar2,
 v_result  out varchar2

)
is
begin
 FOR zip_record in (select * from zipcode where dong like p_dong || '%')
 LOOP
  v_result :=v_result ||  '[' ||zip_record.zipcode ||']'|| chr(9) || zip_record.sido || chr(9) 
  || zip_record.gugun || chr(9) || zip_record.dong || chr(9) || zip_record.ri || chr(9) || zip_record.bunji || chr(10);
 END LOOP;

end;
/

 --sqlplus실행문
SQL> @c:\oracle\zipsearch
SQL> set serveroutput on
SQL> variable g_result varchar2(2000);
SQL> exec zipsearch('신사', :g_result);
SQL> print :g_result;

--익명 실행문 mainzip
set serveroutput on

declare
 v_dong  varchar2(30) := '신사';
 v_result varchar2(32767);
 --v_result 값에 충분한 숫자를 할당해 주어야한다
begin 
 zipsearch(v_dong,v_result=>v_result);
 dbms_output.put_line(v_result); 
end;
/
set serveroutput off

3.
--함수 만들기
create or replace function ename_deptno (
 v_ename  in emp.ename%type
)
return number
is
 v_deptno emp.deptno%type; 
begin
 select deptno
 into v_deptno
 from emp
 where lower(ename) = v_ename;
 
 return v_deptno;
end;
/

--sql plus 함수의 사용
SQL> @c:\oracle\function01
SQL> var g_deptno number
SQL> exec :g_deptno := ename_deptno('scott')
SQL> print :g_deptno;
SQL> select ename, ename_deptno(ename) from emp;
--함수를 select문에 쓸수 있음

4.
--급여를 입력받아서 등급을 출려하는 함수를 생성

create or replace function levelsal (
 v_sal  in emp.sal%type
)
return varchar2
is
 v_result varchar2(100); 
begin
 IF v_sal between 0 and 1000 then
  v_result := 'A 등급';
 ELSIF v_sal between 1001 and 2000 then
  v_result := 'B 등급'; 
 ELSIF v_sal between 2001 and 3000 then
  v_result := 'C 등급';
 ELSIF v_sal between 3001 and 4000 then
  v_result := 'D 등급';
 ELSIF v_sal between 4001 and 5000 then
  v_result := 'E 등급';
 END IF;
 return v_result;
end;
/

--sql plus 함수 실행문
SQL> @c:\oracle\function02
SQL> var g_result varchar2(50)
SQL> exec :g_result := levelsal(3000)
SQL> print :g_result;
SQL> select ename, sal, levelsal(sal) from emp;

5.
--패키지 생성 (선언부)

CREATE OR REPLACE PACKAGE emp_info AS
 PROCEDURE all_emp_info; 
 -- 모든 사원의 사원 정보
 PROCEDURE all_sal_info; 
 -- 모든 사원의 급여 정보
END emp_info;
/


--패키지 생성 (본문)

CREATE OR REPLACE PACKAGE BODY emp_info AS
-- 모든 사원의 사원 정보
 PROCEDURE all_emp_info
 IS
  CURSOR emp_cursor IS
  SELECT empno, ename, to_char(hiredate, 'RRRR/MM/DD') hiredate
  FROM emp
  ORDER BY hiredate;
 BEGIN
  FOR aa IN emp_cursor LOOP
   DBMS_OUTPUT.PUT_LINE('사번 : ' || aa.empno);
   DBMS_OUTPUT.PUT_LINE('성명 : ' || aa.ename);
   DBMS_OUTPUT.PUT_LINE('입사일 : ' || aa.hiredate);
  END LOOP;
 EXCEPTION
  WHEN OTHERS THEN
   DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');
 END all_emp_info;

-- 모든 사원의 급여 정보
 PROCEDURE all_sal_info
 IS
  CURSOR emp_cursor IS
  SELECT round(avg(sal),3) avg_sal, max(sal) max_sal, min(sal) min_sal
  FROM emp;
 BEGIN
  FOR aa IN emp_cursor LOOP
   DBMS_OUTPUT.PUT_LINE('전체급여평균 : ' || aa.avg_sal);
   DBMS_OUTPUT.PUT_LINE('최대급여금액 : ' || aa.max_sal);
   DBMS_OUTPUT.PUT_LINE('최소급여금액 : ' || aa.min_sal);
  END LOOP;
 EXCEPTION
  WHEN OTHERS THEN
   DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');
 END all_sal_info;
END emp_info;
/

--sqlplus 패키지내의 프로시저 실행
SQL> @c:\oracle\package01
SQL> set serveroutput on
-- set serveroutput on 은 DBMS_OUTPUT.PUT_LINE 을 출력하기 위해 사용
SQL> exec emp_info.all_sal_info;
SQL> exec emp_info.all_emp_info;


6.

2016년 7월 4일 월요일

03day PL/SQL

PL/SQL

  • 자료형
    • 데이터베이스 형식 + ...
  • 특수자료형
    • %type
    • %rowtype
    • 사용자정의 레코드
  • 집합자료형
    • varray
    • table
  • 변수 / 상수의 선언부에 쓴다.
제어문
  • if
  • if~elsif ~else
  • loop
  • for
  • while
  • →SQL문 + 프로그램 혼합
  • →SQL문 + java
cursor
  • 다중 SQL문 처리
1.
set serveroutput on

declare
     v_empno               emp.empno%type;
     v_ename               emp.ename%type;
     v_job                 emp.job%type;
     v_mgr                 emp.mgr%type;
     v_hiredate            emp.hiredate%type;
     v_sal                 emp.sal%type;
     v_comm                emp.comm%type;
     v_deptno              emp.deptno%type;
begin
     for emp_record in (select * from emp order by deptno) loop
          v_empno          := emp_record.empno;
          v_ename          := emp_record.ename;
          v_job            := emp_record.job;
          v_mgr            := emp_record.mgr;
          v_hiredate       := emp_record.hiredate;
          v_sal            := emp_record.sal;
          v_comm           := emp_record.comm;
          v_deptno         := emp_record.deptno;

          if v_deptno = 10 then
               insert into emp10
               values (v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno);
          elsif v_deptno = 20 then
               insert into emp20
               values (v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno);
          elsif v_deptno = 30 then
               insert into emp30
               values (v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno);
          end if;
     end loop;

     dbms_output.put_line('처리가 완료되었습니다.');
    
end;
/

set serveroutput off

SQL> rollback;  --PL/SQL를 사용한 것도 롤백을 하면 지워짐 commit을 해줘야함

2.
set serveroutput on

declare

begin
      --create table a (col1 varchar(10));
 --에러남 PL/SQL 안에서 DDL/DCL 직접 실행 불가
 --transaction때문에 commit 되는 것 방지

 --Dynamic SQL 기법
 --문자열을 SQL문 처럼 실행

 execute immediate 'create table a (col1 varchar(10))';
    
end;
/

set serveroutput off

set serveroutput on

declare
 sql_stmt varchar2(2000);
begin

 --Dynamic SQL 기법
 --문자열을 SQL문 처럼 실행

 sql_stmt := 'create table b (col1 varchar(10))';
 execute immediate sql_stmt;
 --문자열 실행문을 변수처럼 가져올 수 있음
    
end;
/

set serveroutput off

set serveroutput on

declare
 sql_stmt varchar2(2000);
begin
 --Dynamic SQL 기법
 --문자열을 SQL문 처럼 실행

 --execute immediate 'create table a (col1 varchar(10))';
 sql_stmt := 'drop table b purge';
 execute immediate sql_stmt;
     --테이블 지우기
end;
/

set serveroutput off

3.
set serveroutput on

declare
 sql_stmt varchar2(2000);
begin
 --Dynamic SQL 기법

 --문자열 작은따옴표 escape
 sql_stmt := 'insert into dept values(90,'||'''개발'''||', '||'''부산'''||')';
 dbms_output.put_line(sql_stmt);
 execute immediate sql_stmt;
    
end;
/

set serveroutput off

4.
set serveroutput on

declare
 sql_stmt varchar2(2000);
 sql_stmt2 varchar2(2000);
 dept_id  number(2) := 91;
 dept_name  varchar(14) := '총무';
 dept_loc  varchar(13) := '서울';
begin
 --statement 기법 :문자열으로 sql문을 만드는 것
 sql_stmt := 'insert into dept values('||dept_id||','''||dept_name||''','''||dept_loc||''')';
 sql_stmt2 := 'insert into dept values('||dept_id||','||''''||dept_name||''''||','||''''||dept_loc||''''||')';
 dbms_output.put_line(sql_stmt);
 dbms_output.put_line(sql_stmt2);
 --execute immediate sql_stmt;
    
end;
/

set serveroutput off

5.
set serveroutput on

declare
 sql_stmt varchar2(2000);
 dept_id  number(2) := 91;
 dept_name  varchar(14) := '총무';
 dept_loc  varchar(13) := '서울';
begin
 --prepared statement 기법
 --미완성 문자열을 가지고 변수를 넣어줌 자바에 printf와 비슷
 sql_stmt := 'insert into dept values(:1,:2,:3)';
 execute immediate sql_stmt
  using dept_id, dept_name, dept_loc;
    
end;
/

set serveroutput off

6.
--사원 이름을 통해서 사원 정보 출력
set verify off
set serveroutput on

accept p_ename prompt '사원명 입력:'

declare
 type emp_record_type is record
 (
  v_empno emp2.empno%type,
  v_ename emp2.ename%type,
  v_sal emp2.sal%type,
  v_deptno emp2.deptno%type
 ); 
 emp_record emp_record_type;
 g_ename  emp2.ename%type := upper('&p_ename');
begin
 --select 문장에 cursor가 없으면 반드시 한개의 데이터만 가져옴
 select empno, ename, sal, deptno
 into emp_record
 from emp2
 where ename = g_ename;
 
 dbms_output.put_line('사원번호 :' || emp_record.v_empno);
 dbms_output.put_line('사원급여 :' || emp_record.v_sal);
 dbms_output.put_line('부서번호 :' || emp_record.v_deptno);

end;
/

set serveroutput off
set verify on

7.
SQL> create table emp2 as select * from emp;
SQL> insert into emp2 select * from emp where deptno=10;

--(예외처리)사원 이름을 통해서 사원 정보 출력
set verify off
set serveroutput on

accept p_ename prompt '사원명 입력:'

declare
 type emp_record_type is record
 (
  v_empno emp2.empno%type,
  v_ename emp2.ename%type,
  v_sal emp2.sal%type,
  v_deptno emp2.deptno%type
 ); 
 emp_record emp_record_type;
 g_ename  emp2.ename%type := upper('&p_ename');
begin
 --select 문장에 cursor가 없으면 반드시 한개의 데이터만 가져옴
 select empno, ename, sal, deptno
 into emp_record
 from emp2
 where ename = g_ename;
 
 dbms_output.put_line('사원번호 :' || emp_record.v_empno);
 dbms_output.put_line('사원급여 :' || emp_record.v_sal);
 dbms_output.put_line('부서번호 :' || emp_record.v_deptno);
--예외 처리
exception
 when no_data_found then
  dbms_output.put_line('자료가 없습니다');
 when too_many_rows then
  dbms_output.put_line('2개 이상의 자료는 출력할 수 없습니다');
 when others then
  dbms_output.put_line('기타 에러입니다');

end;
/

set serveroutput off
set verify on

8.
SQL> drop table emp2 purge;
SQL> create table emp2 as select empno, ename, sal, deptno from emp;
SQL> alter table emp2 add constraint emp2_ename_uk unique(ename);

set verify off
set serveroutput on

accept p_empno prompt '사원번호 입력:'
accept p_ename prompt '사원이름 입력:'
accept p_sal prompt '사원급여 입력:'
accept p_deptno prompt '부서번호 입력:'

declare
 v_empno  emp2.empno%type := &p_empno;
 v_ename  emp2.ename%type := upper('&p_ename');
 v_sal   emp2.sal%type := &p_sal;
 v_deptno  emp2.deptno%type := &p_deptno;
begin
 insert into emp2
 values (v_empno, v_ename, v_sal, v_deptno);
 dbms_output.put_line('입력 완료');

exception
 --입력값 중복 에러
 when dup_val_on_index then
  dbms_output.put_line('&p_ename' || '은 중복되었습니다');
  dbms_output.put_line('코드: ' || to_char(sqlcode));
  --에러 코드 번호
  dbms_output.put_line('내용: ' || sqlerrm);
  --에러코드 내용
end;
/

set serveroutput off
set verify on

9.
--서버 에러의 이름 선언
--foriegn key를 지울수 없는 에러는 에러명이 설정되어 있지 않아서 이름을 만들어 줌
SET VERIFY OFF
SET SERVEROUTPUT ON

ACCEPT p_ename PROMPT '삭제하고자 하는 사원의 이름을 입력하시오 : '

DECLARE
 v_ename emp.ename%TYPE := '&p_ename';
 v_deptno dept.deptno%TYPE;
 emp_constraint EXCEPTION;
 PRAGMA EXCEPTION_INIT (emp_constraint, -2292);
 --에러코드 -2292번은 에러명이 설정되지 않았음
BEGIN
 SELECT deptno
  INTO v_deptno
  FROM emp
  WHERE ename = UPPER(v_ename);
 DELETE dept
  WHERE deptno = v_deptno;
EXCEPTION
 WHEN NO_DATA_FOUND THEN
  DBMS_OUTPUT.PUT_LINE('&p_ename' || '는 자료가 없습니다.');
 WHEN TOO_MANY_ROWS THEN
  DBMS_OUTPUT.PUT_LINE('&p_ename' || '는 자료가 여러개 있습니다.');
 WHEN emp_constraint THEN
  DBMS_OUTPUT.PUT_LINE('&p_ename' || '는 삭제할 수 없습니다.');
 WHEN OTHERS THEN
  DBMS_OUTPUT.PUT_LINE('기타 에러입니다.');

END;
/
SET VERIFY ON
SET SERVEROUTPUT OFF

10.
--에러 강제 만들기
SET VERIFY OFF
SET SERVEROUTPUT ON

ACCEPT p_deptno PROMPT '부서명 : '

DECLARE
 v_deptno emp.deptno%type := &p_deptno;
 emp_deptno_ck EXCEPTION;
BEGIN
 --부서명이 10,20,30 중 하나를 입력하지 않으면 에러처리함
 IF v_deptno not in (10,20,30) THEN
  RAISE emp_deptno_ck;
 ELSE
  dbms_output.put_line('정상 처리');
 END IF;
EXCEPTION
 WHEN emp_deptno_ck THEN
  dbms_output.put_line('입력오류');
 WHEN others THEN
  dbms_output.put_line('기타오류');


END;
/
SET VERIFY ON
SET SERVEROUTPUT OFF

11.
--프로시저 프로그램을 내장함. 실행속도가 더 빠름
create or replace procedure tel1
is  --( =as, declare)
 v_tel varchar2(10) := '123456';
begin
 v_tel := substr(v_tel,1,3) || '-' || substr(v_tel,4);
 dbms_output.put_line('전화번호:' || v_tel);
end;
/


--프로시저 조회
desc user_procedures;
select object_name, procedure_name from user_procedures;
select text from user_source where name =upper('tel1');

--프로시저 실행
SQL> set serveroutput on
SQL> execute tel1;
SQL> set serveroutput off

--프로시저 실행 다른방법
SQL> set serveroutput on
SQL> exec tel1;
SQL> call tel1();
--함수()처럼 사용가능함 = 입출력이 가능함
SQL> set serveroutput off

--main01파일에 프로시저 실행문 넣음
set serveroutput on
begin
 tel1;
 tel1();
end;
/
set serveroutput off

12.
--프로시저 외부 데이터 받기
create or replace procedure tel2 (
 p_tel in varchar2
 --입력받을 변수의 varchar size 정하지 않음
)
is
 v_tel varchar2(10);
begin
 v_tel := substr(p_tel,1,3) || '-' || substr(p_tel,4);
 dbms_output.put_line('전화번호:' || v_tel);
end;
/

--main03 프로시저 실행 구문
set serveroutput on
begin
 tel2(1234567);
 tel2(4567890);
 tel2(1234321);

end;
/
set serveroutput off

13.
--프로시저 내보내기
create or replace procedure tel3 (
 p_tel out varchar2
 --연산 처리결과를 p_tel로 내보냄
)
is
 v_tel varchar2(10) := '123456';
begin
 p_tel := substr(v_tel,1,3) || '-' || substr(v_tel,4);
end;
/

--SQL PLUS에서 프로시저 리턴값을 받을 변수를 만들고 프린트함
SQL> variable g_tel varchar2(20)
SQL> @c:\oracle\proc04
SQL> exec tel3(:g_tel)
SQL> print :g_tel

--main04 프로시저의 리턴값 받아서 프린트하는 것 실행구문
set serveroutput on
declare
 v_tel varchar2(20);

begin
 tel3(p_tel => v_tel);
 dbms_output.put_line('결과 :' || v_tel);

end;
/
set serveroutput off

14.
--구구단 프로시저 만들기
create or replace procedure gugu (
 p_dan in number
)
is
 v_dan varchar(30);
begin
 dbms_output.put_line(p_dan||'단');
 FOR i in 1..9 LOOP
 v_dan := p_dan || '*' || i || '=' || p_dan*i;
 dbms_output.put_line(v_dan);
 END LOOP;
 dbms_output.put_line(chr(7));
end;
/

--main05 구구단 실행구문
set serveroutput on

begin
 gugu(1);
 gugu(2);
end;
/
set serveroutput off

15.
--구구단 프로시저 입력받아서 내보내기
create or replace procedure gugu (
 p_dan  in number,
 v_result  out varchar2

)
is
 v_tot number;
begin
 FOR i_col in 1..9 LOOP
  v_tot := p_dan * i_col;
  v_result := v_result || p_dan || '*' || i_col || '=' ||v_tot || '    ';
 END LOOP;
end;
/

--SQL PLUS에서의 구구단 프로시저 실행문
SQL> @c:\oracle\proc05
SQL> variable g_result varchar2(100);
SQL> exec gugu(8, :g_result);
SQL> print :g_result;

--PL/SQL에서의 main05 구구단 실행구문
set serveroutput on
declare
 g_result varchar2(2000);

begin
 gugu(8, v_result => g_result);
 dbms_output.put_line(g_result);
end;
/
set serveroutput off

16.
--사원의 이름을 입력받아 속한 부서에 최대 급여와 최소 급여를 출력하는 프로시저 생성
create or replace procedure sawon (
 p_ename  in varchar2,
 v_result  out varchar2

)
is
 v_hisal number;
 v_losal number;
 v_deptno number;
begin
 
 select deptno
  into v_deptno
  from emp
  where ename= upper(p_ename);

 select max(sal), min(sal)
  into v_hisal, v_losal 
  from emp
  group by deptno
  having deptno=v_deptno;

 v_result := '최대급여: '|| v_hisal ||'    최소급여:' || v_losal ;

 
end;
/

--SQL PLUS에서 실행문
SQL> @c:\oracle\proc06
SQL> set serveroutput on
SQL> variable g_result varchar2(2000);
SQL> exec sawon('scott', :g_result);
SQL> variable g_result varchar2(2000);
SQL> exec sawon('scott', :g_result);
SQL> set serveroutput off

17.
--지정한 테이블 입력받아 그 외의 테이블 삭제 프로시저 생성, 삭제 테이블 목록 출력
create or replace procedure droptab (
 p_tab  in varchar2,
 v_result  out varchar2
)
is
 --삭제하면 안되는 테이블 명을 담을 nested table 타입을 정함
 type varchar_table_type is table of varchar2(30)
   index by binary_integer;
 v_tab varchar_table_type;
 v_bol number;
 v_del varchar2(2000);
begin

 FOR tab_record in (select tname from tab) LOOP
 --현재 있는 테이블을 CURSOR로 가져와서 하나하나씩 비교를 위해 꺼냄
  v_bol := 1;
  FOR i in 1..regexp_count(p_tab,',')+1 LOOP
   --쉼표를 기준으로 입력된 문자열을 잘라서 nested table에 넣음
   --LOOP횟수는 쉼표+1 / 대문자 처리 /스페이스바를 없앰
   v_tab(i) := regexp_replace(regexp_substr(upper(p_tab), '[^,]+',1,i),' ','');
   IF tab_record.tname = v_tab(i) THEN
    -- 테이블이 nested table에 있을경우 -1을 곱함 
    v_bol := v_bol*(-1);
   END IF;
  END LOOP;

  IF v_bol=-1 THEN
  -- bol 값이 -1이면 데이터를 보존함
  dbms_output.put_line('보존 : ' || tab_record.tname);
  ELSE
  -- bol 값이 1이면 데이터를 삭제하고, 삭제테이블 목록에 추가함
  v_del := v_del || tab_record.tname || chr(9);
  execute immediate 'drop table '|| tab_record.tname;
  END IF;
 END LOOP;
 dbms_output.put_line('삭제완료');

 --삭제 테이블 목록을 리턴값으로 정함
 v_result :=  '삭제데이터 : ' ||v_del;

 
end;
/

2016년 7월 1일 금요일

02day PL/SQL


1. %TYPE 속성
set serveroutput on
declare
 -- type으로 변수속성 가져옴
 v_deptno  dept.deptno%type;
 v_dname  dept.dname%type;
 v_loc  dept.loc%type;
begin
 --select 순서대로 into 순서를 맞춘다
 --데이터를 채움
 --select 문의 출력결과가 한개여야 함 / 여러개 출력은 에러
 select deptno, dname, loc
 into v_deptno, v_dname, v_loc
 from dept
 where deptno=10;

 dbms_output.put_line('deptno: ' || v_deptno);
 dbms_output.put_line('dname: ' || v_dname);
 dbms_output.put_line('loc: ' || v_loc);
end;
/
set serveroutput off


2.
set serveroutput on
declare
 -- 한번에 모든 컬럼타입을 선언함
 v_dept dept%rowtype;
begin
 --
 select *
 into v_dept
 from dept
 where deptno=10;

 dbms_output.put_line(v_dept.deptno);
 dbms_output.put_line(v_dept.dname);
 dbms_output.put_line(v_dept.loc);
end;
/
set serveroutput off




3.
set serveroutput on
declare
 -- 예제 7788사원의 정보를 출력
 v_emp emp%rowtype;
begin
 --
 select *
 into v_emp
 from emp
 where empno=7788;

 dbms_output.put_line('사원번호 : ' || v_emp.empno);
 dbms_output.put_line('이름 : ' || v_emp.ename);
 dbms_output.put_line('담당업무 : ' || v_emp.job);
 dbms_output.put_line('매니저 : ' || v_emp.mgr);
 dbms_output.put_line('입사일 : ' || v_emp.hiredate);
 dbms_output.put_line('급여 : ' || v_emp.sal);
 dbms_output.put_line('보너스 : ' || v_emp.comm);
 dbms_output.put_line('부서번호 : ' || v_emp.deptno);

end;
/
set serveroutput off

4.
set verify off
set serveroutput on

--입력받기
accept p_empno prompt '사원번호'

declare
 v_emp emp%rowtype;
 -- 입력값 변수 만들기
 v_empno emp.empno%type := &p_empno;
begin
 --
 select *
 into v_emp
 from emp
 where empno=v_empno;

 dbms_output.put_line('사원번호 : ' || v_emp.empno);
 dbms_output.put_line('이름 : ' || v_emp.ename);
 dbms_output.put_line('담당업무 : ' || v_emp.job);
 dbms_output.put_line('매니저 : ' || v_emp.mgr);
 dbms_output.put_line('입사일 : ' || v_emp.hiredate);
 dbms_output.put_line('급여 : ' || v_emp.sal);
 dbms_output.put_line('보너스 : ' || v_emp.comm);
 dbms_output.put_line('부서번호 : ' || v_emp.deptno);

end;
/
set serveroutput off
set verify on

5.
-- 예제 사원명 입력받아서 사원번호, 사원명, 급여, 부서번호, 부서명, 부서위치를 출력하는 스크립트 생성
set verify off
set serveroutput on

--입력받기
accept p_ename prompt '사원명 :'

declare
 v_dept dept%rowtype;
 v_emp emp%rowtype;
 v_ename emp.ename%type := '&p_ename';
begin
 --
 select *
 into v_emp
 from emp
 where ename=v_ename;
 --
 select *
 into v_dept
 from dept
 where deptno=v_emp.deptno;

 dbms_output.put_line('사원번호 : ' || v_emp.empno);
 dbms_output.put_line('이름 : ' || v_emp.ename);
 dbms_output.put_line('급여 : ' || v_emp.sal);
 dbms_output.put_line('부서번호 : ' || v_emp.deptno);
 dbms_output.put_line('부서명 : ' || v_dept.dname);
 dbms_output.put_line('부서위치 : ' || v_dept.loc);

end;
/
set serveroutput off
set verify on

-- 예제 사원명 입력받아서 사원번호, 사원명, 급여, 부서번호, 부서명, 부서위치를 출력하는 스크립트 생성
set verify off
set serveroutput on

--입력받기
accept p_ename prompt '사원명 :'

declare
 v_deptno dept.deptno%type;
 v_loc  dept.loc%type;
 v_dname dept.dname%type;
 v_empno emp.empno%type;
 v_sal emp.sal%type;
 v_deptno2 emp.deptno%type;
 v_ename emp.ename%type := '&p_ename';
begin
 --
 select dept.deptno, dept.loc, dept.dname, emp.empno, emp.sal, emp.ename, emp.deptno
 into v_deptno, v_loc, v_dname, v_empno, v_sal, v_ename, v_deptno2
 from emp
 join dept
 on emp.ename=v_ename AND emp.deptno=dept.deptno;
 --
 dbms_output.put_line('사원번호 : ' || v_empno);
 dbms_output.put_line('이름 : ' || v_ename);
 dbms_output.put_line('급여 : ' || v_sal);
 dbms_output.put_line('부서번호 : ' || v_deptno);
 dbms_output.put_line('부서명 : ' || v_dname);
 dbms_output.put_line('부서위치 : ' || v_loc);

end;
/
set serveroutput off
set verify on


6.
set verify off
set serveroutput on

declare
 --type ~ is record() 형선언
 type emp_record_type is record (
  v_empno  emp.empno%type,
  v_ename  emp.ename%type,
  v_job   emp.job%type,
  v_mgr    emp.mgr%type
 );
 
 -- 변수에 형적용
 v_emp emp_record_type;
begin
 --
 select empno, ename, job, mgr
 into v_emp
 from emp
 where empno=7369;

 dbms_output.put_line(v_emp.v_empno);
 dbms_output.put_line(v_emp.v_ename);
 dbms_output.put_line(v_emp.v_job);
 dbms_output.put_line(v_emp.v_mgr);

end;
/
set serveroutput off
set verify on

7.
set serveroutput on

declare
 x number;
 y number;
begin
 x := 1;
 y := 2;

 dbms_output.put_line('x1 : ' || x);
 dbms_output.put_line('y1 : ' || y);
 
 --내부선언
 declare
  --내부에서 y를 선언했으므로 밖의 y과 구분됨
  y number;
  z number;
 begin
  --내부에서 x를 선언하지 않았으므로 밖의 x값을 바꿈
  x :=3;
  y :=4;
  z :=5;

  dbms_output.put_line('x2 : ' || x);
  dbms_output.put_line('y2 : ' || y);
  dbms_output.put_line('z2 : ' || z);
 end;

 dbms_output.put_line('x3 : ' || x);
 dbms_output.put_line('y3 : ' || y);
 --dbms_output.put_line('z3 : ' || z); 내부변수 밖에서 실행못함
end;
/
set serveroutput off

8.
set serveroutput on

declare
 v_cnt number :=0;
 v_eq boolean;
 v_valid boolean;

 v_n1 number :=1;
 v_n2 number :=2;
 v_empno varchar2(10);

begin
 v_cnt := v_cnt +1;
 dbms_output.put_line(v_cnt);

 v_eq := (v_n1 = v_n2);
 --dbms_output.put_line(v_eq);          불린값을 출력하지 못함
 --dbms_output.put_line(to_char(v_eq)); 불린값을 출력하지 못함

end;
/
set serveroutput off

9.
코드 규약

코드 지정 규약


10.
SET serveroutput on

DECLARE
 v_eq boolean;
 v_n1 number :=1;
 v_n2 number :=2;
BEGIN
 v_eq := (v_n1 = v_n2);

 IF v_eq THEN
  dbms_output.put_line('같습니다.');
 ELSE 
  dbms_output.put_line('다릅니다.');
 END IF;


END;
/
SET serveroutput off

11.
-- 성적을 입력받아서 학점을 출력하는 스크립트 작성
SET verify off
SET serveroutput on

ACCEPT p_score PROMPT '성적입력 :'

DECLARE
 v_score number := &p_score;
BEGIN

 IF v_score >= 90 THEN
  dbms_output.put_line('A');
 ELSIF v_score >= 80 THEN
  dbms_output.put_line('B');
 ELSIF v_score >= 70 THEN
  dbms_output.put_line('C');
 ELSIF v_score >= 60 THEN
  dbms_output.put_line('D');
 ELSE
  dbms_output.put_line('F');
 END IF;


END;
/
SET serveroutput off
SET verify on

12.
-- 이름을 입력받아 업무를 조회하여 업무별로 급여를 갱신하는 SCRIPT를 작성하여라. 
-- 단 PRESIDENT:10%, MANAGER:20%, ANALYST:30%, SALESMAN:40%, CLERK:50%를 적용
SET VERIFY OFF
SET SERVEROUTPUT ON

ACCEPT p_name PROMPT ' 이 름: '

DECLARE
 v_empno emp.empno%TYPE;
 v_name emp.ename%TYPE := UPPER('&p_name');
 v_sal emp.sal%TYPE;
 v_job emp.job%TYPE;

BEGIN
 SELECT empno,job
  INTO v_empno,v_job
  FROM emp
  WHERE ename = v_name;

 IF v_job = 'PRESIDENT' THEN
  v_sal := v_sal * 1.1;
 ELSIF v_job = 'MANAGER' THEN
  v_sal := v_sal * 1.2;
 ELSIF v_job = 'ANALYST' THEN
  v_sal := v_sal * 1.3;
 ELSIF v_job = 'SALESMAN' THEN
  v_sal := v_sal * 1.4;
 ELSIF v_job = 'CLERK' THEN
  v_sal := v_sal * 1.5;
 ELSE
  v_sal := NULL;
 END IF;

 UPDATE emp
  SET sal = v_sal
  WHERE empno = v_empno;
 DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || '개의 행이 갱신되었습니다.');

EXCEPTION
 WHEN NO_DATA_FOUND THEN
  DBMS_OUTPUT.PUT_LINE(v_name || '는 자료가 없습니다.');
 WHEN TOO_MANY_ROWS THEN
  DBMS_OUTPUT.PUT_LINE(v_name || '는 동명 이인입니다.');
 WHEN OTHERS THEN
  DBMS_OUTPUT.PUT_LINE('기타 에러가 발생 했습니다.');
 END;
/
SET VERIFY ON
SET SERVEROUTPUT OFF

13. LOOP
SET VERIFY OFF
SET SERVEROUTPUT ON

DECLARE
 v_cnt number :=1;

BEGIN
 LOOP
  dbms_output.put_line(v_cnt);
  v_cnt := v_cnt +1;
  
  
  /*
  IF v_cnt >=10 THEN
   exit;
  END IF;
  */
  --위 코드를 줄임
  exit WHEN v_cnt >=10;
 END LOOP;
END;
/
SET SERVEROUTPUT OFF
SET VERIFY OFF

14.FOR LOOP
SET VERIFY OFF
SET SERVEROUTPUT ON

DECLARE

BEGIN
 FOR idx in reverse 1..10 LOOP
  dbms_output.put_line(idx);
 END LOOP;
END;
/
SET SERVEROUTPUT OFF
SET VERIFY OFF

15. WHILE LOOP
SET VERIFY OFF
SET SERVEROUTPUT ON

DECLARE
 v_cnt number :=1;
BEGIN
 WHILE v_cnt <= 10 LOOP
  dbms_output.put_line(v_cnt);
  v_cnt := v_cnt + 1;
 END LOOP;
END;
/
SET SERVEROUTPUT OFF
SET VERIFY OFF

16. 이중 LOOP
SET VERIFY OFF
SET SERVEROUTPUT ON

DECLARE

BEGIN
 FOR i_idx in 1..5 LOOP
  FOR j_idx in 1..3 LOOP
   dbms_output.put_line(i_idx || '/' || j_idx);
  END LOOP;
 END LOOP;
END;
/
SET SERVEROUTPUT OFF
SET VERIFY OFF

17.
--별표 피라미드 만들기
SET VERIFY OFF
SET SERVEROUTPUT ON

DECLARE
 v_star varchar2(30) := null;
BEGIN
 FOR i_idx in 1..10 LOOP
  FOR j_idx in 1..i_idx LOOP
   dbms_output.put('★');
  END LOOP;
  dbms_output.put_line('');
 END LOOP;

 FOR k_idx in 1..10 LOOP
  v_star := v_star || '☆';
  dbms_output.put_line(v_star);
 END LOOP;
END;
/
SET SERVEROUTPUT OFF
SET VERIFY OFF

18.
SET SERVEROUTPUT ON

DECLARE
 --배열형태 varray / table

 --형선언  (20) 데이터입력수 20개까지
 type varray_type1 is varray(20) of number;
 type varray_type2 is varray(20) of varchar2(20);
 
 --변수 선언
 varray1  varray_type1;
 varray2  varray_type2;
BEGIN
 varray1 := varray_type1(10,20,30,50);
 --인덱스가 1부터 시작함
 dbms_output.put_line(varray1(1));
 varray1(1) :=100;
 dbms_output.put_line(varray1(1));

 --배열의 크기
 dbms_output.put_line(varray1.count);

 --FOR문으로 데이터 모두 찍기
 FOR i in 1..varray1.count LOOP
  dbms_output.put(rpad(varray1(i),12));
    --rpad는 간격을 벌림
 END LOOP;
 dbms_output.put_line('');


 varray2 := varray_type2('AA','BB','CC', 'DD', 'EE');

 --FOR문으로 데이터 모두 찍기
 FOR i in 1..varray2.count LOOP
  dbms_output.put(rpad(varray2(i),12));
 END LOOP;
 dbms_output.put_line('');

END;
/
SET SERVEROUTPUT OFF

19.
SET SERVEROUTPUT ON

DECLARE
 --배열형태 varray / table

 --형선언
 type number_table_type is table of number
  index by binary_integer;
 --변수선언
 v_table number_table_type;

BEGIN
 --변수를 하나씩 추가해서 집어넣을 수 있음
 v_table(1) := 10;
 v_table(2) := 20;
 v_table(3) := 30;
 v_table(4) := 40;
 v_table(5) := 50;
 
 --테이블 사이즈
 dbms_output.put_line(v_table.count);

 --데이터 모두 출력
 FOR i in 1..v_table.count LOOP
  dbms_output.put_line(v_table(i));
 END LOOP;

END;
/
SET SERVEROUTPUT OFF

20.
SET SERVEROUTPUT ON

DECLARE
 --커서
 CURSOR emp_cursor is
  SELECT empno, ename, sal 
  FROM emp
  WHERE deptno =10;
 --변수선언
 v_empno  emp.empno%type;
 v_ename  emp.ename%type;
 v_sal  emp.sal%type;

BEGIN
 --
 OPEN emp_cursor;
 LOOP
  FETCH emp_cursor into v_empno, v_ename, v_sal;
  exit when emp_cursor%notfound;

  dbms_output.put_line(v_empno);
  dbms_output.put_line(v_ename);
  dbms_output.put_line(v_sal);
  --빈줄을 포함함
  dbms_output.put_line(chr(7));
 END LOOP;

 CLOSE emp_cursor;

END;
/
SET SERVEROUTPUT OFF

SET SERVEROUTPUT ON

DECLARE
 --커서 전체 열을 다가져오는 방법
 CURSOR emp_cursor is
  SELECT *
  FROM emp
  WHERE deptno =10;
 --변수선언
 v_emp  emp%rowtype;

BEGIN
 --
 OPEN emp_cursor;
 LOOP
  FETCH emp_cursor into v_emp;
  exit when emp_cursor%notfound;

  dbms_output.put_line(v_emp.empno);
  dbms_output.put_line(v_emp.ename);
  dbms_output.put_line(v_emp.sal);
  
  --빈줄을 포함함
  dbms_output.put_line(chr(7));
 END LOOP;

 CLOSE emp_cursor;

END;
/
SET SERVEROUTPUT OFF


21.
SET VERIFY OFF
SET SERVEROUTPUT ON

ACCEPT p_deptno PROMPT ' 부서번호를 입력하시오 : '

DECLARE
 --변수선언
 v_deptno emp.deptno%type := &p_deptno;
 v_empno  emp.empno%type;
 v_ename  emp.ename%type;
 v_sal  emp.sal%type;
 v_sal_total  NUMBER(10,2) := 0;
 --커서
 CURSOR emp_cursor IS
  SELECT empno,ename,sal
  FROM emp
  WHERE deptno = v_deptno
  ORDER BY empno;

BEGIN
 --
 OPEN emp_cursor;
 DBMS_OUTPUT.PUT_LINE('사번    이 름        급 여');
 DBMS_OUTPUT.PUT_LINE('---- ---------- ----------------');
 LOOP
  FETCH emp_cursor INTO v_empno,v_ename,v_sal;
  EXIT WHEN emp_cursor%NOTFOUND;
  v_sal_total := v_sal_total + v_sal;
  DBMS_OUTPUT.PUT_LINE(RPAD(v_empno,6) ||
  RPAD(v_ename,12) || LPAD(TO_CHAR(v_sal,'$99,999,990.00'),16));
 END LOOP;
 DBMS_OUTPUT.PUT_LINE('----------------------------------');
 DBMS_OUTPUT.PUT_LINE(RPAD(TO_CHAR(v_deptno),2) || '번 부서의 합 ' ||
  LPAD(TO_CHAR(v_sal_total,'$99,999,990.00'),16));
 CLOSE emp_cursor;

END;
/
SET SERVEROUTPUT OFF
SET VERIFY ON

22.
SET SERVEROUTPUT ON

DECLARE
 
BEGIN
 --
 FOR dept_record in (select * from dept) LOOP
  dbms_output.put_line(dept_record.deptno);
  dbms_output.put_line(dept_record.dname);
  dbms_output.put_line(dept_record.loc);
  dbms_output.put_line(chr(7));
 END LOOP;

END;
/
SET SERVEROUTPUT OFF

23.
--테이블의 목록을 출력하는 스크립트 생성
SET SERVEROUTPUT ON

DECLARE

BEGIN
 --
 FOR tab_record in
  (select * from tab where tabtype =upper('table')) LOOP
  dbms_output.put_line(rpad(tab_record.tname,30) ||
  rpad(tab_record.tabtype,6));
 END LOOP;

END;
/
SET SERVEROUTPUT OFF

24.
--주민번화 확인
SET verify off
SET SERVEROUTPUT ON

ACCEPT p_jumin PROMPT '주민번호입력 :'
 
DECLARE
 --입력값 변수 선언
 v_jumin varchar2(14) := '&p_jumin';
 --숫자하나씩 넣을 변수선언
 v_result number;
 --곱하기할 숫자 어레이만듬
 type varray_type1 is varray(12) of number;
 v_array varray_type1;

BEGIN
 v_array := varray_type1(2,3,4,5,6,7,8,9,2,3,4,5);
 v_result  := 0;

 IF length(v_jumin)!=14 THEN
  dbms_output.put_line('******-******* 형식으로 입력하세요');
 ELSE
  --숫자만 잘라서 붙임
  v_jumin := substr(v_jumin,1,6)||substr(v_jumin,8,7);
 
  --곱하고 축적함
  FOR i in 1..12 LOOP
   v_result := v_result + to_number(substr(v_jumin,i,1))*v_array(i);
  END LOOP;
  --나눈 나머지 계산
  v_result := 11-mod(v_result,11);
  v_result := mod(v_result,10);
 
  IF v_result=to_number(substr(v_jumin,13,1)) THEN
   dbms_output.put_line('정확한 주민번호입니다');
  ELSE
   dbms_output.put_line('부정확한 주민번호입니다');
  END IF;
 
 END IF;


END;
/
SET SERVEROUTPUT OFF
SET verify on