2020.10.07 SQL 강의노트

 반복문

1. FOR LOOP : 루프를 실행할 데이터의 갯수가 정해져 있을 때 

for(int i = 0 ; i < list.size(); i++ ) 

2. LOOP 

3. WHILE : 루프 실행 횟수를 모를때, 루프 실행 조건이 로직에 의해 바뀔 때 


FOR LOOP 


FOR 인덱스변수 (개발자가 이름부여) IN [REVERSE] 시작인덱스.. 종료인덱스 LOOP 

    반복실행할 문장;     

END LOOP ; 



1-5 까지 출력 



SET SERVEROUTPUT ON ; 


DECLARE 

BEGIN

    FOR i IN 1..5  LOOP 

        DBMS_OUTPUT.PUT_LINE(i); 

    END LOOP; 

END; 



2~5단까지 구구단 연산 

(포맷 신경쓰지 말고) 


DECLARE 

BEGIN 

    FOR i IN 2..5 LOOP 

    DBMS_OUTPUT.PUT_LINE(i)

      FOR j IN 1..9 LOOP 

      DBMS_OUTPUT.PUT_LINE(i*j);

     END LOOP; 

END;    

/



DECLARE 

BEGIN

    FOR i IN 2..5  LOOP 

        FOR j IN 1..9 LOOP 

            DBMS_OUTPUT.PUT_LINE( i ||'*'|| j|| '=' || i*j ); 

        END LOOP; 

    END LOOP;

END; 


WHILE

java 


while (조건식) { 

{


while 조건식 LOOP

    반복할 문장; 

END LOOP ; 



DECLARE

    i NUMBER := 1; 

BEGIN

    WHILE i < 5 LOOP

       DBMS_OUTPUT.PUT_LINE(i); 

       i := i + 1; 

    END LOOP;    

END; 



**커서  : 패치를 직접하는것 

변수가 필요가 없다 (V_SAL) 같은 . 한건,두건 패치하는것. 

변수가 엄청많은 컬럼의 데이터값이면 이것을 변수에 저장하려면 우선 --에 올려야하는데 그게 메모리가 부족할 수 있어서 패치를 쓰는것. 



참고사항 


NETWORK 에서 전달된다.


# (사용자가 읽는것)            @500 ( 전체데이터) 

                            &10 (사이즈)

   네트워크 작업은 한번 & 에서 # 로 갈때 임시저장하는곳& 크기가 작아서 ( 총 @개를 다 해야하면) 여러번 가야하면 네트워크 부하가 걸린다. 

   적당한 사이즈를 유지해야한다. 

   

   &이 작으면 : 응답이빠른것 대신 500을 다옮기는데 총 시간은 느려짐

   &이 크면 응답은 느리지만 500 전체시간은 빨라진다. 

   

    


--REVERSE 1 -> 10 을 10 -> 1로 돌 때



SQL CURSOR : SELECT 문에 의해 추출된 데이터를 가리키는 포인터 


SELECT 문 처리 순서 

1. 실행계획 생성 OR 기 생성된 계획 찾기

2. 바인드 변수 처리 

3. 실행

4. ******* 인출 



커서를 통해 개발자가 인출 하는 과정을 통제함으로써 테이블 타입변수에 SELECT 결과를 모두 담지 않고도 ( 메모리 낭비 없이 ) 

효율적으로 처리하는 것이 가능하다. 



커서의 종류

1. 묵시적 커서 - 커서 선언없이 실행한 SQL에 대해서 오라클 서버가 스스로 생성, 삭제하는커서 

2. 명시적 커서 - 개발자가 선언하여 사용하는 커서 


커서의 속성


커서명%ROWCOUNT : 커서에 담긴 행의 갯수 

커서명%FOUND : 커서에 읽을 행이 더 있는지 여부 

커서명%NOTFOUND : 커서에 읽을 행이 더 없는지여부

커서명%ISOPEN : 커서가 메모리에 선언되어 사용 가능한 상태 여부


커서 사용법

1. 커서 선언

    CURSOR 커서이름 IS 

        SELECT 쿼리 

2. 커서 열기

    OPEN 커서이름; 

    

3. 커서로부터 패치

    FETCH 커서이름 INTO 변수 ; 

    

4. 커서 닫기

    CLOSE 커서이름; 


DEPT 테이블의 부서번호deptno, 부서이름dname을 CURSOR 를 통해 데이터 출력 


DECLARE

/**/

    CURSOR c_dept IS 

        SELECT deptno, dname 

        FROM dept ; 

        v_deptno dept.deptno%TYPE; 

        v_dname dept.dname%TYPE; 

BEGIN 

/* 2. 커서열기 */ 

    OPEN c_dept;

/*3. 데이터 패치*/    

    lOOP 

        FETCH c_dept INTO v_deptno , v_dname; 

        EXIT WHEN c_dept%NOTFOUND; 

        DBMS_OUTPUT.PUT_LINE('v_deptno : ' || v_deptno || ' , v_dname : ' || v_dname);

        

    END lOOP; 

    CLOSE   c_dept; 

END;

/



명시적 커서 FOR LOOP : FOR LOOP 와 명시적 커서를 결합한 형태로 커서 OPEN , FETCH, CLOSE 단계를 FOR LOOP 에서 처리하여 

개발자가 사용하기 쉬운형태로 제공 

사용방법 ( JAVA 향상된 FOR 문과 비슷 ) 

FOR (String name : names ) 

사용방법 

FOR 레코드이름 IN 커서 LOOP 

    반복할 문장; 

END LOOP 




DECLARE

    CURSOR c_dept IS 

        SELECT deptno, dname 

        FROM dept ; 

        v_deptno dept.deptno%TYPE; 

        v_dname dept.dname%TYPE; 

BEGIN  

    FOR rec IN c_dept LOOP 

        DBMS_OUTPUT.PUT_LINE('rec.deptno : ' || rec.deptno || ' , rec.dname : ' ||  rec.dname); 

    END LOOP; 

END;

/



파라미터가 있는 커서 : 함수처럼 커서에 인자를 전달해서 실행시 조건을 추가할 수 있다. 


커서선언시 인자 명시 

CURSOR 커서이름 ( 파라미터명 파라미터타입 ) IS 

    SELECT * 

    FROM emp 

    WHERE deptno = 파라미터명; 

emp 테이블의 특정 부서에 속하는 사원들을 조회할 수 있는 커서를 커서 파라미터를 통해 생성 (사원이름, 사원번호 ) 




DECLARE

    CURSOR c_emp ( P_deptno emp.deptno%TYPE) IS 

        SELECT empno, ename

        FROM emp 

        WHERE deptno = p_deptno; 

BEGIN 


    FOR rec IN c_emp(10) LOOP 

        DBMS_OUTPUT.PUT_LINE('rec.empno : ' || rec.empno || ' , rec.ename : ' || rec.ename ) ; 

    END LOOP ; 


END;

/


쿼리가 짧을 경우 FOR LOOP 에 커서를 인라인 형태로 작성하여 사용가능

==> DECLARE 절에 커서를 선언하지 않음 

FOR 레코드명 in (SELECT 쿼리) LOOP 

END LOOP; 









DECLARE

BEGIN  

    FOR rec IN (SELECT deptno , dname FROM dept) LOOP

        DBMS_OUTPUT.PUT_LINE('rec.deptno : ' || rec.deptno || ' , rec.dname : ' ||  rec.dname); 

    END LOOP; 

END;

/




SELECT (SYSDATE + 5) - SYSDATE 

FROM dual; 




코드 


DECLARE

    v_date dt.dt%TYPE; 

    nexdate dt.dt%TYPE; 

    result NUMBER := 0 ; 

    minus dt.dt%TYPE; 

BEGIN    

       

            SELECT dt INTO v_date 

            FROM dt

            WHERE dt = TO_DATE('20201017' , 'YYYYMMDD' ) 

                    

            SELECT dt into nexdate

            FROM

            WHERE dt = TO_DATE('20201017' , 'YYYYMMDD' )

        

            minus :=  v_date - nextdate ;

            result := result + minus ;  

            

          i := i+1; 

          END LOOP ;


        DBMS_OUTPUT.PUT_LINE("result"); 

END;

/





DECLARE

    i NUMBER := 1; 

    v_date dt.dt%TYPE; 

    nexdate dt.dt%TYPE; 

    result NUMBER := 0 ; 

    minus dt.dt%TYPE; 


BEGIN    

      WHILE i <= 8 LOOP

            

            SELECT dt INTO v_date 

            FROM

            (SELECT ROWNUM RN, DT 

            FROM dt) A

            WHERE rn = i ;

            

            SELECT dt into nexdate

            FROM

            (SELECT ROWNUM RN, DT 

            FROM dt ) A

            WHERE rn = i+1;

        

            minus :=  v_date - nextdate ;

            result := result + minus ;  

            

          i := i+1; 

          END LOOP ;


        DBMS_OUTPUT.PUT_LINE("result"); 

END;

/







---답 



CREATE OR REPLACE PROCEDURE avgdt IS

    TYPE t_dt IS TABLE OF dt%ROWTYPE INDEX BY BINARY_INTEGER; 

    v_dt t_dt;   

    diff_sum NUMBER := 0 ;

BEGIN

    SELECT dt BULK COLLECT INTO v_dt  

    FROM dt

    ORDER BY dt DESC; 

    

    FOR i IN 1..v_dt.COUNT-1 LOOP 

        diff_sum := diff_sum + v_dt(i).dt - v_dt(i+1).dt;

       END LOOP ;

       DBMS_OUTPUT.PUT_LINE( diff_sum / (v_dt.COUNT-1)); 

END; 

/


EXEC avgdt; 



실습 pro3 을 dt 테이블로 sql에서 사용해보기 


 

 SELECT AVG(min)  

 FROM

( SELECT dt , lead (dt ) OVER (order by dt ) newdt , lead (dt ) OVER (order by dt ) - dt min

FROM dt)


//분석함수의 결과값이 일반 그룹함수의 인자로 사용할 수 없다. 


 SELECT AVG(min)  

 FROM

( SELECT dt - lead (dt ) OVER (order by dt desc )  min

FROM dt)



좀더 집합적인부분이다. 


SELECT  (MAX(dt) - MIN( dt))/ (COUNT(*) -1 )  

FROM dt; 










    

댓글