PL/SQL (Procedual Language SQL)
사용예)키보드로 부서번호를 입력 받아 해당 부서의 주소,인원수,평균급여를 출력하는 익명블록을 작성하시오
ACCEPT P_DEPT_NO PROMPT '부서코드 입력(10-110) : ' --P_DEPT_NO:변수(P:파라미터라는 뜻)
DECLARE
V_DEPT_NO HR.DEPT.DEPARTMENT_ID%TYPE := TO_NUMBER('&P_DEPT_NO');
--&:참조하는 방식(포인터 안의 내용을 참조하라는 기호
,실행할 때 &안에 있는 자료를 꺼내서 참조하라)
V_CNT NUMBER:=0;--V_DEPT_NO:(V:변수라는 뜻)
V_ASAL NUMBER:=0;
V_ADDR VARCHAR2(200);
BEGIN
SELECT A.STREET_ADDRESS||' '||A.CITY||' '||A.STATE_PROVINCE --주소를 얻기위한 SELECT문
INTO V_ADDR --주소를 할당
FROM HR.LOCATIONS A, HR.DEPT B
WHERE A.LOCATION_ID=B.LOCATION_ID
AND B.DEPARTMENT_ID=V_DEPT_NO;
SELECT COUNT(EMPLOYEE_ID), --사원의 수
ROUND(AVG(SALARY)) --그 부서의 평균급여
INTO V_CNT,V_ASAL --두 개의 변수에 각각 할당해줌
FROM HR.EMP
WHERE DEPARTMENT_ID=V_DEPT_NO;
DBMS_OUTPUT.PUT_LINE('부서번호 : '||V_DEPT_NO); --SYSTEM.OUT.PRINTLN과 같음
DBMS_OUTPUT.PUT_LINE('주소 : '||V_ADDR);
DBMS_OUTPUT.PUT_LINE('인원수 : '||V_CNT);
DBMS_OUTPUT.PUT_LINE('평균급여 : '||V_ASAL);
END;
TO_NUMBER('&P_DEPT_NO') - 문자열타입을 NUMBER타입으로
':=' : 자바의 대입연산자와 같음
V_DEPT_NO HR.DEPT.DEPARTMENT_ID%TYPE := TO_NUMBER('&P_DEPT_NO');
-> HR.DEPT.DEPARTMENT_ID과 같은 타입으로 변수를 선언하라는 뜻(참조타입)
지역변수는 사용하기 전에 반드시 초기화해야함.
V_CNT NUMBER:=0;
-> NUMBER타입은 반드시 초기화시켜야 함(초기화하지 않으면 NULL값이 들어감)
초기화시키지 않으면 SCRIPTRUNNER가 왔다갔다하기만 함. - 중지해서 NUMBER에 0 대입해줘야 함.
PL/SQL의 BEGIN블록 안에서 사용되는 SELECT문은 SELECT~INTO로 사용됨
SELECT에 두 컬럼이 사용되면 INTO에도 두 변수가 할당되어야 함.
선언문(DECLARE)에서는 SELECT~INTO문이 안 쓰임,
BEGIN블록 안에서만 SELECT~INTO절이 사용됨, 이외의 구간에는 SELECT FROM절 사용
SELECT 위치를 골라서
INTO 변수에 할당
DBMS_OUTPUT.PUT_LINE('부서번호 : '||V_DEPT_NO); --자바에서 PRINTLN과 같은 역할
스크립트 출력창에는 결과가 나오지 않음, DBMS출력창에 결과가 나옴
결과가 지워지지 않음, 지우개 툴을 눌러서 직접 지워줘야 함.
SCALR 변수 : 한 순간에 하나의 값만 들어올 수 있는 변수
같은 타입의 변수를 여러 개 동시에 저장할 수 있는 변수 : 배열
참조타입의 행참조타입은 자바의 ArrayList와 비슷하고 C언어의 구조체와 똑같음
구조체 : 다양한 타입의 데이터들을 한번에 저장할 수 있음 -> 데이터는 저장하지만 데이터를 조작하는 행위가 없음.
(자바의) class : 데이터를 저장하고 조작을 할 수있음
1)변수와 상수
사용예)임의의 부서코드를 발생시켜 해당 부서에 속한 사원 중 한 직원의 --난수발생
사원번호,사원명,입사일,직책코드,급여를 출력하는 익명블록을 작성하시오
DECLARE
V_EMP_ID HR.EMP.EMPLOYEE_ID%TYPE;
V_ENAME HR.EMP.EMP_NAME%TYPE;
V_JOB HR.EMP.JOB_ID%TYPE;
V_SAL HR.EMP.SALARY%TYPE;
V_DEPT_ID HR.DEPT.DEPARTMENT_ID%TYPE;
BEGIN
V_DEPT_ID:=TRUNC(DBMS_RANDOM.VALUE(10,110),-1);
--난수발생 VALUE(하한값,상한값) : 하한값~상한값 사이의 정수형 난수발생
SELECT EMPLOYEE_ID,EMP_NAME,JOB_ID,SALARY
INTO V_EMP_ID,V_ENAME,V_JOB,V_SAL
FROM HR.EMP
WHERE DEPARTMENT_ID = V_DEPT_ID
AND ROWNUM=1;
DBMS_OUTPUT.PUT_LINE('사원번호 : '||V_EMP_ID);
DBMS_OUTPUT.PUT_LINE('사원명 : '||V_ENAME);
DBMS_OUTPUT.PUT_LINE('직책 : '||V_JOB);
DBMS_OUTPUT.PUT_LINE('급여 : '||V_SAL);
END;
가장많은
DECLARE
V_EMP_ID HR.EMP.EMPLOYEE_ID%TYPE;
V_ENAME HR.EMP.EMP_NAME%TYPE;
V_JOB HR.EMP.JOB_ID%TYPE;
V_SAL HR.EMP.SALARY%TYPE;
V_DEPT_ID HR.DEPT.DEPARTMENT_ID%TYPE;
BEGIN
V_DEPT_ID:=TRUNC(DBMS_RANDOM.VALUE(10,110),-1);
SELECT A.EMPLOYEE_ID, A.EMP_NAME,A.JOB_ID,A.SALARY
INTO V_EMP_ID,V_ENAME,V_JOB,V_SAL
FROM (SELECT EMPLOYEE_ID,EMP_NAME,JOB_ID,SALARY
FROM HR.EMP
WHERE DEPARTMENT_ID = V_DEPT_ID
ORDER BY 4 DESC) A
WHERE ROWNUM=1;
DBMS_OUTPUT.PUT_LINE('사원번호 : '||V_EMP_ID);
DBMS_OUTPUT.PUT_LINE('사원명 : '||V_ENAME);
DBMS_OUTPUT.PUT_LINE('부서코드 : '||V_DEPT_ID);
DBMS_OUTPUT.PUT_LINE('직책 : '||V_JOB);
DBMS_OUTPUT.PUT_LINE('급여 : '||V_SAL);
END;
COMMIT;
사용예)2005년 7월 29일 'h001'회원이 'P202000012' 제품을 2개 구입했을 경우 이 정보를 CART테이블에 저장하시오.
--해야할 것 1.2005년7월29일에 매출이 발생되었나 확인
데이터 개수를 세서 COUNT를 써서 1일경우 -> 구매한 경우
0인경우 -> 구매하지 않은 경우
DECLARE
V_CNT NUMBER:=0; --V_CNT: 레코드 수(2005년7월29일 매출이 있는지 확인하는 변수)
V_CART_NO CART.CART_NO%TYPE;
BEGIN
SELECT COUNT(*) INTO V_CNT --2005년7월29일 매출 행이 존재하는지 확인
FROM CART
WHERE CART_NO LIKE '20050729%;';
IF V_CNT=0 THEN --매출이 없다(0이다)
V_CART_NO:='2005072900001'; --카트번호 부여
ELSE --매출이 있다. V_CNT값이 0이 아니다(이미 데이터가 존재한다)
SELECT CART_NO INTO V_CART_NO --1번이 부여됨
FROM CART
WHERE CART_MEMBER='h001' --이 회원이
AND SUBSTR(CART_NO,1,8)='20050729' --이 날
AND CART_PROD='P202000012';
--이 상품을 구매한 이력이 있는지 없는지 판별 -있으면 수를 추가, 없으면 INSERT
END IF; --여기까지 V_CART_NO가 NULL인 경우, NULL이 아닌 경우, V_CNT가 0인 경우
IF V_CART_NO IS NULL AND V_CNT !=0 THEN --안샀으면 NULL
INSERT INTO CART --V_CART_NO가 NULL인 경우 : 매출은 있지만 그 회원이 그 날 그 제품을 사지는 않음
SELECT 'h001',MAX(CART_NO)+1,'P202000012',2 --구매한적없음, 카트번호중 제일 큰 번호에 다음번호
FROM CART
WHERE CART_NO LIKE '20050729%';
ELSIF V_CART_NO IS NOT NULL AND V_CNT !=0 THEN --V_CART_NO가 NULL이 아닌 경우, 사간 경우
UPDATE CART
SET CART_QTY=CART_QTY+2 --그 회원이 이미 그 물건을 샀기 때문에 CART_QTY에 숫자만 2개 더해줌
WHERE CART_MEMBER='h001'
AND SUBSTR(CART_NO,1,8)='20050729'
AND CART_PROD='P202000012';
ELSIF V_CART_NO IS NOT NULL AND V_CNT =0 THEN --아무도 안 사간 경우 : 신규로 구매를 등록
INSERT INTO CART
VALUES('h001',V_CART_NO,'P202000012',2);
END IF;
END;