[2023/07/20 점심시간 문제]
사원번호를 입력하면 해당 사원의 입사일이 출력되게 PLSQL 프로그램밍을 하세요 !
사원 번호를 입력하세요 ~ 7788
입사일: 82/12/22
부울 변수
✅ 부울 변수 선언은 다음과 같다.
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;/
따로 출력되는거 없이 프로시저 성공 문구만 뜬다.
❓ 뭔소린지 하나도 모르겠는디

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

컬렉션 : 마치 테이블에 저장하듯이 세로로 저장할 수 있다. (번호도 indexing 하듯 붙는다)
스칼라 서브쿼리는 하나만 저장하는데, 컬렉션은 4개를 한번에 저장했다.
바인드 변수
❗비유적으로, 텀블러 - 호스트 변수 (카페 밖에서도 안에서도 자유롭게 쓸 수 있는)
실습
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)
- 데이터베이스 열 정의에 따라 변수를 선언하는 데 사용됩니다.
- 데이터베이스 테이블 또는 뷰의 열 모음에 따라 변수를 선언하는 데 사용됩니다.
-> 열 모음에 따라 : %rowtype (레코드 변수) 를 말하는 것이다. (나중에 6단원에서 배움)- 선언된 또 다른 변수의 정의에 따라 변수를 선언하는 데 사용됩니다.
- 데이터베이스 테이블 및 열 이름이나 선언된 변수의 이름이 접두어로 붙습니다.
-> v_ename emp.ename%type ㅇㅇ맞다.
컨트롤+F7 혹은 마우스 오른쪽 클릭->format 으로도 가능)tab 키 눌러서 앞에 공백 만드는게 나을듯!
프로시저문에서 사용할 수 없는 함수 -> 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 문장으로는 사용불가능
문제 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; /
(은행의 번호표 기계 생각하기)

예제.
1. my_seq 라는 이름으로 시퀀스를 생성create sequence my_seq start with 1 increment by 1 maxvalue 100;
- 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;
✅ 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 블럭을 중첩하는 이유
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


문제 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; /
- 수정 후
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; /
- 이렇게도 할 수 있다.
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; /
소중한 정보 잘 봤습니다!