상세 컨텐츠

본문 제목

Oracle -GROUPING, HAVING, EXTRACT,MAX, SEQUENCE ,INDENTITY

IT/DBMS

by TMI1 2025. 7. 8. 10:58

본문

문제1.

-- 위에서 조회한 내용을 아래와 같이 조회될 수 있도록 쿼리문을 구성한다.
/*
부서번호        급여합
---------- ----------
        10       8750
        20      10875
        30       9400
      인턴       8000
   모든부서      37025
---------------------
*/

SELECT CASE GROUPING(DEPTNO) WHEN 0 THEN NVL(TO_CHAR(DEPTNO), '인턴')
            ELSE '모든부서' -- 문자타입
            END "부서번호"
            ,  SUM(SAL)
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO);
/*
10	8750
20	10875
30	9400
인턴	8000
모든부서	37025
*/

-- 문제2
--○TBL_SAWON 테이블을 대상으로 다음과 같이 조회될 수 있도록 쿼리문을 구성한다.
/*
-------------------
 성별    |  급여합
-----------------
  남          XXX
  여         XXXX
모든사원    XXXXX
------------------
*/

SELECT CASE GROUPING(T.성별) WHEN 0 THEN T.성별
        ELSE '모든사원' 
        END "성별"
    , SUM(T.급여) "급여합"   
FROM
(
    SELECT CASE WHEN SUBSTR(JUBUN,7,1) IN ('1','3') THEN '남'
                WHEN SUBSTR(JUBUN,7,1) IN ('2','4') THEN '여'
                ELSE '성별판별불가'
            END "성별"
         ,SAL "급여"
    FROM TBL_SAWON
)T
GROUP BY ROLLUP(T.성별);
/*
남	15100
여	11000
모든사원	26100
*/

 

-- 문제3
--○TBL_SAWON 테이블을 대상으로 다음과 같이 연령대별 인원수 형태로 
--  조회될 수 있도록 쿼리문을 구성한다.
/*
----------------
연령대   인원수
--------------
10         X
20         X
30         X
50         X
전체       XX
--------------

SELECT CASE GROUPING(Q.연령대) WHEN 0 THEN TO_CHAR(Q.연령대)
            ELSE '전체'
       END "연령대"
     , COUNT(Q.연령대) "인원수"
FROM
(
    SELECT CASE WHEN T.나이 >=50 AND T.나이<60 THEN 50
                WHEN T.나이 >=40 THEN 40
                WHEN T.나이 >=30 THEN 30
                WHEN T.나이 >=20 THEN 20
                WHEN T.나이 >=10 THEN 10
                ELSE 0
            END "연령대"
    FROM
    (
        SELECT CASE WHEN SUBSTR(JUBUN, 7, 1) IN ('1','2')
                 THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) + 1899)    
                 WHEN SUBSTR(JUBUN, 7, 1) IN ('3','4')
                 THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) +1999) 
                 ELSE -1
                END "나이"
        FROM TBL_SAWON
    ) T
) Q
GROUP BY ROLLUP(Q.연령대);
/*
연령대  인원수
------- ----------
20       5
30       1
40       3
50       4
전체     13
*/

방법2)
SELECT CASE GROUPING(T.연령대) WHEN 0 THEN TO_CHAR(T.연령대)
        ELSE '전체'
        END "연령대"
        ,COUNT (T.연령대) "인원수" 
FROM
(
    SELECT TRUNC(CASE WHEN SUBSTR(JUBUN, 7, 1) IN ('1','2')
             THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) + 1899)    
             WHEN SUBSTR(JUBUN, 7, 1) IN ('3','4')
             THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) +1999) 
             ELSE -1
            END , -1) "연령대" 
    FROM TBL_SAWON
)T
GROUP BY ROLLUP(T.연령대);
/*
연령대  인원수
------- ----------
20       5
30       1
40       3
50       4
전체     13
*/

문제4.

--○TBL_EMP 테이블을 대상으로 입사년도별 인원수를 조회한다.
/*
-----------------------------
    입사년도        인원수
-----------------------------
    1980              1 
    1981             10     
    1982              1 
    1987              2 
     2025              5 
    전체              19  
-----------------------------
*/

SELECT TO_CHAR(HIREDATE, 'YYYY') "입사년도"
     , COUNT(*) "인원수"
FROM TBL_EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY')
ORDER BY 1;
/*
1980	1
1981	10
1982	1
1987	2
2025	5
*/

 

-- ■■■ HAVING ■■■ --

--○ EMP 테이블에서 부서번호가 20, 30인 부서를 대상으로
-- 부서의 총 급여가 10000 보다 적을 경우만 부서별 총 급여를 조회한다. 
-- FWG HSO

SELECT DEPTNO, SUM(SAL)
FROM EMP
WHERE DEPTNO IN(20,30)
GROUP BY DEPTNO;
/*
30	9400
20	10875
*/

SELECT DEPTNO, SUM(SAL)
FROM EMP
WHERE DEPTNO IN(20,30)
    AND SUM(SAL) < 10000
GROUP BY DEPTNO; 
--==>> 에러발생
/*
ORA-00934: group function is not allowed here
00934. 00000 -  "group function is not allowed here"
*Cause:    
*Action:
736행, 9열에서 오류 발생
*/

SELECT DEPTNO, SUM(SAL)
FROM EMP
WHERE DEPTNO IN(20,30)
GROUP BY DEPTNO 
-- 그룹에 대한 조건은 해빙절에 위치
HAVING SUM(SAL) < 10000;  --파싱순서체크 
--==>> 30	9400

-- CHECK~!!! 
SELECT DEPTNO, SUM(SAL)
FROM EMP
GROUP BY DEPTNO 
-- 그룹에 대한 조건은 해빙절에 위치 (그룹조건이 아닌 것은 쓰지 않는 것이 좋음) 
HAVING SUM(SAL) < 10000 -- 
    AND DEPTNO IN(20,30);  --파싱순서체크 
--==>> 30	9400

-- ※ 그룹 함수는 2 LEVEL 까지 중첩해서 사용할 수 있다. 
--    이마저도 MS-SQL 은 불가능하다. 

SELECT ... MAX(SUM(SAL)) "결과확인" -- ...에 추가로 무엇을 한다는 안된다는 뜻임 
FROM EMP
GROUP BY DEPTNO;

-- ※ RANK()
--    DENSE_RANK()
--    → ORACLE 9i 부터 적용 ... MS-SQL 2005 부터 적용...

--※ 위와 같이 하위 버전에서 RANK() 나 DENSE_RANK() 를 사용할 수 없기 때문에
--   이를 대체하여 연산을 수행할 수 있는 방법을 강구해야 한다.

-- 예를 들어, 급여의 순위를 구해야 하는 상황이라면...
-- 해당 사원의 급여보다 더 큰 급여 값이 몇 개인지 확인한 후 
-- 그 확인한 숫자에 +1을 추가 연산해주면 그것이 곧 등수가 된다. 

SELECT ENAME, SAL
FROM EMP;

--  SMITH 사원의 급여 등수
SELECT COUNT(*) + 1 "SMITH급여등수"
FROM EMP
WHERE SAL > 800;    -- SMITH의 급여 

SELECT ENAME "사원명", SAL "급여", 1 "급여등수"
FROM EMP;

-- ※ 상관 서브 쿼리(서브 상관 쿼리) 
--    메인 쿼리에 있는 테이블의 컬럼이 
--    서브 쿼리의 조건절(WHERE절, HAVING절)에 사용되는 경우
--    우리는 이 쿼리문을 상관 서브쿼리(서브 상관 쿼리)라고 부른다. 

(1) "급여등수"

SELECT ENAME "사원명", SAL "급여", (SELECT COUNT(*) + 1 "SMITH급여등수"
FROM EMP
WHERE SAL > 800;
FROM EMP;

SELECT ENAME "사원명", SAL "급여", (SELECT COUNT(*) + 1
                                   FROM EMP
                                   WHERE SAL > 800) "급여등수" 
FROM EMP;

SELECT ENAME "사원명", SAL "급여", (SELECT COUNT(*) + 1
                                   FROM EMP E2
                                   WHERE E2.SAL > E1.SAL) "급여등수" -- E2급여셀 > 스미스부터~ 의 급여 
FROM EMP E1
ORDER BY 3;
/*                              
KING	5000	1
FORD	3000	2
SCOTT	3000	2
JONES	2975	4
BLAKE	2850	5
CLARK	2450	6
ALLEN	1600	7
TURNER	1500	8
MILLER	1300	9
WARD	1250	10
MARTIN	1250	10
ADAMS	1100	12
JAMES	950	13
SMITH	800	14
*/

-- 문제5
--○ EMP 테이블을 대상으로
--   사원명, 급여, 부서번호, 부서내급여등수, 전체급여등수 항목을 조회한다.
--   단, RANK() 함수를 사용하지 않고, 서브 상관 쿼리를 활용할 수 있도록 한다. 

SELECT COUNT(*) + 1
FROM EMP E2
WHERE SAL > 5000
      AND DEPTNO = 10;
--위 수식을 짤라서 (100) 자리에 넣어주고 최종 쿼리문 완성       
SELECT ENAME "사원명", SAL "급여", DEPTNO "부서번호" 
        ,(SELECT COUNT(*) + 1
            FROM EMP E2
            WHERE E2.SAL > E1.SAL
                  AND E2.DEPTNO = E1.DEPTNO) "부서내급여등수"
        ,(SELECT COUNT(*) + 1
         FROM EMP E2
         WHERE E2.SAL > E1.SAL) "전체급여등수"
FROM EMP E1
ORDER BY E1.DEPTNO, E1.SAL DESC;
/*
KING	5000	10	1	1
CLARK	2450	10	2	6
MILLER	1300	10	3	9
SCOTT	3000	20	1	2
FORD	3000	20	1	2
JONES	2975	20	3	4
ADAMS	1100	20	4	12
SMITH	800	20	5	14
BLAKE	2850	30	1	5
ALLEN	1600	30	2	7
TURNER	1500	30	3	8
MARTIN	1250	30	4	10
WARD	1250	30	4	10
JAMES	950	30	6	13
*/

-- 문제6
--○ EMP 테이블을 대상으로 다음과 같이 조회될 수 있도록 쿼리문을 구성한다.
/*
----------------------------------------------------------------------------------------------------------------------
    사원명     부서번호    입사일         급여      부서내입사별급여누적(→ 부서 내에서 입사일자별로 급여가 누적된 상황 확인)
----------------------------------------------------------------------------------------------------------------------
    CLRAK       10      1981-06-09      2450            2450
    KING        10      1981-11-17      5000            7450
    MILLER      10      1982-01-23      1300            8750    
    SMITH       20      1980-12-17        800            800    
    JONES       20      1981-04-02       2975           3775
                            :
-----------------------------------------------------------------------------------------------------------------------                       
*/

SELECT ENAME "사원명", DEPTNO"부서번호",HIREDATE "입사일", SAL"급여"
    ,(SELECT SUM(E2.SAL)
        FROM EMP E2
        WHERE E2.DEPTNO = E1.DEPTNO -- 같은 부서이면서라는 조건 
         AND E2.HIREDATE <=E1.HIREDATE) "부서내입사별급여누적"
FROM EMP E1  
ORDER BY 3,2;
--==>> 
/*
CLARK	10	81/06/09	    2450	2450
KING	10	81/11/17	5000	7450
MILLER	10	82/01/23	    1300	8750
SMITH	20	80/12/17	    800	800
JONES	20	81/04/02	    2975	3775
FORD	20	81/12/03	    3000	6775
SCOTT	20	87/07/13	    3000	    10875
ADAMS	20	87/07/13	    1100	    10875
ALLEN	30	81/02/20	    1600	1600
WARD	30	81/02/22	    1250	2850
BLAKE	30	81/05/01    	2850	5700
TURNER	30	81/09/08    	1500	7200
MARTIN	30	81/09/28	    1250	8450
JAMES	30	81/12/03	    950	9400
*/

 

-- 문제7
--○ TBL_EMP 테이블에서 입사한 사원의 수가 제일 많았을 때의
--   입사년월과 인원수를 조회할 수 있도록 쿼리문을 구성한다. 
/*
------------------------
    입사년월    인원수
------------------------
    2025-07        5
------------------------    
*/

SELECT MAX(COUNT(*))
FROM TBL_EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM');
--==>> 5 -- 인원수 가장 많은 걸 알려줘 

SELECT TO_CHAR(HIREDATE, 'YYYY-MM') "입사년월"
     , COUNT(*) "인원수"
FROM TBL_EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM')
HAVING COUNT(*) = (SELECT MAX(COUNT(*))
                FROM TBL_EMP
                GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM')); 
--==>> 2025-07	5

 

-- ※ 게시판의 게시물 번호를
--  SEQUENCE 나 INDENTITY 를 사용하게 되며 (EX : 번호표 발행 모듈)
--  특정 게시물을 삭제했을 경우, 삭제한 게시물의 자리에
--  다음 번호를 가진 게시물이 등록되는 상황이 발생하게 된다.
--  이는, 보안 측면에서나 ... 미관상 ... 바람직하지 않은 상황일 수 있기 때문에
--  ROW_NUMBER() 의 사용을 고려해 볼 수 있다.
--  관리의 목적으로 사용할 때는 SEQUENCE 나 INDENTITY를 사용하지만
--  단순히 게시물을 목록화하여 사용자에게 리스트 형식으로 보여줄 때는
--  사용하지 않는 것이 좋다. 
-- EX) 싸이월드 쪽지 NO. 79885414 << 게시물의 관리번호 

UPDATE TBL_AAA 
SET GRADE='A'
WHERE NO=6;
--==>> 1 행 이(가) 업데이트되었습니다.
-- 식별자를 갖고 있는것이 관리측면에서 좋음. 

--○ SEQUENCE 생성(시퀀스, 주문번호)
--   → 사전적인 의미 : 1.(일련의) 연속적인 사건들 2.(사건,행동 등의) 순서 
-- SEQUENCE생성시 리모컨 형태 - 은행에서 번호표 뽑을때마다
CREATE SEQUENCE SEQ_BOARD -- 시퀀스 기본 생성 구문(MYSQL의 INDENTITY와 동일한 개념)
START WITH 1              -- 시작값
INCREMENT BY 1            -- 증가값 (얼마씩 증가해 나갈래?)
NOMAXVALUE                -- 최대값 제한 없음 
NOCACHE;                  -- 캐시 사용 안함(없음) -- 번호표를 미리 많이 뽑아놓은것=그것이 캐시
--==>> Sequence SEQ_BOARD이(가) 생성되었습니다. 
-- 시퀀스는 생성 후 수정 불가함. 

--○ 테이블 생성 
-- 테이블명 : TBL_BOARD
CREATE TABLE TBL_BOARD                  --  TBL_BOARD이름의 테이블 생성 → 게시판
(   NO          NUMBER                  -- 게시물 번호     X
,   TITLE       VARCHAR2(50)            -- 게시물 제목     O
,   CONTENTS    VARCHAR2(2000)          -- 게시물 내용     O
,   NAME        VARCHAR2(20)            -- 게시물 작성자   △
,   PW          VARCHAR2(20)            -- 게시물 패스워드 △
,   CREATED     DATE DEFAULT SYSDATE    -- 게시물 작성일   X -- 제약조건의 일종 
);
--==>> Table TBL_BOARD이(가) 생성되었습니다.

관련글 더보기

댓글 영역