2. SEQUENCE
  - 순차적으로 증가(감소)하는 값을 생성하는 오라클 객체
  - 테이블과 독립적으로 수행
  - 기본키로 선정할만한 컬럼이 존재하지 않는 경우, 자동적으로 증가하는 값이 필요한 경우 사용
  
(사용형식)
    CREATE SEQUENCE 시퀀스명
    [START WITH 시작값] -- 시작값/생략하면 MINVALUE값
    [INCREMENT BY 값]  -- 증(감)값
    [MAXVALUE 값|NOMAXVALUE] -- 최대값 설정, 기본은 NOMAXVALUE이며 10^27
    [MINVALUE 값|NOMINVALUE] -- 최소값 설정, 기본은 NOMINVALUE이며 1
    [CYCLE|NOCYCLE-- 최대[최소]값 까지 도달 후 다시 시퀀스를 생성할 지 여부. 기본은 NOCYCLE
    [CACHE n | NOCACHE] -- 시퀀스를 생성하여 캐쉬에 저장할지 여부, 기본은 CACHE 20
    [ORDER NOORDER] -- 위 조건대로 시퀀스 생성을 보장할지 여부, 기본은 NOORDER
    
-- 시퀀스를 만들어 두고 쓰는 것 : 캐쉬 
-- ORDER 정렬이 아니라 명령 이다.

 

  - 시퀀스 값을 참조하기 위한 의사컬럼(Pseudo Column)

-------------------------------------------------
  의사컬럼                          내용
-------------------------------------------------
 시퀀스명.NEXTVAL   '시퀀스'의 다음 값 반환
 시퀀스명.CURRVAL   '시퀀스'의 현재 값 반환
 *** 시퀀스가 생성된 후 처음 사용하는 명령은 반드시 NEXTVAL이어야 함
 -- 시퀀스 전의 값 참조할 수 없음. CURRVAL값을 가지고 NEXTVAL값으로 가야 함.

 

사용예) 

 CREATE SEQUENCE SEQ_TEST
  START WITH 10; -- SEQ_TEST 10부터 시작되는 시퀀스
     
    SELECT SEQ_TEST.CURRVAL FROM DUAL;
    -- CURRVAL is not yet defined in this session => NEXTVAL값을 써야함
    SELECT SEQ_TEST.NEXTVAL FROM DUAL; -- = 10이 있는 위치로 감
    SELECT SEQ_TEST.CURRVAL FROM DUAL; -- = 10
    SELECT SEQ_TEST.NEXTVAL FROM DUAL; -- = 11
    SELECT SEQ_TEST.CURRVAL FROM DUAL; -- = 11
    SELECT SEQ_TEST.NEXTVAL FROM DUAL; -- = 12
    -- 이후 10과, 11을 더이상 참조할 수 없음.

 

사용예) 분류테이블에 다음 자료를 삽입하시오

 자료
       -------------------------------------------------------------
        LPROD_ID     LPROD_GU     LPROD_NM 
       -------------------------------------------------------------
        시퀀스 사용        P501         농산물
        시퀀스 사용        P502         수산물
        시퀀스 사용        P503         농산가공식품

    CREATE SEQUENCE SEQ_LPROD_ID
     START WITH 10; -- 현재 LPROD 테이블 LPROD_ID SEQUENCE값 9

    INSERT INTO LPROD VALUES(SEQ_LPROD_ID.NEXTVAL,'P501','농산물');
    INSERT INTO LPROD VALUES(SEQ_LPROD_ID.NEXTVAL,'P502','수산물');
    INSERT INTO LPROD VALUES(SEQ_LPROD_ID.NEXTVAL,'P503','농산가공식품');
    SELECT * FROM LPROD;

 

**장바구니 번호 생성

-- 로그인되는 순간 계속 해당되는 장바구니 번호 부여함
-- 수행될때마다 실행되고 되돌아갈 수 없다. -- 시퀀스를 이용한 방법은 많이 사용하지는 않는다.

    CREATE SEQUENCE SEQ_CART_NO
     START WITH 1;

    SELECT TO_CHAR(SYSDATE,'YYYYMMDD')||TRIM(TO_CHAR(SEQ_CART_NO.NEXTVAL,'00000'))
      FROM DUAL;
      
-- 2022113000003

 

3. 동의어(SYNONYM)
  - 오라클 객체에 부여하는 별칭
  - 테이블 별칭은 해당 SQL문에서만 유효하지만 동의어는 테이블처럼 모든 곳에서 사용 가능
  - 다른 소유자의 객체 접근시 긴 수식어 대신 짧고 사용하기 쉬운 별칭 부여에 사용

(사용형식)
  CREATE [OR REPLACESYNONYM 동의어 FOR 객체명;

 

사용예) HR계정의 사원테이블과 부서테이블에 맞는 EMP 및 DEPT라는 동의어를 부여하시오

  CREATE OR REPLACE SYNONYM EMP FOR HR.EMPLOYEES;
  CREATE OR REPLACE SYNONYM DEPT FOR HR.DEPARTMENTS;
  -- 접근 수식어를 포함하고 있는거에 동의어를 부여  
    
  SELECT * FROM DEPT; 
  
  SELECT EMPLOYEE_ID,EMP_NAME,SALARY
    FROM EMP -- << 동의어 별칭 사용
   WHERE DEPARTMENT_ID=50;
   -- 50번 부서에 속한 사원의 사원번호,사원명,급여 조회

 

1. VIEW
  - 테이블과 유사한 객체(가상의 테이블)
  - SELECT문의 결과 집합
  - 테이블과는 독립적으로 사용됨
  - VIEW는
    . 필요한 정보가 여러 테이블에 분산되어 있는 경우
    . 특정자료의 접근을 제어하는 경우
    
(사용형식)
  CREATE [OR REPLACE] VIEW 뷰이름[(컬럼list)] -- 뷰 : 가상의 테이블
  AS
    SELECT 문;
    [WITH READ ONLY]
    [WITH CHECK OPTION]
    .'(컬럼list)' : 뷰에서 사용할 컬럼명. 생략하면 SELECT 문의 컬럼별칭이 뷰의 컬럼명이 되고,
      SELECT 문의 컬럼 별칭이 없는 경우 SELECT문의 컬럼명이 뷰의 컬럼명이 됨
    .'OR REPLACE' : '뷰이름'이 이미 존재하면 대치시키고 없으면 신규로 생성
    .'WITH READ ONLY' : 읽기전용 뷰 생성. 뷰를 대상으로 DML 명령을 수행시킬 수 없음.
     다만, 원본 테이블은 제한없이 DML 명령 사용할 수 있으며, 원본테이블에서 변경사항은 즉시 뷰에 반영
    .'WITH CHECK OPTION' : 원본 SELECT 문의 WHERE 조건을 위배하는 값으로 뷰의 내용을 변경하는
      DML명령을 사용할 수 없다. 다만, 원본 테이블은 제한없이 DML 명령 사용할 수 있으며,
      원본테이블에서 변경사항은 즉시 뷰에 반영.


-- CREATE : 오라클 객체를 만들때 사용하는 명령어 <=> 반대는 DROP
-- OR REPLACE : 항상 쓰지못하는 경우가 있다.
-- 기본키나 제약사항은 뷰에는 없음. (2차원 배열구조)
-- FROM절에 나올수 있음.
-- 뷰의 내용을 UPDATE로 하면 원본의 내용이 변경된다.


-- WITH READ ONLY의 읽기 전용 대상은 오로지 뷰이다. 원본테이블 변경 X 
-- WITH CHECK OPTION의 WHERE절을 위배하는 UPDATE 실행문 사용 불가.
-- WITH READ ONLY(변경금지)와 WITH CHECK OPTION(조건변경)는 같이 쓸 수 없다.

 

사용예) 회원테이블에서 마일리지가 5000이상인 회원의 회원번호,회원명,마일리지로 뷰를 생성하시오

 CREATE OR REPLACE VIEW MEM_MILE_VI(MID,MNAME,MILEAGE)
    AS 
      SELECT MEM_ID,MEM_NAME,MEM_MILEAGE
        FROM MEMBER
       WHERE MEM_MILEAGE>=5000;

 

 

**(원본테이블 내용이 변경)
  회원테이블에서 'e001' 회원의 마일리지를 9299 -> 4000으로 변경하시오 

 UPDATE MEMBER
    SET MEM_MILEAGE=4000
  WHERE MEM_ID='e001';

 

 

**(뷰의 내용이 변경)
   뷰(MEM_MILE_VI)에서 'x001' 회원의 마일리지를 9791 -> 2000으로 변경하시오

  UPDATE MEM_MILE_VI
     SET MILEAGE=2000
   WHERE MID='x001';
   
    SELECT * FROM MEM_MILE_VI; 
    SELECT MEM_ID,MEM_MILEAGE
      FROM MEMBER;

 


-- 뷰에 삽입이 되려면 NOT NULL 항목에 자료가 있어야함..
-- 삭제하려면 참조하는 테이블이없어야 한다.
-- 업데이트는 되지만 삽입 삭제는 테이블과의 관계를 살펴봐야 한다.

 

**테이블 복사
    CREATE TABLE 테이블명
    AS 
      SELECT 문;

 

-- SELECT 문의 결과가 테이블로 만들어진다.

 CREATE TABLE CUSTOMERS
    AS 
      SELECT * FROM MEMBER;


   
-- CUSTOMERS 테이블이 생성되고 널이 아님을 널로 바꿈(기본키는 MEM_ID)
      

 

사용예) MEM_MILE_V1 뷰에 회원번호'a002','홍길동',마일리지 3000 자료를 입력하시오


    INSERT INTO MEM_MILE_V1
           VALUES('a002','홍길동',3000);


-- CUSTOMERS 테이블에 홍길동의 자료 들어가고 뷰에는 없음(뷰는 마일리지 5000이상)

 

** V2 생성

  CREATE OR REPLACE VIEW MEM_MILE_V2
      AS 
        SELECT MEM_ID,
               MEM_NAME,
               MEM_MILEAGE
          FROM CUSTOMERS
         WHERE MEM_MILEAGE>=5000
    WITH READ ONLY; -- 읽기전용

**MEM_MILE_V2에서 'p001' 자료를 삭제

    DELETE FROM MEM_MILE_V2
     WHERE MEM_ID='p001';

-- 오류 : cannot perform a DML operation on a read-only view : 읽기전용이여서 삭제불가

 

**CUSTOMERS 'p001' 자료를 삭제 (원본테이블에서 삭제 가능)

  DELETE FROM CUSTOMERS
   WHERE MEM_ID='p001'; -- 삭제되었습니다.

 

 

** V3 생성

  CREATE OR REPLACE VIEW MEM_MILE_V3
      AS 
        SELECT MEM_ID AS 회원번호,
               MEM_NAME AS 회원이름,
               MEM_MILEAGE AS 마일리지
          FROM CUSTOMERS
         WHERE MEM_MILEAGE>=5000
    WITH CHECK OPTION; --<< 조건 위배시 명령 실행불가

 

** 뷰 MEM_MILE_V3에서 '이쁜이' 회원의 마일리지를 4000으로 변경하시오

 UPDATE MEM_MILE_V3
    SET 마일리지=4000 -- 컬럼명이 한글이라 한글로
  WHERE 회원이름='이쁜이';

-- 오류 : 마일리지 5000 이하여서 view WITH CHECK OPTION where-clause violation 위배됨 : 명령 실행불가

 

** 뷰 MEM_MILE_V3에서 '이쁜이' 회원의 마일리지를 10000으로 변경하시오

 UPDATE MEM_MILE_V3
    SET 마일리지=10000 
  WHERE 회원이름='이쁜이';

-- 원본테이블 CUSTOMERS 에도 바뀐다. 

    WITH CHECK OPTION을 만족하는 조건이기 때문에

- 하나의 테이블에 2개 이상의 별칭을 부여하여 다른 테이블로 간주한 후 수행하는 조인

 

사용예) 회원테이블에서 '이혜나' 회원의 마일리지보다 많은 마일리지를 보유한 회원들을 조회하시오.
       Alias는 회원번호,회원명,마일리지
       -- 같은 멤버테이블에서 '이혜나'의 테이블과 다른 모든 회원테이블과 조인한다.
       -- 모든회원테이블은 이혜나의 값보다 많은 값을 가진다. 
       -- '=' 연산자 이외의 연산자 사용 //비동등조인 사용

 

 SELECT B.MEM_ID AS 회원번호,
                B.MEM_NAME AS  회원명,
                B.MEM_MILEAGE AS 마일리지
   FROM  MEMBER A, MEMBER B
WHERE  A.MEM_NAME='이혜나'
      AND B.MEM_MILEAGE > A.MEM_MILEAGE;  

-- 조인조건 : 모든 회원의 마일리지 > 이혜나의 마일리지(6500) => 결과 진현경 : 8700

EX) 오철희 회원(3700)  보다 많은 마일리지를 가진회원 : 이혜나, 구길동, 이진영, 진현경

 

 

22-11-28 ) 서브쿼리

 - SQL구문안에 포함된 또 다른 SQL 구문
  - 서브쿼리는 알려지지 않은 조건에 근거한 검색을 수행하는 경우 사용
  - 서브쿼리는 메인쿼리의 해당 절이 실행되기 전에 한번 실행 됨
  - 서브쿼리는 '( )' 안에 기술하며, 연산자와 함께 사용하는 경우 연산자 우측에 위치해야 함
  -- 예외 : insert/ create table문에 나오는 서브쿼리는 ()생략
  -- 연산자의 오른쪽에 와야한다.
  - 분류
    . 연관성 있는 서브쿼리/연관성 없는 서브쿼리
-- 연관성 있는 서브쿼리 : 메인쿼리와 서브쿼리에 사용된 테이블이 조인으로 연결된 경우 (대부분의 경우)


    . 일반서브쿼리(SELECT절)/인라인서브쿼리(FROM절)/중첩서브쿼리(WHERE절)
    -- 인라인 : 제일 먼저 실행되어야 할 절/서브쿼리가 먼저 실행되어야함. /자기가 스스로 실행되어야함.
    --         from절에 나오기 전에 결과가 나와야함 => 뷰
    -- select 의 결과가 뷰(익명뷰) / 뷰가 없어지기전에 이름을 부여하면 저장됨..
    -- WHERE절에 사용되는 서브쿼리 = 중첩서브쿼리. 연산자를 사용하면 서브쿼리를 연산자 오른쪽에 쓴다.

    . 단일행/다중행, 단일열/다중열
-- 행 : 다중행이냐 단일행이냐 중요함. 
    -- from 절에 사용된 서브쿼리 먼저 실행 => 그 다음 where절 실행 => select 절 실행 

 

1. 연관성 없는 서브쿼리(Noncorrelated Subquery)
  - 메인쿼리와 서브쿼리에 사용된 테이블이 조인으로 연결되지 않은 경우

 

 

사용예) 사원테이블에서 사원들의 평균 급여보다 많은 급여를 받은 사원들을 조회하시오.
       Alias는 사원번호,사원명,급여,평균급여

더보기

메인쿼리 : 사원테이블에서 사원번호,사원명,급여,평균급여
    SELECT EMPLOYEE_ID AS 사원번호,
           EMP_NAME AS 사원명,
           SALARY AS 급여,
           (SELECT ROUND(AVG(SALARY))
              FROM HR.EMPLOYEES) AS 평균급여
      FROM HR.EMPLOYEES
     WHERE SALARY>(평균급여:서브쿼리)

서브쿼리 : 평균급여
    SELECT AVG(SALARY)
      FROM HR.EMPLOYEES

결합
    SELECT EMPLOYEE_ID AS 사원번호,
           EMP_NAME AS 사원명,
           SALARY AS 급여,
           (SELECT ROUND(AVG(SALARY)) 
              FROM HR.EMPLOYEES) AS 평균급여
   -- WHERE절의 계산결과는 안남음.. 둘다 써먹으려면 FROM절에서..
      FROM HR.EMPLOYEES
     WHERE SALARY>(SELECT AVG(SALARY) --WHERE절의 서브쿼리는 연산자 우측에 기술
                     FROM HR.EMPLOYEES) -- WHERE절의 계산이 끝나면 없어짐
/*    
(SELECT ROUND(AVG(SALARY)) 
              FROM HR.EMPLOYEES) = > 158번 실행되어진다.
 => FROM절에 기술해서 1번만 실행될수 있다. */
 
    SELECT A.EMPLOYEE_ID AS 사원번호,
           A.EMP_NAME AS 사원명,
           A.SALARY AS 급여,            
           ROUND(B.ESAL) AS 평균급여  
      FROM HR.EMPLOYEES A, (SELECT AVG(SALARY) AS ESAL
                            FROM HR.EMPLOYEES)B  -- 1행1열의 결과만 나옴  
--         HR.EMPLOYEES A와 B를 비교
     WHERE A.SALARY>B.ESAL;  -- 비동등 조인
       


 -- 총무부에 상위부서는 없음
사용예) SAMPLE계정에서 부모부서코드가 NULL이 아닌 부서에 속한 사원정보를 조회하시오
       Alias는 사원번호,사원명,부서코드,직책코드

 

더보기

메인쿼리 :  
    SELECT EMPLOYEE_ID AS 사원번호,
           EMP_NAME AS 사원명,
           DEPARTMENT_ID AS 부서코드,
           JOB_ID AS 직책코드 
      FROM LHY93_SAMPLE.EMPLOYEES
     WHERE DEPARTMENT_ID=(서브쿼리 : 부모부서코드가 NULL이 아닌 부서)

서브쿼리 : 부모부서코드가 NULL이 아닌 부서
    SELECT DEPARTMENT_ID
      FROM LHY93_SAMPLE.DEPARTMENTS
     WHERE PARENT_ID IS NOT NULL
       
결합 : 
    SELECT DISTINCT EMPLOYEE_ID AS 사원번호,
           EMP_NAME AS 사원명,
           DEPARTMENT_ID AS 부서코드,
           JOB_ID AS 직책코드 
      FROM LHY93_SAMPLE.EMPLOYEES
     WHERE DEPARTMENT_ID IN(SELECT DEPARTMENT_ID
                             FROM LHY93_SAMPLE.DEPARTMENTS
                            WHERE PARENT_ID IS NOT NULL);

 

** EXISTS 연산자 사용
    - 연산자의 대상의 결과가 하나의 행이라도 존재하면 참(TRUE)을 반환
    - 단일행 연산자
    - EXISTS 우측의 서브쿼리 결과가 값은 연산과 무관(보통 SELECT절에 '1'을 사용)

더보기

  SELECT DISTINCT A.EMPLOYEE_ID AS 사원번호,
           A.EMP_NAME AS 사원명,
           A.DEPARTMENT_ID AS 부서코드,
           A.JOB_ID AS 직책코드 
      FROM LHY93_SAMPLE.EMPLOYEES A
     WHERE EXISTS (SELECT 1  -- '1' = 의미 없는 1. / EXISTS의 결과가 하나라도 있음 TRUE
                                     FROM LHY93_SAMPLE.DEPARTMENTS B
                                  WHERE B.PARENT_ID IS NOT NULL
                                        AND A.DEPARTMENT_ID=B.DEPARTMENT_ID); -- 조인

-- EXISTS를 사용하면 연관성 없는 서브쿼리가 연관성 있는 서브쿼리로 바뀜 

 

사용예) HR계정의 직무변동테이블(JOB_HISTORY)의 부서의 부서코드,부서명,책임사원명을 조회하시오

 

더보기

메인쿼리 : 부서코드,부서명,책임사원명
    SELECT A.DEPARTMENT_ID AS 부서코드,
           A.DEPARTMENT_NAME AS 부서명,
           B.EMP_NAME AS 책임사원명
      FROM HR.DEPARTMENTS A, HR.EMPLOYEES B
     WHERE A.MANAGER_ID=B.EMPLOYEE_ID  
     -- 사원이름 꺼내기 위해 책임사원 ID = 사원테이블의 사원ID
       AND A.DEPARTMENT_ID=(서브쿼리 : 직무변동테이블 JOB_HISTORY의 부서코드)
       
서브쿼리 : 직무변동테이블 JOB_HISTORY의 부서코드
    SELECT DEPARTMENT_ID
     FROM HR.JOB_HISTORY
     
결합 :
     SELECT A.DEPARTMENT_ID AS 부서코드,
           A.DEPARTMENT_NAME AS 부서명,
           B.EMP_NAME AS 책임사원명
      FROM HR.DEPARTMENTS A, HR.EMPLOYEES B
     WHERE A.MANAGER_ID=B.EMPLOYEE_ID  
       AND A.DEPARTMENT_ID IN(SELECT DEPARTMENT_ID 
                                FROM HR.JOB_HISTORY)
     ORDER BY 1;   
    -- IN 연산자는 중복 제거를 한다. (DISTINCT와 같음)
    -- 연관성 없는 서브쿼리

 

 

더보기

    SELECT A.DEPARTMENT_ID AS 부서코드,
           A.DEPARTMENT_NAME AS 부서명,
           B.EMP_NAME AS 책임사원명
      FROM HR.DEPARTMENTS A, HR.EMPLOYEES B
     WHERE A.MANAGER_ID=B.EMPLOYEE_ID  -- 조건을 만족하는 값 11개(NULL값 버림)
       AND EXISTS (SELECT 1  
                                  FROM HR.JOB_HISTORY C
                               WHERE C.DEPARTMENT_ID=A.DEPARTMENT_ID)
     -- EXISTS를 사용하면 WHERE절이 반드시온다
     ORDER BY 1;  

 

(일반쿼리 사용) -- SELECT절에 서브쿼리를 사용한 경우

더보기

    SELECT DISTINCT A.DEPARTMENT_ID AS 부서코드,
          (SELECT DEPARTMENT_NAME
             FROM HR.DEPARTMENTS B 
    -- 서브쿼리를 벗어나면 값을 잃어버리기 때문에 다른 서브쿼리에 테이블 별칭 같이써도 됨
            WHERE A.DEPARTMENT_ID=B.DEPARTMENT_ID) AS 부서명,
          (SELECT C.EMP_NAME
             FROM HR.DEPARTMENTS B, HR.EMPLOYEES C
            WHERE A.DEPARTMENT_ID=B.DEPARTMENT_ID
              AND B.MANAGER_ID=C.EMPLOYEE_ID) AS 책임사원명
      FROM HR.JOB_HISTORY A
      ORDER BY 1;

 

사용예) 사원테이블에서 본인이 속한 부서의 평균급여보다 많은 급여를 받는 사원정보를 조회하시오.
       Alias는 사원번호,사원명,부서번호,부서명,부서평균급여,급여

 

더보기

 SELECT A.EMPLOYEE_ID AS 사원번호,
           A.EMP_NAME AS 사원명,
           A.DEPARTMENT_ID AS 부서번호,
           B.DEPARTMENT_NAME AS 부서명,
           (SELECT ROUND(AVG(C.SALARY))
             FROM HR.EMPLOYEES C
            WHERE C.DEPARTMENT_ID=A.DEPARTMENT_ID
         GROUP BY C.DEPARTMENT_ID) AS 부서평균급여,
           A.SALARY AS 급여
      FROM HR.EMPLOYEES A, HR.DEPARTMENTS B
     WHERE A.SALARY>(SELECT C.CASL 
                                        FROM (SELECT DEPARTMENT_ID, 
                                                                    AVG(SALARY) AS CASL      
                                                        FROM HR.EMPLOYEES                   
                                                GROUP BY DEPARTMENT_ID)C
                                      WHERE A.DEPARTMENT_ID=C.DEPARTMENT_ID)
       AND A.DEPARTMENT_ID=B.DEPARTMENT_ID
    ORDER BY 3, 6 DESC;

 

 


  - NVL, NVL2, NULLIF 등이 제공됨
 
 1. IS NULLIS NOT NULL
   . NULL값은 '='연산자로 동등성 평가가 불가능함
   . NULL의 평가를 위한 연산자로 IS, IS NOT 연산자가 제공됨

  

사용예) 상품테이블에서 상품의 색상(PROD_COLOR)이 

              NULL인 제품의 제품코드,제품명,매입단가를 조회하시오

SELECT  PROD_ID AS 제품코드,
        PROD_NAME AS 제품명,
        PROD_COST AS 매입단가
  FROM  PROD
 WHERE PROD_COLOR IS NULL;

 

 

 

 

 

 2. NVL(expr, val)
   . 'expr' 값이 NULL이면 'val'를 반환하고 NULL이 아니면  'expr'값을 반환
   . 'expr'과 'val'은 같은 데이터 타입 이어야 함

 

사용예) 2020년 7월 모든(=OUTTER JOIN 외부조인) 회원별 구매현황을 조회하시오 
        -- '모든' 이라는 수식어가 붙으면 OUTTER JOIN 외부조인이다.
       Alias는 회원번호,회원명,구매수량합계

 SELECT B.MEM_ID AS 회원번호,
        B.MEM_NAME AS 회원명,
        SUM(A.CART_QTY) AS 구매수량합계
   FROM CART A
  RIGHT OUTER JOIN MEMBER B ON(A.CART_MEMBER=B.MEM_ID
    AND A.CART_NO LIKE '202007%')
  GROUP BY B.MEM_ID,B.MEM_NAME
  ORDER BY  1;

 

※ NVL로 null 값을 0으로

  SELECT B.MEM_ID AS 회원번호,
         B.MEM_NAME AS 회원명,
         NVL(SUM(A.CART_QTY),0) AS 구매수량합계
    FROM CART A
   RIGHT OUTER JOIN MEMBER B ON(A.CART_MEMBER=B.MEM_ID
     AND A.CART_NO LIKE '202007%')
   GROUP BY B.MEM_ID,B.MEM_NAME
   ORDER BY  1;

 

 


사용예) 2020년 7월 모든(=OUTTER JOIN 외부조인) 회원별 구매현황을 조회하시오 
       Alias는 회원번호,회원명,구매수량합계 이며 구매수량이 없으면 '구매정보없음'을 출력

 

       

※ 하지만 '구매수량합계'의 값은 문자열이다.(TO_CHAR)

SELECT B.MEM_ID AS 회원번호,
       B.MEM_NAME AS 회원명,
       NVL(SUM(A.CART_QTY),'구매정보없음') AS 구매수량합계
   --  오류 :'expr'과 'val'은 같은 데이터 타입 이어야 함
  FROM CART A
 RIGHT OUTER JOIN MEMBER B ON(A.CART_MEMBER=B.MEM_ID
   AND A.CART_NO LIKE '202007%')
 GROUP BY B.MEM_ID,B.MEM_NAME
 ORDER BY  1;
-------------------------------------------------------------    
SELECT B.MEM_ID AS 회원번호,
       B.MEM_NAME AS 회원명,
       NVL(TO_CHAR(SUM(A.CART_QTY),'9,999,999'),
       '구매정보없음') AS 구매수량합계
   --  오류 :'expr'과 'val'은 같은 데이터 타입 이어야 함
   -- 'expr' 을 문자열로 바꿔줘야함
  FROM CART A
  RIGHT OUTER JOIN MEMBER B ON(A.CART_MEMBER=B.MEM_ID
    AND A.CART_NO LIKE '202007%')
  GROUP BY B.MEM_ID,B.MEM_NAME
  ORDER BY  1;

 

 

 

 

3. NVL2(expr, v1,v2)
   . 'expr' 값이 NULL이면 v2를 반환하고, NULL이 아니면 v1을 반환
   . NVL을 확장한 개념(NVL을 NVL2로 변환가능)
   . v1과 v2는 같은 데이터 타입이어야 함
   
사용예) 상품테이블에서 제품의 제품코드,제품명,매입단가,색상을 조회하시오
       색상이 NULL이면 '색상정보 없음'을 출력하시오. NVL2와 NVL을 적용

(NVL 사용)
SELECT PROD_ID AS 제품코드,
       PROD_NAME AS 제품명,
       PROD_COST AS 매입단가,
       NVL(PROD_COLOR,'색상정보 없음')  AS 색상
  FROM PROD;
      
(NVL2 사용)
SELECT PROD_ID AS 제품코드,
       PROD_NAME AS 제품명,
       PROD_COST AS 매입단가,
       NVL2(PROD_COLOR,PROD_COLOR,
       '색상정보 없음')  AS 색상
  FROM PROD;

 

 

사용예) 사원테이블에서 사원들의 보너스를 계산하시오.
            보너스는 영업실적이 있으면 기본급여(SALARY)*영업실적이고, 영업실적이 없으면
            기본급여(SALARY)*10%이다.
            영업실적이 없으면 영업실적에 '실적없음'을 출력할 것.
            Alias는 사원번호,사원명,영업실적,기본급,보너스
      

SELECT EMPLOYEE_ID AS 사원번호,
       EMP_NAME AS 사원명,
       NVL(TO_CHAR(COMMISSION_PCT,'0.99'),'실적없음') AS 영업실적,
       SALARY AS 기본급,
       NVL2(COMMISSION_PCT,SALARY*COMMISSION_PCT,SALARY*0.1) AS 보너스          
  FROM HR.EMPLOYEES

 

 

 

 


 4. NULLIF(col1, col2)
   . col1과 col2를 비교하여 서로 같은 값이면 NULL을 반환하고 다른값이면 'col1'을 반환함

 

 

 

 

** 상품테이블에서 분류코드 'P301' 자료의 매출가격을 

    매입가격으로 조정하시오

 UPDATE PROD
    SET PROD_PRICE=PROD_COST
  WHERE PROD_LGU= 'P301';
-- 4개 행 이(가) 업데이트되었습니다.
  : P301이 포함한 제품이 4가지

 

 

사용예) 상품테이블에서 상품들의 매입가와 매출가를 조회하여 같은 값이면 비고란에 '단종예정상품'을,
        서로 다른 가격이면 판매이익을 조회하시오.
        Alias는 상품코드, 상품명,매입가격, 매출가격, 비고

 

 SELECT PROD_ID AS 상품코드, 
        PROD_NAME AS 상품명,
        PROD_COST AS 매입가격, 
        PROD_PRICE AS 매출가격, 
    -- 같은 값이면 '단종예정상품' /다른 값이면 판매이익
        NVL2(NULLIF(PROD_COST,PROD_PRICE),
        TO_CHAR(PROD_PRICE-PROD_COST,'9,999,999'), '단종예정상품') AS 비고           
   FROM PROD;

변환함수
  - 자료의 형을 일시적으로 변환하기 위한 함수
  - TO_CHAR(숫자나 날짜를 문자로), 

    TO_NUMBER(문자나 날짜를 숫자로), 

    TO_DATE(문자를 날짜 데이터로 변환),

    CAST(바꾸고싶은대로 바꿈) 제공


 1. CAST(expr  AS 타입명) -- 기본형으로밖에 밖을수 없음
    . 'expr'형을 '타입명'으로 변환
    . 물리적으로 변환되지는 않음
    
    -- 변환하고자 하는 새로운 데이터 타입으로 출력
    
    

사용예) 2020년 6월 일자별 판매집계를 조회하시오.

SELECT CAST(SUBSTR(A.CART_NO,1,8) AS DATE) AS 일자,
 -- 날짜형식으로 바꿈(형변환)
       SUM(A.CART_QTY) AS 판매수량,
       SUM(A.CART_QTY*B.PROD_PRICE) AS 판매금액
  FROM CART A, PROD B
 WHERE A.CART_PROD=B.PROD_ID
 GROUP BY CAST(SUBSTR(A.CART_NO,1,8) AS DATE)
 ORDER BY 1;

 


 2. TO_CHAR(expr [, fmt])
   - 문자열(CHAR, CLOB -> VARCHAR2), 숫자, 날짜 타입의 데이터를 'fmt' 형식에 맞는 
     문자열 자료로 형변환 -- 특정한 경우 문자열을 문자열로 바꿀수 있다. 

     (예 -고정길이 문자열 -> 가변길이 문자열)
   - format 문자열은 날짜와 숫자로 구분

 

 

 

 

** 날짜 format string

더보기

-----------------------------------------------------------------------------------
    format                          기능                          예
-----------------------------------------------------------------------------------
    CC                               세기                    SELECT TO_CHAR(SYSDATE, 'CC') FROM DUAL;
    AD, BC                         서기                    SELECT TO_CHAR(SYSDATE, 'AD YYYY') FROM DUAL; 
    YYYY,YYY,YY,Y           년도                    SELECT TO_CHAR(SYSDATE, 'YYYY'),
                                                                                   TO_CHAR(SYSDATE, 'YYY'),
                                                                                   TO_CHAR(SYSDATE, 'YY'),
                                                                                   TO_CHAR(SYSDATE, 'Y') FROM  DUAL;


    Q                                 분기                   SELECT TO_CHAR(SYSDATE, 'YYYY/MM Q') FROM DUAL;

                                                                  -- 2022/11/4분기
    MM, RM                       월                      SELECT TO_CHAR(SYSDATE, 'MM'),
                                                                                 TO_CHAR(SYSDATE, 'RM'),
                                                                                 TO_CHAR(SYSDATE, 'MONTH'),
                                                                                 TO_CHAR(SYSDATE, 'MON') FROM DUAL;  
    MONTH, MON         '월'문자열 

                                     추가 출력     
    WW,                         년의 주수, 

      W                           월의 주수              SELECT TO_CHAR(SYSDATE, 'WW'),
                                                                 TO_CHAR(SYSDATE, 'W')  FROM DUAL;  
    DDD,DD,D           년의 일,월의 일,

                                 주의 일                    SELECT TO_CHAR(SYSDATE, 'DDD'),   
                                                                                TO_CHAR(SYSDATE, 'DD'),   
                                                                                TO_CHAR(SYSDATE, 'D'),  
                                                                                TO_CHAR(SYSDATE, 'DAY'),
                                                                                TO_CHAR(SYSDATE, 'DY') FROM DUAL;    
                                                     
    DAY,DY             요일  -- 수요일 / 수(약자)
    AM, PM, A.M        오전, 오후              SELECT TO_CHAR(SYSDATE, 'AM'),
                                                                              TO_CHAR(SYSDATE, 'P.M.')  FROM DUAL; 
                                                     
    P.M.               --  SYSDATE를 받으면 아무리 P.M.을 선언해도 오전이면 오전이라고 표기된다.
    HH,HH12,HH24       시간
    MI                             분
    SS,SSSSS               초                     SELECT TO_CHAR(SYSDATE, 'HH:MI:SS'),
                                                                            TO_CHAR(SYSDATE, 'HH12:MI:SSSSS'),  
                                                                            TO_CHAR(SYSDATE, 'HH24:MI:SS')  
                                                                            FROM DUAL;




    "사용자정의 문자열"         

    SELECT TO_CHAR(SYSDATE, 'YYYY"년" MM"월" DD"일"') FROM DUAL;                                                                 
    >> 2022년 11월 23일


-- **    
--  AD, BC 원본데이터가 이미 저장되어있어서 둘다 '서기'로 표시됨
--  RM 로마자로 월 표기
--  MONTH(월의 풀네임), MON(월의 약자 - JUN,DEC) /한글은 월을 표현하는 약자가 없어서 같은 형식으로 출력됨
--  1년 52주/WW 오늘이1년의 몇 주 차인지/ W 이번달에 오늘은 몇주차인지
--  (11월 23일 WW : 오늘은 1년의 47주차/W : 11월의 4주차)
--   DDD : 날짜가 3자리로 표현한다. => 1월 1일부터 오늘까지 경과된 일 
--   DD : 2자리로 표현 이번달 1일부터 오늘까지 경과된 일,
--   D  : 이번주의 월요일부터 오늘까지 경과된 일  
--  HH = HH12 : 12시간 형식,HH24 : 24시간 형식
--  SS : 1분은 60초 / SSSSS : 5자리로 표기함 : 오늘 0시0초부터 시작해서 지금까지 경과된 초를 출력

 

 

 


** 숫자 format string

사용예) -- 결과는 숫자가 아닌 문자열!!
SELECT TO_CHAR(12345,'999,999'),     --  12,345     /나인모드
       TO_CHAR(12345,'000,000'),     --  012,345
       TO_CHAR(12345,'999,999.99'),  --  12,345.00  /나인모드여도 소숫점0출력
       TO_CHAR(12345,'999,999.00'),  --  12,345.00
       TO_CHAR(-12345,'999,999MI'),  --  12,345-    / 음수부호가 오른쪽에 표기
       TO_CHAR(-12345,'999,999PR'),  --  <12,345>   / 음수인경우 < 숫자 > 표기 / 양수인경우 일반숫자 표기
       TO_CHAR(12345,'L999,999'),    --  ₩12,345   / Location의 'L'
       TO_CHAR(12345,'$000,999')     --  $012,345   / 달러표기와 제로모드
 FROM DUAL

 

더보기

-----------------------------------------------------------------------------------
    format                                        기능                              
-----------------------------------------------------------------------------------
    9                                        유효숫자출력, 무효의                       
                                              0은 공백 처리
    0                                        유효숫자출력, 무효의 
                                              0은 '0' 출력
    $,L                                     화폐기호 출력 -- 맨왼쪽에 출력
    MI                                     음수인 경우 우측에 '-'출력--( 1234-)
    PR                                    음수인 경우 우측에 < >안에 출력
    ,(Comma)                         3자리마다 자리점 출력
    .(DOT)                              소숫점 출력

 

 


/* 나인모드         제로모드            
** 01234.30        01234.30
   99,999.99       00,000.00
-------------------------------- 유효숫자 출력
   1,234           01,234.30
   0공백처리         0 출력
(소숫점은 0출력)

 화폐 기호 : $ 1,234   / L 1,234 L: 다른나라 화폐기호 */
 


  

   SELECT TO_CHAR('345') + 9999  -- 실행됨 : 10344
     FROM DUAL; 
      
   SELECT TO_CHAR('1,344') + 9999  -- 실행불가 : 1,344 => 콤마 때문에 
     FROM DUAL;

 

 

사용예) 

    SELECT TO_DATE('20211230'), -- 숫자가 날짜로 바뀜
           TO_DATE(20211230),   -- 숫자가 날짜로 바뀜
           TO_DATE('20211230','YYYY-MM-DD'),  -- 'YYYY-MM-DD' 여도 == 2021/12/30 표기
           TO_CHAR(TO_DATE('20211230095023','YYYYMMDDHH24MISS'),'YYYY-MM-DD HH24:MI:SS')
           -- 날짜타입으로 변경 => TO_CHAR로 YYYY-MM-DD 형식으로 표기
      FROM DUAL;


           
사용예)'2022.08.25'를 날짜형식으로 변환하고 10일 후의 날짜와 해당월의 마지막 날짜를 구하시오

    SELECT TO_DATE('2022.08.25','YYYY/MM/DD'),          -- 2022/08/25
           TO_DATE('2022.08.25','YYYY/MM/DD') + 10,     -- 2022/09/04
           LAST_DAY(TO_DATE('2022.08.25','YYYY/MM/DD')) -- 2022/08/31
      FROM DUAL;
           
    
    SELECT TO_DATE('2022년 08월 25일','YYYY/MM/DD'),  -- 에러남
           TO_DATE('2022 08 25','YYYY/MM/DD') + 10,     -- 2022/09/04
           LAST_DAY(TO_DATE('2022.08.25','YYYY/MM/DD')) -- 2022/08/31
      FROM DUAL; 
      
  
    --  출력되기 위해서     형식지정문자열을 기술해줘야함
    SELECT TO_DATE('2022년 08월 25일','YYYY"년" MM"월" DD"일"') + 5, -- 2022/08/30
           TO_DATE('2022 08 25','YYYY/MM/DD') + 10,                 -- 2022/09/04
           LAST_DAY(TO_DATE('2022.08.25','YYYY/MM/DD'))             -- 2022/08/31
      FROM DUAL;

    
 4. TO_NUMBER(expr [, fmt])
   - 문자열 데이터 expr을 숫자 타입으로 형을 변환 시킴
   - 'expr'은 반드시 숫자로 변환 가능해야하며 숫자로 변환할 수 없는 문자열이 포함된 경우
     'expr'이 출력되기 위해 요구되는 형식지정문자열을 기술해야 함.
   - 'fmt'은 TO_CHAR에 사용된 숫자 format string과 같다.
   

 

   
사용예)

    SELECT TO_NUMBER('12345'),
           TO_NUMBER('1234.08') FROM DUAL; 
    -- 소숫점은 별도의 형식없이 그냥 숫자로 변환됨
    
           
    SELECT TO_NUMBER('12,345'),   -- 콤마 사용으로 에러남
                   TO_NUMBER('12,345.08') FROM DUAL;       

    SELECT TO_NUMBER('12,345','99,999'),    
           TO_NUMBER('12,345.08','99,999.99') FROM DUAL;  
     -- 콤마를 사용하려면 '99,999'의 사용자지정형식 사용       
     -- 기본숫자열 '12345' 로 표기됨  
           

    SELECT TO_NUMBER('<12,345>','99,999PR'),   -- 음수 '-12,345'
           TO_NUMBER('₩12,345.08', 'L99,999.00') FROM DUAL;   
            -- 원본숫자 '12345.08' 로 표기됨

 

 등위함수(WINDOW 분석함수)
  - 특정 컬럼을 기준으로 순위를 부여할때 사용
  - RANK, DENSE_RANK, ROW_NUMBER 함수 제공
  - SELECT 절에 사용

 


(사용형식)
    RANK()|DENSE_RANK()|ROW_NUMBER() 

             OVER(ORDER BY 컬럼명1[ASC|DESC][, 컬럼명2 [ASC|DESC],...])
    . RANK() : '컬럼명1'의 값이 같으면 같은 순위 부여하고 동점순위가 n개일 때

                      차 순위는 '현재순위' + 'n'임
        ex) 18,16,16,16,14,13,10
                  1  2  2  2  5  6  7
    . DENSE_RANK() : '컬럼명1'의 값이 같으면 같은 순위 부여하고 동점순위가 n개일 때

                                     차 순위 차례대로 다음값 부여
           ex) 18,16,16,16,14,13,10
                  1  2  2  2  3  4  5
    . ROW_NUMBER :  '컬럼명1'의 값이 같아도 차례대로 순위부여 
      ex) 18,16,16,16,14,13,10
                  1  2  3  4  5  6  7 -- 마지막 번호는 전체 데이터의 갯수

사용예) 회원테이블에서 회원들의 마일리지 순으로 등수를 부여하시오. 같은 값이면 동일 등수를 부여하고
        차순위는 동점자 수만큼 건너뛴 등수부여
        Alias는 회원번호,회원명,나이,마일리지,등수

    SELECT MEM_ID AS 회원번호,
           MEM_NAME AS 회원명,
           EXTRACT(YEAR FROM SYSDATE) - EXTRACT(YEAR FROM MEM_BIR) AS 나이,
           MEM_MILEAGE AS 마일리지,
           RANK() OVER(ORDER BY MEM_MILEAGE DESC) AS "등수1(RANK)", 
           DENSE_RANK()  OVER(ORDER BY MEM_MILEAGE DESC) AS "등수2(DENSE_RANK)", 
           ROW_NUMBER() OVER(ORDER BY MEM_MILEAGE DESC)AS "등수3(ROW_NUMBER)"
      FROM MEMBER

 

 

 

사용예) 회원테이블에서 회원들의 마일리지 순으로 등수를 부여하시오. 
       마일리지가 동일한 값이면 나이가 적은 회원에게 앞선 등수를 부여하고
       나이도 같은 값이면 동일 등수를 부여하고 차순위는 동점자 수만큼 건너뛴 등수를 부여하세요
       Alias는 회원번호,회원명,나이,마일리지,등수
        
   

SELECT MEM_ID AS 회원번호,
       MEM_NAME AS 회원명,
       EXTRACT(YEAR FROM SYSDATE) - EXTRACT(YEAR FROM MEM_BIR) AS 나이,
       MEM_MILEAGE AS 마일리지,
       RANK() OVER (ORDER BY MEM_MILEAGE DESC,
                             EXTRACT(YEAR FROM SYSDATE) - EXTRACT(YEAR FROM MEM_BIR) ASC) 
                             AS "등수1(RANK)", 
       DENSE_RANK() OVER(ORDER BY MEM_MILEAGE DESC,
                                  EXTRACT(YEAR FROM SYSDATE) - EXTRACT(YEAR FROM MEM_BIR) ASC)
                                 AS "등수2(DENSE_RANK)", 
       ROW_NUMBER() OVER(ORDER BY MEM_MILEAGE DESC,
                                  EXTRACT(YEAR FROM SYSDATE) - EXTRACT(YEAR FROM MEM_BIR) ASC) 
                                 AS "등수3(ROW_NUMBER)"        
  FROM MEMBER

 

** 그룹내 순위부여
  - 그룹별로 순위 부여


(사용형식)
    RANK()|DENSE_RANK()|ROW_NUMBER() OVER(PARTITION BY 컬럼명1[컬럼명2,...]  
                                          ORDER BY 컬럼명1[ASC|DESC][,컬럼명2 [ASC|DESC], ...]

-- PARTITION BY 그룹을 묶는 것 GROUP BY과 같음

 

사용예) 사원테이블에서 각 부서별로 급여순으로 순위를 부여하시오(RANK()함수 사용)
        Alias는 사원번호,사원명,부서코드,급여,순위

 SELECT EMPLOYEE_ID AS 사원번호,
        EMP_NAME AS 사원명,
        DEPARTMENT_ID AS 부서코드,
        SALARY AS 급여,
        RANK() OVER(PARTITION BY DEPARTMENT_ID 
                    ORDER BY SALARY DESC) AS 순위
   FROM HR.EMPLOYEES
  ORDER BY 3;

 

 

 

 

 

 

사용예)2020년 분류별 판매액집계를 구하고 분류별 순위를 조회하시오
     Alias는 분류코드,분류명,판매액,순위

(서브쿼리) 
    SELECT B.LPROD_GU AS 분류코드,
           B.LPROD_NM AS 분류명,
           SUM(A.CART_QTY*C.PROD_PRICE) AS 판매액    
      FROM CART A, LPROD B, PROD C
     WHERE A.CART_PROD=C.PROD_ID
       AND C.PROD_LGU=B.LPROD_GU
       AND A.CART_NO LIKE '2020%'
     GROUP BY B.LPROD_GU ,B.LPROD_NM
     ORDER BY 1;


 --------------------------------------------------------------  

 SELECT D.BLGU AS 분류코드,
        D.BLNM AS 분류명,
        TO_CHAR(D.CSUM,'999,999,999') AS 판매액,
        RANK() OVER( ORDER BY D.CSUM DESC) AS 순위
   FROM (SELECT B.LPROD_GU AS BLGU,
                B.LPROD_NM AS BLNM,
                SUM(A.CART_QTY*C.PROD_PRICE) AS CSUM     
           FROM CART A, LPROD B, PROD C
          WHERE A.CART_PROD=C.PROD_ID
            AND C.PROD_LGU=B.LPROD_GU
            AND A.CART_NO LIKE '2020%'
          GROUP BY B.LPROD_GU ,B.LPROD_NM)D


-----------------------------------------------------------------------------                      

(제품별집계 후 분류별 순위)

SELECT B.LPROD_GU AS 분류코드,
       B.LPROD_NM AS 분류명,
       P.PROD_ID AS 상품코드,
       P.PROD_NAME AS 상품명,
       TO_CHAR(D.CSUM,'999,999,999') AS 판매액,
       RANK() OVER(PARTITION BY B.LPROD_GU ORDER BY D.CSUM DESC) AS 순위 
       --그룹별로 순위
  FROM LPROD B, PROD P,
       (SELECT A.CART_PROD AS ACID,                   
               SUM(A.CART_QTY*C.PROD_PRICE) AS CSUM     
          FROM CART A, PROD C
         WHERE A.CART_PROD=C.PROD_ID
         GROUP BY A.CART_PROD)D        
 WHERE B.LPROD_GU=P.PROD_LGU
   AND P.PROD_ID=D.ACID
 ORDER BY 1;

 

ROLLUP 과 CUBE
  - 다양한 집계를 반환
  - 반드시 GROUP BY 절에서만 사용되어야 함


  1) ROLLUP(col1[, col2,.. coln])
    . 부분합계와 전체합계를 반환
    . ROLLUP 절에 기술된 컬럼들을 이용하요 레벨별 합계를 반환
    . 레벨은 모든 컬럼이 적용된 합계가 가장 하위레벨이고, 그 이후 부터 오른쪽 부터 컬럼을 하나씩 
      제가한 단계(레벨)별 합계반환을 하며, 마지막으로 전체합계를 반화
    . ROLLUP 절에 사용된 컬럼의 수가 n개 일때 n+1개의 합계 반환

사용예)계정_SAMPLE 계정의 KOR_LOAN_STATUS 테이블에서 기간별, 지역별, 구분별 대출합계를 조회하시오
(ROLLUP을 사용하지 않은 경우)

    SELECT PERIOD AS 기간,
           REGION AS 지역,
           GUBUN AS 구분,
           SUM(LOAN_JAN_AMT) AS 대출합계 -- 기간별로 그룹을 묶고, 기간이 같은 같은 지역별로 묶고
        FROM LHY93_SAMPLE.KOR_LOAN_STATUS
    GROUP BY PERIOD,REGION,GUBUN -- 기간>>지역>>구분 이라는 그룹으로 적용되어진 합계가 나옴
    ORDER BY 1;


-- LOAN_JAN_AMT(NUMBER) : 대출잔액

 


(ROLLUP을 사용하는 경우)

  SELECT PERIOD AS 기간,
         REGION AS 지역,
         GUBUN AS 구분,
         SUM(LOAN_JAN_AMT) AS 대출합계 -- 기간별로 그룹을 묶고, 기간이 같은 같은 지역별로 묶고
    FROM LHY93_SAMPLE.KOR_LOAN_STATUS
   GROUP BY ROLLUP(PERIOD,REGION,GUBUN) -- ROLLUP 3개가 다 적용되어진 합계
   ORDER BY 1;


    -- 컬럼의 갯수가 3개 => 맨마지막에 전체합계

  -- 전체합계
      SELECT SUM(LOAN_JAN_AMT) AS 대출합계
        FROM LHY93_SAMPLE.KOR_LOAN_STATUS;

 

** 부분 ROLLUP
  - GROUP BY 절에 사용되는 컬럼 중 일부만 ROLLUP절에 사용된 경우

    SELECT PERIOD AS 기간,
           REGION AS 지역,
           GUBUN AS 구분,
           SUM(LOAN_JAN_AMT) AS 대출합계 
      FROM LHY93_SAMPLE.KOR_LOAN_STATUS
     GROUP BY PERIOD, ROLLUP(REGION,GUBUN)
     ORDER BY 1;
   -- PERIOD 고정된 상수형태로 놓는다. 전체합계는 나오지 않는다.

 

 2) CUBE(col1[, col2,.. coln])
   . CUBE절에 사용된 컬럼들의 조합 가능한 모든 경우의 집계를 반환
   . CUBE절에 사용된 컬럼의 수가 n개일 때 집계의 종류는 2^n가지임 
   -- 결과의 종류가 너무 다양해서 특수한 상황 아니면 ROLLUP을 쓴다.
   
(CUBE를 사용하는 경우)

    SELECT PERIOD AS 기간,
           REGION AS 지역,
           GUBUN AS 구분,
           SUM(LOAN_JAN_AMT) AS 대출합계 
      FROM LHY93_SAMPLE.KOR_LOAN_STATUS
     GROUP BY CUBE(PERIOD,REGION,GUBUN)  --432의 결과
     ORDER BY 1;


   

 

 

 

 

집계함수
 - 자료를 특정 컬럼을 기준으로 그룹으로 분리하여 각 그룹별 합계, 평균 등을 구하여 반환
 - 결과가 다중행으로 반환
 - SUM , AVG, COUNT, MAX, MIN 등 제공
 - 집계함수는 집계함수를 포함할 수 없다.-- 집계함수는 일반함수를 포함할 수 있다.
 
(사용형식)
    SELECT [컬럼 list],
집계함수 --집계함수만 사용되어질수 있다. -> 그룹바이 안 쓸수가 있다.
        FROM 테이블명 
      [WHERE 조건]
      [GROUP BY 컬럼명[, 컬럼명, ...]] 
      [HAVING 조건]
      [ORDER BY 컬럼|컬럼인덱스 [ASC|DESC], ...]
      - SELECT 절에서 집계함수 이외의 컬럼이 사용되면 반드시 GROUP BY 절이 기술되어야 함
      - GROUP BY 절에는 SELECT 절에 기술된 모든 일반 컬럼이 기술되어야 함
      - GROUP BY 절에 기술된 컬럼은 왼쪽에 기술된 컬럼부터 대분류, 중분류.. 등으로 그룹화되어짐
      - 집계함수에 조건이 부여될때는 HAVING 절을 이용해야 함

 

-- SELECT 절 컬럼리스트에 없어도 필요하다면 그룹바이 절에서 기준으로 사용될 수 있다.

-- 첫번째컬럼을 기준으로 그룹을 묶고, 그 다음 컬럼을 대그룹 안의 중분류로..


      
1. SUM(expr), AVG(expr), MAX(expr), MIN(expr), COUNT(*|col)
  - SUM : 각 그룹으로 기술된 expr의 모든 값의 합을 반환
  - AVG : 각 그룹으로 기술된 expr의 평균 값을 반환 -- 소숫점이 나와서 ROUND나 TRUNC로 잘라줘야함
  - MAX : 각 그룹으로 기술된 expr의 최대 값을 반환 -- 행의 최대값 GREATEST / 열의 최대값 MAX
  - MIN : 각 그룹으로 기술된 expr의 최소 값을 반환
  - COUNT : 각 그룹에 포함된 행의 수를 반환 -- 자료의 수를 구할때 쓰임
    . '*'를 사용하면 NULL 값도 하나의 행으로 카운팅됨.(일반적인 행의수, 자료수를 반환할때 사용)
    -- null 값이든 아니든 모두 카운팅 하고싶을때 *
    . 'col' : 해당 컬럼의 값 중 NULL이 아닌 행의 갯수 반환(보통 외부 조인시 사용)

 

사용예) 사원테이블에서 전체 사원의 수, 사원의 평균임금을, 임금의 합계를 조회하시오. 

             --그룹이 전체 테이블이여야 함. 일반컬럼이 셀렉트절에 없어야함.
     

  SELECT COUNT(*) AS "전체사원 수", 
         ROUND(AVG(SALARY)) AS 평균임금, 
         SUM(SALARY) AS 급여합계,
         ROUND(SUM(SALARY)/ COUNT(*))
    FROM HR.EMPLOYEES;

 

 

 

 

사용예) 사원테이블에서 부서별 사원의 수를 조회하시오.

SELECT DEPARTMENT_ID AS 부서코드, -- ~별 : 일반컬럼
       COUNT(*) AS "사원의 수"
  FROM HR.EMPLOYEES
 GROUP BY DEPARTMENT_ID -- 일반컬럼 기술(집계함수가 포함되면 그대로)
 ORDER BY 1;

 

 

 

 

 

 

 

 

 

사용예) 사원테이블에서 부서별 평균급여를 조회하시오.

SELECT DEPARTMENT_ID AS 부서코드, 
       COUNT(*) AS "사원의 수",
       ROUND(AVG(SALARY)) AS 평균급여
  FROM HR.EMPLOYEES
 GROUP BY DEPARTMENT_ID 
 ORDER BY 1;


 

 

 

 

사용예) 사원테이블에서 부서별 사원의 수가 5명 이상인 부서를 조회하시오.   

SELECT DEPARTMENT_ID AS 부서코드, 
       COUNT(*) AS "사원의 수",
       ROUND(AVG(SALARY)) AS 평균급여
  FROM HR.EMPLOYEES
--   에러 :   WHERE COUNT(*)>= 5 
--   그룹함수가 이곳에는 기술될수 없습니다.
 GROUP BY DEPARTMENT_ID 
HAVING COUNT(*)>= 5  --  GROUP BY 다음에 기술되어야 한다.
 ORDER BY 1;

 

 SELECT A.DID AS 부서코드,
        A.CNT AS 인원수
   FROM (SELECT DEPARTMENT_ID AS DID,     
                COUNT(*) AS CNT         
           FROM HR.EMPLOYEES -- VEIW 는 가상의 테이블이다.
          GROUP BY DEPARTMENT_ID       
          ORDER BY 2 DESC)A -- A를 하나의 테이블로 => A.DID / A.CNT       
  WHERE ROWNUM=1; 
  -- 제일 첫번째 행(오라클에서 제공하는 컬럼 = Psudo 컬럼 = 가상의 컬럼)

 

  

 

 

 SELECT  MAX(A.CNT) AS 인원수           
   FROM  (SELECT DEPARTMENT_ID AS DID,     
                 COUNT(*) AS CNT          
            FROM HR.EMPLOYEES 
           GROUP BY DEPARTMENT_ID       
           ORDER BY 2 DESC)A; 

 SELECT  A.DID,
         MAX(A.CNT) AS 인원수
   FROM  (SELECT DEPARTMENT_ID AS DID,     
                 COUNT(*) AS CNT             
            FROM HR.EMPLOYEES 
           GROUP BY DEPARTMENT_ID       
           ORDER BY 2 DESC)A 
  GROUP BY A.DID; 
  -- 그룹 12개 생성, 각 그룹별 인원수 최대값 MAX

 


사용예) 상품테이블에서 분류별 상품의 수를 조회하시오.

   SELECT PROD_LGU AS 분류코드,
          COUNT(*) AS "상품의 수"
     FROM PROD
    GROUP BY PROD_LGU
    ORDER BY 1;

 

 

 

 

 

 

사용예) 매입테이블에서 2020년 상반기 월별 매입집계를 조회하시오.

    SELECT EXTRACT(MONTH FROM BUY_DATE) AS 월, 
           SUM(BUY_QTY) AS 매입수량합계, 
           SUM(BUY_QTY*BUY_COST) AS 매입금액합계
      FROM BUYPROD
     WHERE BUY_DATE BETWEEN TO_DATE('20200101') 
       AND TO_DATE('20200630')
     GROUP BY EXTRACT(MONTH FROM BUY_DATE)
     ORDER BY 1;

 

사용예) 매입테이블에서 2020년 상반기 매입금액 합계가 500만원을 넘는 제품을 조회하시오.

    SELECT BUY_PROD AS 제품별,
           SUM(BUY_QTY) AS 매입수량합계, 
           SUM(BUY_QTY*BUY_COST) AS 매입금액합계
      FROM BUYPROD
     WHERE BUY_DATE BETWEEN TO_DATE('20200101') 
       AND TO_DATE('20200630')
     GROUP BY BUY_PROD
    HAVING SUM(BUY_QTY*BUY_COST)>= 5000000
     ORDER BY 1;

 

사용예) 회원테이블에서 회원들의 성별 평균 마일리지를 조회하시오.

SELECT CASE WHEN SUBSTR(MEM_REGNO2,1,1) IN('1','3') THEN 
                     '남성회원'
                ELSE 
                     '여성회원'
                END AS 구분,                 
                ROUND(AVG(MEM_MILEAGE)) AS 평균마일리지    
  FROM MEMBER
 GROUP BY CASE WHEN SUBSTR(MEM_REGNO2,1,1) IN('1','3') THEN  
                    '남성회원'
                ELSE 
                    '여성회원'
                END;-- 별칭 전까지 복붙

 

 

사용예) 2020년 5월  100만원 이상 구매한 회원의 회원번호, 회원명, 나이, 직업, 마일리지, 구매금액 합계를 조회하시오.
-- 회원별 구매금액 합계

(메인쿼리)
    SELECT A.CART_MEMBER AS 회원번호,     
           EXTRACT(YEAR FROM SYSDATE) - EXTRACT(YEAR FROM MEM_BIR) AS 나이, 
           B.MEM_JOB AS 직업, 
           B.MEM_MILEAGE AS 마일리지,
      FROM
(서브쿼리 : 2020년 5월 회원별 구매금액 합계가 1000만원 이상인 회원)  
  SELECT A.CART_MEMBER AS MID, 
         SUM(A.CART_QTY*C.PROD_PRICE) AS PSUM
    FROM CART A, PROD C
   WHERE A.CART_PROD=C.PROD_ID
     AND A.CART_NO LIKE '202005%'
   GROUP BY A.CART_MEMBER
  HAVING SUM(A.CART_QTY*C.PROD_PRICE)>10000000

 

 SELECT P.MID AS 회원번호, 
        B.MEM_NAME AS 회원명, 
        EXTRACT(YEAR FROM SYSDATE) 
        - EXTRACT(YEAR FROM B.MEM_BIR) AS 나이, 
        B.MEM_JOB AS 직업, 
        B.MEM_MILEAGE AS 마일리지, 
        P.PSUM AS "구매금액 합계"
   FROM MEMBER B,
        (SELECT A.CART_MEMBER AS MID, 
                SUM(A.CART_QTY*C.PROD_PRICE) AS PSUM
                FROM CART A, PROD C
          WHERE A.CART_PROD=C.PROD_ID
            AND A.CART_NO LIKE '202005%'
          GROUP BY A.CART_MEMBER
         HAVING SUM(A.CART_QTY*C.PROD_PRICE)>10000000)P
  WHERE B.MEM_ID=P.MID;

 

 

사용예) 2020년 4월 제품별 매출집계를 조회하시오.

 SELECT A.CART_PROD AS 제품코드, 
        B.PROD_NAME AS 제품명, 
        SUM(A.CART_QTY) AS 매출수량, 
        SUM(A.CART_QTY*B.PROD_PRICE) AS 매출금액
   FROM CART A, PROD B
  WHERE A.CART_PROD=B.PROD_ID
    AND A.CART_NO LIKE '202004%'
  GROUP BY A.CART_PROD, B.PROD_NAME 
  ORDER BY 1;
  --  GROUP BY은 SELECT절의 집계함수 
  --  빼고 일반 컬럼은 전부 기술한다.

 

 

사용예) 회원테이블에서 년령대별 평균마일리지를 조회하시오.

SELECT TRUNC(EXTRACT(YEAR FROM SYSDATE)
             - EXTRACT(YEAR FROM MEM_BIR),-1) AS 년령대, 
       ROUND(AVG(MEM_MILEAGE)) AS 평균마일리지
  FROM MEMBER
 GROUP BY TRUNC(EXTRACT(YEAR FROM SYSDATE) 
                - EXTRACT(YEAR FROM MEM_BIR),-1)
 ORDER BY 1;

    

 

 

사용예)(2020년 FROM 절 :회원별 구매수량합계)를 구하고 상위 5명의 결과를 출력하시오

(서브쿼리 : 2020년 회원별 구매수량합계)
   SELECT CART_MEMBER AS 회원번호,   
          SUM(CART_QTY) AS CSUM 
     FROM CART
    WHERE SUBSTR(CART_NO,1,4)='2020'
    GROUP BY CART_MEMBER
    ORDER BY 2 DESC
    
 -- 별칭 메인쿼리와 똑같으면 오류
(메인쿼리 : 상위 5명의 결과를 출력)
   SELECT 회원번호,회원명,구매수량합계
     FROM MEMBER A, 
          (서브쿼리) B
    WHERE A.MEM_ID=B.회원번호
      AND ROWNUM<5;

 

 (결합 : 상위 5명의 결과를 출력)
   SELECT B.CART_MEMBER AS 회원번호,
          A.MEM_NAME AS 회원명,
          B.CSUM AS 구매수량합계
     FROM MEMBER A, 
          (SELECT CART_MEMBER,
                  SUM(CART_QTY) AS CSUM 
            FROM CART
           WHERE SUBSTR(CART_NO,1,4)='2020'
           GROUP BY CART_MEMBER
           ORDER BY 2 DESC) B
    WHERE A.MEM_ID=B.CART_MEMBER
      AND ROWNUM<=5;

 

 


1. SYSDATE
  - 시스템이 제공하는 날짜 및 시각정보(년,월,일,시,분,초) 반환
  -  '+', '-' 연산이 가능하며, 날짜자료 사이의 뺄셈의 결과는 두 날짜사이의 날수(Days)를 반환

  --정오를 기준으로 반올림될수도 있음


  2. ADD_MONTHS(d, n)
 - 날짜자료 d에 포함된 월에 n을 더한 날짜 반환
 
사용예)-- 더해줄 개월 수// 출력은 날짜정보

    SELECT EMPLOYEE_ID,
           EMP_NAME,
           HIRE_DATE,
           ADD_MONTHS(HIRE_DATE,3) 
      FROM HR.EMPLOYEES;

 

 

 

 

 

 

3. NEXT_DAY(d, c) -- 주어진 날짜의 다음 만나는 요일
  - 날짜 자료 d 이후에 처음 만나는 c 요일의 날짜 반환
  - c는 '월요일', '월',....'일요일','일' 중 하나 기술
  
  
사용예)
    SELECT NEXT_DAY(SYSDATE, '금') FROM DUAL;
    SELECT NEXT_DAY(SYSDATE, '토요일') FROM DUAL;

 

4. LAST_DAY(d) - *** --년월일 있어야 함
  - 날짜자료 d 에 포함된 월의 마지막 일자를 반환
  - 주로 2월의 마지막 일자나 확정되니 않은 월의 마지막일자가 필요한 경우 사용

사용예) 회원테이블에서 각 회원의 생년월일에 포함된

월의  마지막 일을 조회하시오

  SELECT MEM_ID,
         MEM_NAME,
         MEM_BIR,
         LAST_DAY(MEM_BIR)
    FROM MEMBER;

 

 

4. LAST_DAY(d) - *** --년월일 있어야 함
  - 날짜자료 d 에 포함된 월의 마지막 일자를 반환
  - 주로 2월의 마지막 일자나 확정되니 않은 월의 마지막일자가 필요한 경우 사용

사용예) 키보드로 년도와 월을 입력받아 해당 월에 발생된 매입수량과 매입금액합게를 출력하시오

ACCEPT P_PERIOD PROMPT '년도와 월(YYYYMM) 입력 ; ' -- ACCEPT 메세지 기술
  DECLARE
         L_SDATE DATE := TO_DATE('&P_PERIOD'||'01');  -- 시작일자
         L_EDATE DATE := LAST_DAY(L_SDATE);       -- 월의 종료 일자
         L_SQTY NUMBER:=0; --수량합계 // 숫자변수 초기화 시켜야함 // 안하면 무한루트
         L_SUM NUMBER:=0; -- 매입금액합계
    BEGIN
        SELECT SUM(A.BUY_QTY), SUM(A.BUY_QTY*B.PROD_COST) INTO L_SQTY,L_SUM
        --셀렉트 INTO절 변수에 하나씩 넣는다
          FROM BUYPROD A, PROD B
    WHERE A.BUY_PROD=B.PROD_ID
      AND A.BUY_DATE BETWEEN L_SDATE AND L_EDATE;       
          DBMS_OUTPUT.PUT_LINE('기간 : '||L_SDATE||'~'||L_EDATE);
          DBMS_OUTPUT.PUT_LINE('매입수량 합계 : '||TO_CHAR(L_SQTY,'9,999')||'개');
          DBMS_OUTPUT.PUT_LINE('매입금액 합계 : '||TO_CHAR(L_SUM,'999,999,999')||'원');
          DBMS_OUTPUT.PUT_LINE('----------------------------------');   
  END; 

---------------------------------------
기간 : 2020/06/01~2020/06/30
매입수량 합계 :    206개
매입금액 합계 :   48,090,000원

 

5. EXTRACT(fmt FROM d) - *****  -- 추출하다
  - 주어진 날짜 자료 d 에서 'fmt'로 정의된 값을 반환
  - 'fmt'는 YEAR, MONTH, DAY, MINUTE, SECOND 중 하나
  - 결과는 숫자형 자료임
  
사용예) 회원테이블에서 회원들의 생년월일(MEM_BIR) 컬럼의 값을 사용하여 나이를 계산하시오
    Alias 회원번호,회원명,생년월일,나이

    SELECT MEM_ID AS 회원번호,
           MEM_NAME AS 회원명,
           MEM_BIR AS 생년월일,
           EXTRACT(YEAR FROM SYSDATE) - EXTRACT(YEAR FROM MEM_BIR) AS 나이 
           -- 오늘날짜 정보에서 '년도'를 뽑음 - 맴버 생년월일의 년도를 뽑음
     FROM MEMBER



 

 

 

사용예) 회원테이블에서 이번달 생일인 회원을 찾아 보너스 마일리지를 100포인트씩 지급하려 한다.
       이번달 생일인 회원정보를 조회하시오
       Alias 회원번호,회원명,생년월일,원마일리지,변경마일리지
   

SELECT MEM_ID AS 회원번호,
       MEM_NAME AS 회원명,
       MEM_BIR AS 생년월일,
       MEM_MILEAGE AS 원마일리지,
       MEM_MILEAGE + 100 AS 변경마일리지
  FROM MEMBER
 WHERE EXTRACT(MONTH FROM SYSDATE)=EXTRACT(MONTH FROM MEM_BIR)

 

 

6. MONTHS_BETWEEN(d1,d2) -**
  - 두 날짜자료 d1과 d2 사이의 개월 수를 반환
  - 경력계산 등 날짜 자료 중 개월 수가 필요한 경우 사용
  
사용예) 사원테이블에서 80번 부서의 직원들의 근속년수를 계산하시오.
       근속년수는 월단위 까지 계산하시오(XXS년 XX월)
       Alias는 사원번호,사원명,입사일,직무코드,근속년수

 

 SELECT EMPLOYEE_ID AS 사원번호,
        EMP_NAME AS 사원명,
        HIRE_DATE AS 입사일,
        JOB_ID AS 직무코드,
        ROUND(MONTHS_BETWEEN(SYSDATE,HIRE_DATE)) AS 근속개월수,
        TRUNC(MONTHS_BETWEEN(SYSDATE,HIRE_DATE)/12)||'년'|| 
        -- XXX월을 12로 나누면 몫: 년수
        LPAD(ROUND(MOD(MONTHS_BETWEEN(SYSDATE,HIRE_DATE),12)),3)||'개월'
        AS 근속년수-- XXX월을 12로 나눈 나머지 : 개월수
   FROM HR.EMPLOYEES
  WHERE DEPARTMENT_ID = 80;

 

 

 

+ Recent posts