230712 PL/SQL 2 [

권주희·2023년 7월 20일

[2023/07/20 점심시간 문제]
사원번호를 입력하면 해당 사원의 입사일이 출력되게 PLSQL 프로그램밍을 하세요 !

사원 번호를 입력하세요 ~ 7788
입사일:  82/12/22

복습

  1. PL/SQL 을 왜 배워야 하는지?
  2. PL/SQL 이 무엇인지?
  3. 오라클 PL/SQL 정규교재
    • 1장 : PL/SQL 의 종류와 기본블럭의 구조
      • 익명 블럭 : 이름x (나머지는 다 이름O)
      • 프로시저
      • 함수 (FUNTION)
      • 트리거
      • 패키지
    • 기본 블럭의 구조
      • declare : 선언절 (선택)
      • begin : 실행절 (필수)
      • exception : 예외처리절 (선택)
      • end; : 종료절 (필수)
    • 2장 : PL/SQL 변수
      • 스칼라 변수 : 단일값을 저장하는 변수 --- 여기까지 어제 내용 ---
      • 조합 변수 : 여러개값을 저장하는 변수
      • 바인드 변수 : 호스트 변수
      • ❗'%type' 중요❗

21. 부울 변수 선언

부울 변수

  • TRUE, FALSE 및 NULL 값만 부울 변수에 할당할 수 있습니다.
  • 조건식은 논리 연산자 AND 및 OR 그리고 단항 연산자 NOT 을 사용하여 변수 값을 확인합니다.
  • 변수는 항상 TRUE, FALSE 또는 NULL을 반환합니다.
  • 산술, 문자 및 날짜 표현식은 부울 값을 반환하는 데 사용될 수 있습니다.

✅ 부울 변수 선언은 다음과 같다.

v_bool  boolean;

✅ 조건식은 논리 연산자 (and, or, not) 을 이용해서 변수의 값을 확인한다.
✅ 뒤에서 배울 if 문과 while loop 문에서 유용한 변수다.

emp_sal1  := 50000;
emp_sal2  := 60000;

emp_sal1 < emp_sal2

➡️ true

declare
 flag boolean := false;
begin 
 flag := true;
end;/

따로 출력되는거 없이 프로시저 성공 문구만 뜬다.

❓ 뭔소린지 하나도 모르겠는디

23. LOB 데이터 유형 변수


LOB (대형 객체) 는 다량의 데이터를 저장하는 것을 의미합니다.
(큰 텍스트, 이미지, 동영상, 국가별 문자 텍스트를 저장)
데이터베이스 블록 크기에 따라 최대 128TB까지, 구조화되지 않은 데이터 블록을 저장할 수 있습니다.**

  • clob : 큰 텍스트
  • blob : 이미지
  • bfile : 동영상
  • nclob : 국가별 언어 큰 텍스트

24. 조합 데이터 유형


컬렉션 : 마치 테이블에 저장하듯이 세로로 저장할 수 있다. (번호도 indexing 하듯 붙는다)
스칼라 서브쿼리는 하나만 저장하는데, 컬렉션은 4개를 한번에 저장했다.

변수의 종류 3가지

  • 스칼라 변수
  • 조합변수
    • 레코드 : 여러개의 데이터 값을 레코드 단위 (가로로) 로 담는 변수
    • 컬렉션 : 여러개의 데이터 값을 테이블의 행처럼 (세로로) 담는 변수
  • 바인드 변수

25. 바인드 변수

바인드 변수

  • 호스트 환경에서 생성됩니다.
    • 호스트 환경 : PL/SQL 블럭 외의 환경
  • 호스트 환경에서 사용될 수 있어서 호스트 변수라고도 합니다.
  • VARIABLE 키워드를 사용하여 생성됩니다.
  • SQL 문과 PL/SQL 블록에서 사용됩니다.
  • PL/SQL 블록이 실행된 후에도 액세스할 수 있습니다.
  • 앞에 콜론을 사용하여 참조합니다.
  • PRINT 명령을 사용하여 값을 출력할 수 있습니다.

❗비유적으로, 텀블러 - 호스트 변수 (카페 밖에서도 안에서도 자유롭게 쓸 수 있는)

실습

variable v_salaly number       -> 외부의 호스트
begin
 select sal into :v_salary     -> : 를 붙여서 내부에서 사용하게 한다.
  from emp
  where empno = 7788;
end;
/

print v_salary                -> 출력

❗where sal = :v_salart; -> ; 붙여줘!야함!!

✔️ 바인드변수 (호스트변수) 를 PL/SQL 블럭과 sql 에서 사용하려면, 콜론 (:) 을 앞에 붙여줘야한다.
✔️ 바인드변수 선언시 숫자 변수는 number 라고 이름 옆에 쓰는데, number(10) 이런식으로 쓰면 오류난다.
✔️ 문자는 varchar2 만 써도되고, varchar2(10) 길이 써도 된다.

문제 12.
아래의 코드를 실행하는데 autoprint 기능을 켜고 실행하시오

variable v_salaly number
set autoprint on

declear 
 v_empno  number(6) := &empno;     -> 치환변수

begin
  select sal into :v_salary
  from emp
  where empno = v_empno;

end;

➡️ 사원번호를 입력하면 월급을 볼수 있게 된다.
print 적지 않아도 자동 출력된다!!! set autoprint on

✅ 값을 입력받아서 같은 sql 을 반복해서 수행하고 싶을때 유용한 변수 : 치환변수

✅ &empno 대신에 &사원번호 로 써도 됨. 팝업창에 쓴대로 뜸

❓팝업창같은거 띄우는거 설정을 안했는데 어케 되는건지! 뭐때문에?

문제 13. 위의 코드를 활용해서 다음과 같이 수행되게 하시오

ename 의 값을 입력하세요
variable v_salaly number
set autoprint on

declear 
 v_ename  varchar2(10) := '&ename';   --> 문자라서 '' 둘러줘야함

begin
  select sal into :v_salary
  from emp
  where ename = v_ename;

end;

✔️ 문자와 날짜는, 선언절 치환변수 쓸때 '' 둘러줘야함!! ('&ename')

입력할 때 조건 넣어주기

ex) 사원이름에 소문자, 대문자 상관없이 써도되게 하기 ⬇️

문제 14.
위의 코드를 다시 수정해서 이번에는 이름을 입력할 때 소문자로 입력하던지 대문자로 입력하던지 무조건 결과가 나오게 코드를 수정하시오

variable v_salaly number
set autoprint on

declear 
 v_ename  varchar2(10) := upper('&사원이름');

begin
  select sal into :v_salary
  from emp
  where ename = v_ename;

end;

✔️ upper를 선언절에 사용해서 대문자로 바꿔준다!

where upper(ename) = v_ename;

해도 결과는 나오나, 좌변을 가공한 것이기 때문에 index 가 만들어지지않는다.
-> 꼭 써야하면 함수기반인덱스를 사용해야하는데 나중에 튜닝할때 배운데욥

🔎 퀴즈!

TYPE 속성 맞는거 골라라! (1,3,4)

  1. 데이터베이스 열 정의에 따라 변수를 선언하는 데 사용됩니다.
  2. 데이터베이스 테이블 또는 뷰의 열 모음에 따라 변수를 선언하는 데 사용됩니다.
    -> 열 모음에 따라 : %rowtype (레코드 변수) 를 말하는 것이다. (나중에 6단원에서 배움)
  3. 선언된 또 다른 변수의 정의에 따라 변수를 선언하는 데 사용됩니다.
  4. 데이터베이스 테이블 및 열 이름이나 선언된 변수의 이름이 접두어로 붙습니다.
    -> v_ename emp.ename%type ㅇㅇ맞다.

3장. 실행문 작성

26. PL/SQL 용어정리

  • 식별자 : 변수명 (v_ename, v_sal)
  • 구분자 : 연산자, 세미콜론 (+,-,;)
  • 리터럴 : 문자 데이터값, 숫자 데이터값 (scott, 7788)
  • 주석 : parser에 의해서 실행되지 않게하고 싶을때 사용 (오라클에 회색되는거)
    • 한줄 주석 : v_ename varchar2(10) ; -- 이름을 담을 변수를 선언합니다.
    • 여러줄 주석 : / 프로그램이름 : 어쩌구 작성자 : 어쩌구 /

27. PL/SQL 블럭 작성 지침

  1. 문자와 날짜는 반드시 양쪽에 싱글 쿼테이션 마크를 둘러준다.
  2. 가독성을 높이기 위해서 적절하게 공백과 들여쓰기를 해줍니다.
    (sqldeveloper 컨트롤+F7 혹은 마우스 오른쪽 클릭->format 으로도 가능)
    근데 너무 오바되서 나오니까, 드래그 한다음에 tab 키 눌러서 앞에 공백 만드는게 나을듯!

28. PL/SQL 에서 사용 가능/불가능한 함수

  • 프로시저문 (PL/SQL) 에서 사용할 수 있는 함수
    • 단일 행 함수 : 문자, 날짜, 숫자, 변환, 일반 (upper, nvl, 등등..)
  • 프로시저문 (PL/SQL) 에서 사용할 수 없는 함수
    • DECODE : 단일행함수지만 사용할 수 없다.
    • 그룹 함수

프로시저문에서 사용할 수 없는 함수 -> SQL에서는 사용할 수 있다. 오해 놉!

예제. 문자를 입력하게 하고 문자의 철자의 갯수를 출력하는 PL/SQL 문을 작성하시오

set serveroutput on

accept  p_str  prompt '문자열을 입력하시오'

declare
       v_str  varchar2(100) := '&p_str';
       v_result  number(20);
begin
       v_result := length( v_str );
       dbms_output.put_line( v_result );
end;
/

문제15. (점심시간 문제)
위의 코드를 수정해서 문자열을 물어보게하고,
문자열을 입력하면 해당 문자열의 제일 끝 철자가 출력되게 하시오.

set serveroutput on

accept  p_str  prompt '문자열을 입력하시오'

declare
       v_str  varchar2(10) := '&p_str';
       v_result  varchar2(10);
begin
       v_result := substr(v_str,-1,1);
       dbms_output.put_line( v_result );
end;
/

PL/SQL에서 DECODE 사용

PL/SQL 문장으로는 사용불가능

문제 16. 숫자를 물어보게 하고, 숫자를 입력해서 숫자를 1을 입력하면 true 가 출력되게 하고
0 을 입력하면 false 를 출력하게 하시오

accept  p_num  prompt '숫자를 입력하시오'

declare
       v_num  number(10) := '&p_num';
       v_result  varchar2(10);          -> true or false 는 문자니까!
begin
       v_result := decode(v_num,1,'true', 0,'false');
       dbms_output.put_line( v_result );
end;
/

begin 절에 sql 문장으로 쓰면 사용 가능!

문제17. sql문장에 DECODE 를 써서 위의 결과가 실행되게 하시오

set serveroutput on
accept  p_num  prompt '숫자를 입력하시오'

declare
       v_num  number(10) := '&p_num';
       v_result  varchar2(10);
begin
      select decode(v_num,1,'true', 0,'false') into v_result
      from dual;
      dbms_output.put_line( v_result );
end;
/

29. PL/SQL 에서의 시퀀스(sequence) 사용법

(은행의 번호표 기계 생각하기)

예제.
1. my_seq 라는 이름으로 시퀀스를 생성

create sequence my_seq
 start with 1
 increment by 1
 maxvalue 100;
  1. my_seq 를 사용하는 PL/SQL 코드 작성
set serveroutput on
declare
 v_new_id   number(10);
begin
 v_new_id  := my_seq.nextval;
 dbms_output.put_line(v_new_id);
end;
/


번호 쭉쭉 생긴답 (100까지 생김)

v_new_id := my_seq.nextval;

30. PL/SQL 에서의 데이터 유형 변환

  • 두 가지 유형
    • 암시적 변환
    • 명시적 변환
  • 함수:
    • TO_CHAR
    • TO_DATE
    • TO_NUMBER
    • TO_TIMESTAMP

✅ SQL에서의 암시적 유형 변환

select ename, sal
 from emp
 where sal='3000';

-> sal 은 숫자형, 3000은 숫잔데 '' 를 붙혀서 숫자형으로 변환됨

✅ PL/SQL 에서의 암시적 유형 변환

1. 02-Feb-2000 이 현재 내가 접속한 세션의 날짜 포맷과 일치해서
오라클이 알아서 문자형 --> 날짜형 으로 암시적 형변환 한것
2. 암시적 형변환에 실패한 케이스 (February 02, 2000) 이 현재 접속한 세션의 날짜 포맷이 아니기 때문에 실패했다.
3. 그래서, to_date 함수를 이용해서 명시적으로 형변환을 해줘야한다.

현재 접속한 세션의 날짜 형식 확인하기

select * from nls_session_parameters;
              -> (national languege support)


➡️ 현재 포맷이 RR/MM/DD 라는 것을 알 수 있다.

문제 18.
암시적 형변환이 PL/SQL 에서 일어나는 경우를 테스트하시오

set serveroutput on
declare
  v_sal  emp.sal%type := 0;
  v_hiredate emp.hiredate%type := '23/07/20';
begin
  dbms_output.put_line( v_sal );
  dbms_output.put_line( v_hiredate );
end;
/


➡️ 암시적 형변환 성공 (문자형 -> 날짜형)
확실한 방법은,

v_hiredate emp.hiredate%type := to_date ('23/07/20','RR/MM/DD');

문제 19.
문제 18번 코드가 책에 나온것 처럼 암시적형변환 실패할 수 있도록
날짜를 아래와 같이 영어로 변경해서 실행해보시오

set serveroutput on
declare
  v_sal  emp.sal%type := 0;
  v_hiredate emp.hiredate%type := 'JULY 20,2023';
begin
  dbms_output.put_line( v_sal );
  dbms_output.put_line( v_hiredate );
end;
/


에러 발생 에러 발생

날짜 형식 바꾸기

문제 20.
문제 19번 코드에 명시적 형변환 함수 to_date 를 사용하여
'JULY 20,2023' 이 포맷을 그대로 사용하더라도 에러가 나지 않도록 코드를 수정하시오

alter session set nls_date_language='english';
set serveroutput on
declare
  v_sal  emp.sal%type := 0;
  v_hiredate emp.hiredate%type := to_date('July 20,2023','MONTH DD,YYYY');
begin
  dbms_output.put_line( v_sal );
  dbms_output.put_line( v_hiredate );
end;
/

여기서부터 조퇴함


💡 날짜언어가 korean으로 되어져 있어도 코드레벨에서 에러가 안나게 하는 코드

SET SERVEROUTPUT ON
DECLARE
v_sal emp.sal%TYPE := 0 ;
v_hiredate emp.hiredate%TYPE := TO_DATE('February/02/2000','Month/DD/YYYY', 'NLS_DATE_LANGUAGE=ENGLISH');

BEGIN
dbms_output.put_line( v_sal );
dbms_output.put_line( v_hiredate );
END;
/

to_date()안에 'NLS_DATE_LANGUAGE=ENGLISH' 혹은 'NLS_DATE_LANGUAGE=AMERICAN' 넣어주기
❓ 코드레벨이란 이 코드에서만 !

PL/SQL 중첩 블록 이해하기

✅ 서브쿼리에서 어떤값을 출력하여 메인쿼리에서 사용한 것 처럼, 서브블럭에서 어떤 데이터를 메인블럭에서 사용한다. (그냥 서브쿼리 생각하면 이해가 쉽다는 이야기임)
PL/SQL 블럭을 중첩하는 이유
1. 여러 업무 요구사항을 지원하기 위해서 실행
2. 실행섹션에 논리적으로 많은 기능들이 포함되어져 있는 경우

예제

DECLARE
    v_outer_variable VARCHAR2(20) := 'GLOBAL VARIABLE';
    // 여기 전역(글로벌)변수는 내부에 들어가서 사용할 수 있다.
BEGIN
    DECLARE
        v_inner_variable VARCHAR2(20) := 'LOCAL VARIABLE';
        // 이 변수는 내부 블럭에서만 액세스할 수 있다.
    BEGIN
        dbms_output.put_line(v_inner_variable);
        dbms_output.put_line(v_outer_variable);
        
    END;
    dbms_output.put_line(v_outer_variable);
END;

출력 결과 ↓

문제 21. 위 예제의 v_inner_variable(내부블럭)이 내부블럭에서만 사용될 수 있고, 외부에서도 사용될 수 있는지 확인해보기

DECLARE
    v_outer_variable VARCHAR2(20) := 'GLOBAL VARIABLE';
BEGIN
    DECLARE
        v_inner_variable VARCHAR2(20) := 'LOCAL VARIABLE';
    BEGIN
        dbms_output.put_line(v_inner_variable);
        dbms_output.put_line(v_outer_variable);
    END;
    dbms_output.put_line(v_inner_variable); //여기 외부로 실행시켜보기
    dbms_output.put_line(v_outer_variable);
END;

내부블럭 변수는 외부 블럭에서 사용될 수 없습니다!

변수 범위 가시성


외부블럭과 내부블럭이 있다. 바깥쪽(외부) 변수 이름과 내부 변수명이 같은 이름이면 어떤것이 먼저 실행될까 -> 내부가 먼저 실행된다.
그래서 아들의 생일과 아빠의 생일이 잘못 출력되고있다.

DECLARE
    v_father_name   VARCHAR2(20) := 'Patrick';
    v_date_of_birth DATE := '72/04/20';
BEGIN
    DECLARE
        v_child_name    VARCHAR2(20) := 'Mike';
        v_date_of_birth DATE := '02/12/12';
    BEGIN
        dbms_output.put_line('Father''s Name: ' || v_father_name);
        dbms_output.put_line('Date of Birth: ' || outer.v_date_of_birth);
        dbms_output.put_line('Child''s Name: ' || v_child_name);
    END;

    dbms_output.put_line('Date of Birth: ' || v_date_of_birth);
END;
/

그렇다면 외부 변수를 출력하고싶다면(위 결과 제대고 만드려면)!!

문제 22. 위 결과가 제대로 출력되도록 <<outer>>레이블을 사용해보기

BEGIN << outer >> 
    DECLARE
        v_father_name   VARCHAR2(20) := 'Patrick';
        v_date_of_birth DATE := '72/04/20';
    BEGIN
        DECLARE
            v_child_name    VARCHAR2(20) := 'Mike';
            v_date_of_birth DATE := '02/12/12';
        BEGIN
            dbms_output.put_line('Father''s Name: ' || v_father_name);
            dbms_output.put_line('Date of Birth: ' || outer.v_date_of_birth);
            dbms_output.put_line('Child''s Name: ' || v_child_name);
            dbms_output.put_line('Date of Birth: ' || v_date_of_birth);
        END;
    END;
END outer;
/


잘 나옵니다!!

< 문제 23~29 관련 이미지>

문제 23. 아래 번호의 코드가 실행하는 결과를 기술하시오

BEGIN << outer >> 
    DECLARE
        v_sal      NUMBER(7, 2) := 60000;
        v_comm     NUMBER(7, 2) := v_sal * 0.20;
        v_message  VARCHAR2(255) := ' eligible for commission';

    BEGIN
        DECLARE
            v_sal         NUMBER(7, 2) := 50000;
            v_comm        NUMBER(7, 2) := 0;
            v_total_comp  NUMBER(7, 2) := v_sal + v_comm;

        BEGIN
            v_message := 'CLERK not' || v_message;
            outer.v_comm := v_sal * 0.30;
            dbms_output.put_line(v_message); -- 답:
        END;

        v_message := 'SALESMAN' || v_message;
    END;
END outer;
/

✅ 답 : CLERK not eligible for commission

문제 24.

BEGIN << outer >> 
  DECLARE
        v_sal      NUMBER(7, 2) := 60000;
        v_comm     NUMBER(7, 2) := v_sal * 0.20;
        v_message  VARCHAR2(255) := ' eligible for commission';

    BEGIN
        DECLARE
            v_sal         NUMBER(7, 2) := 50000;
            v_comm        NUMBER(7, 2) := 0;
            v_total_comp  NUMBER(7, 2) := v_sal + v_comm;

        BEGIN
            v_message := 'CLERK not' || v_message;
            outer.v_comm := v_sal * 0.30;

        END;
        v_message := 'SALESMAN' || v_message;
        dbms_output.put_line(v_total_comp);  -- 답:

    END;
END outer;
/

✅ 답: 내부 블럭을 외부에서 호출할 수 없으므로 에러가 난다.(?)

문제 25. 아래의 변수가 출력되는 값이 무엇인가?

BEGIN << outer >> 
  DECLARE
        v_sal      NUMBER(7, 2) := 60000;
        v_comm     NUMBER(7, 2) := v_sal * 0.20;
        v_message  VARCHAR2(255) := ' eligible for commission';

    BEGIN
        DECLARE
            v_sal         NUMBER(7, 2) := 50000;
            v_comm        NUMBER(7, 2) := 0;
            v_total_comp  NUMBER(7, 2) := v_sal + v_comm;

        BEGIN
            v_message := 'CLERK not' || v_message;
            outer.v_comm := v_sal * 0.30;
            dbms_output.put_line( v_comm); --  답:  

        END;
        v_message := 'SALESMAN' || v_message;

    END;
END outer;
/

✅ 답: 0

문제 26. 다음의 값이 출력되는 결과?

BEGIN << outer >> 
  DECLARE
        v_sal      NUMBER(7, 2) := 60000;
        v_comm     NUMBER(7, 2) := v_sal * 0.20;
        v_message  VARCHAR2(255) := ' eligible for commission';

    BEGIN
        DECLARE
            v_sal         NUMBER(7, 2) := 50000;
            v_comm        NUMBER(7, 2) := 0;
            v_total_comp  NUMBER(7, 2) := v_sal + v_comm;

        BEGIN
            v_message := 'CLERK not' || v_message;
            outer.v_comm := v_sal * 0.30;
            dbms_output.put_line( outer.v_comm); --  답:  

        END;
        v_message := 'SALESMAN' || v_message;

    END;
END outer;
/


✅ 답: 15000

문제 27.

BEGIN << outer >> 
  DECLARE
        v_sal      NUMBER(7, 2) := 60000;
        v_comm     NUMBER(7, 2) := v_sal * 0.20;
        v_message  VARCHAR2(255) := ' eligible for commission';

    BEGIN
        DECLARE
            v_sal         NUMBER(7, 2) := 50000;
            v_comm        NUMBER(7, 2) := 0;
            v_total_comp  NUMBER(7, 2) := v_sal + v_comm;

        BEGIN
            v_message := 'CLERK not' || v_message;
             dbms_output.put_line( outer.v_comm);  -- 답: 
            outer.v_comm := v_sal * 0.30;
       

        END;
        v_message := 'SALESMAN' || v_message;

    END;
END outer;
/

✅ 답: 12000

문제 28. 다음의 변수가 출력하는 결과는?

BEGIN << outer >> 
  DECLARE
        v_sal      NUMBER(7, 2) := 60000;
        v_comm     NUMBER(7, 2) := v_sal * 0.20;
        v_message  VARCHAR2(255) := ' eligible for commission';

    BEGIN
        DECLARE
            v_sal         NUMBER(7, 2) := 50000;
            v_comm        NUMBER(7, 2) := 0;
            v_total_comp  NUMBER(7, 2) := v_sal + v_comm;

        BEGIN
            v_message := 'CLERK not' || v_message;
            outer.v_comm := v_sal * 0.30;
       
        END;
        
      v_message := 'SALESMAN' || v_message;
      dbms_output.put_line(v_comm);  -- 답: 

    END;
END outer;
/

✅ 외부 DECLARE만 확인하면 12000 이지만, 내부 BEGIN에 확인하면 outer.v_comm := v_sal * 0.30; 로 외부 v_comm값이 변경되었으므로 정답은 15000입니다!

문제 29. 다음의 변수가 출력하는 결과는?

BEGIN << outer >> 
  DECLARE
        v_sal      NUMBER(7, 2) := 60000;
        v_comm     NUMBER(7, 2) := v_sal * 0.20;
        v_message  VARCHAR2(255) := ' eligible for commission';

    BEGIN
        DECLARE
            v_sal         NUMBER(7, 2) := 50000;
            v_comm        NUMBER(7, 2) := 0;
            v_total_comp  NUMBER(7, 2) := v_sal + v_comm;

        BEGIN
            v_message := 'CLERK not' || v_message;
            outer.v_comm := v_sal * 0.30;
       
        END;
        v_message := 'SALESMAN' || v_message;
       dbms_output.put_line(v_message);  -- 답: 

    END;
END outer;
/


✅ 답: SALESMANCLERK not eligible for commission

PL/SQL 연산자

문제 30. 이름을 물어보고, 이름을 입력하면 해당 사원의 월급이 출력되는 PL/SQL 코드를 작성하시오
SCOTT넣으면 3000 나오게 !

set  serveroutput  on
accept   p_ename  prompt  '이름을 입력하세요!'
declare
            v_ename     emp.ename%type := upper('&p_ename');
            v_sal       emp.sal%type; 
begin
           select  sal into  v_sal
           from emp 
           where ename = v_ename;
        
dbms_output.put_line( v_sal );
end;
/

문제 31. 위 코드 수정해서 이름을 물어보게하고, 이름을 입력하면 연봉이 출력되게 하시오 연봉 -> (월급 + 커미션) x12

scott 의 연봉은 ---- 입니다.

처음에 쓴 답
: v_total의 초기값에 아예 다 만들어버리고 begin절에서 그값을 출력만 하고싶었는데 에러가 났다. 그래서 select 절에서 다시 연산을 했음.
1.

set  serveroutput  on
accept   p_ename  prompt  '이름을 입력하세요!'
declare
            v_ename     emp.ename%type := upper('&p_ename');
            v_sal       emp.sal%type; 
            v_comm      emp.comm%type; 
            v_total     number(10,2) := (v_sal + nvl(v_comm,0)) * 12;
begin
           select  (sal + nvl(comm,0)) * 12 into v_total
           from emp 
           where ename = v_ename;
  
dbms_output.put_line( v_ename || '의 연봉은' || v_total || '입니다!');
end;
/
  1. 수정 후
set  serveroutput  on
accept   p_ename  prompt  '이름을 입력하세요!'
declare
            v_ename     emp.ename%type := upper('&p_ename');
            v_sal       emp.sal%type; 
begin
           select  (sal + nvl(comm,0)) * 12 into v_sal
           from emp 
           where ename = v_ename;

dbms_output.put_line( v_ename || '의 연봉은' || v_sal || '입니다!');
end;
/

에러가 났던 PLSQL (원래 내 의도)
1.

set  serveroutput  on
accept   p_ename  prompt  '이름을 입력하세요!'
declare
            v_ename     emp.ename%type := upper('&p_ename');
            v_sal       emp.sal%type; 
            v_comm      emp.comm%type; 
            v_total     number(10,2):= (v_sal + nvl(v_comm,0)) * 12; 
begin
 v_total  ;   
dbms_output.put_line( v_ename || '의 연봉은' || v_total || '입니다!');
end;
/

✅ DECLARE에서는 선언만 하는거라 사실상 연산쓴게 다 빈컵만 있는거라서 의미가 없다고 함.. BEGIN절에서 데이터를 불러오고, 그 데이터로 계산을 해야하는데 그걸 못하고 있는 것!
2. 이렇게도 쓸 수 있고

set serveroutput on
accept p_ename prompt '이름을 입력하세요!'

declare
  v_ename emp.ename%type := upper('&p_ename');
  v_sal emp.sal%type; 
  v_comm emp.comm%type; 
  v_total number(10,2);
begin
  select sal, comm
    into v_sal, v_comm
    from emp
   where ename = v_ename;

  v_total := (v_sal + nvl(v_comm, 0)) * 12;
  dbms_output.put_line(v_ename || '의 연봉은 ' || v_total || '입니다!');
end;
/
  1. 이렇게도 할 수 있다.
set serveroutput on

DECLARE
    v_ename emp.ename%TYPE := upper('&사원이름');
    v_sal emp.sal%TYPE;
    v_comm emp.comm%TYPE;
BEGIN
    SELECT sal, nvl(comm, 0) INTO v_sal, v_comm
    FROM emp
    WHERE ename = v_ename;

    dbms_output.put_line(v_ename||'의 연봉은 : ' || (v_sal+v_comm)*12);
END;
/
profile
열씨미하자

1개의 댓글

comment-user-thumbnail
2023년 7월 20일

소중한 정보 잘 봤습니다!

답글 달기