본문 바로가기
📝 자격증/SQLD : SQL 개발자

[2과목] SQL 활용 - 서브쿼리, 집합연산자, 그룹함수, 윈도우함수, TOPNQUERY, 계층형질의, PIVOT, 정규표현식

by b5ingbo2ng 2024. 5. 20.

Part1, 서브쿼리

📍서브쿼리

  • 메인 쿼리의 반댓말 
  • 하나의 SQL 문 안에 포함되어 있는 또 다른 SQL 문을 말함
  • 알려지지 않은 기준을 이용한 검색에 사용
  • 반드시 괄호로 묶어서 전달하는 또다른 셀렉트 문
  • 사용 가능한 곳
    • GROUP BY 절을 제외한 모든 절
    • SELECT, FROM, WHERE, HAVING, ORDER BY, 기타 DML(INSERT-VALUES, UPDATE-SET절에 사용가능)
- 단일행 비교 연산자 : =, >, <, <>
- 다중행 비교 연산자 : IN, ALL, ANY, SOME

 

📍서브쿼리 종류

1. 동작하는 방식에 따라

  • UN-CORRELATED : 비연관 서브쿼리 
    • 서브 쿼리가 메인 쿼리 컬럼을 갖고 있지 않은 형태의 서브쿼리
    • 메인쿼리에 서브쿼리가 실행된 결과 값을 제공하기 위한 목적으로 사용
  • CORRELATED : 연관 서브쿼리 
    • 서브쿼리가 메인 쿼리 컬럼을 가지고 있는 형태의 서브쿼리
    • 일반적으로 메인 쿼리가 먼저 수행된 후에 서브쿼리에서 조건이 맞는지 확인하고자 할 때 사용

 

2. 위치에 따라

  • ① 스칼라 서브쿼리 
    • 한행, 한 컬럼만을 반환하는 서브쿼리
    • SELECT에 사용하는 서브쿼리 
      • 서브쿼리 결과를 마치 메인쿼리의 하나의 컬럼처럼 사용하기 위해 주로 사용
       

 

  • ② 인라인 뷰
    • FROM 절에 사용하는 서브쿼리
    • ORDER BY 사용 가능
    • 서브쿼리 결과를 "테이블"처럼 사용하기 위해 주로 사용
     

 

뷰 : 테이블은 실제로 데이터를 가지고 있는 반면, 뷰는 실제 데이터를 가지고 있지 않다. (가상 테이블이라고도 함)
실행 시점에 sql 재작성 하여 수행됨
===============
뷰 사용 장점
① 독립성 : 테이블 구조가 변경되어도 뷰를 사용하는 응용 플그램은 변경하지 않아도 된다.
② 편리성 : 복잡한 질의를 뷰로 생성함으로써 관련 질의를 단순하게 작성할 수 있다.
③ 보안성 : 직원의 급여정보와 같이 숨기고 싶은 정보가 존재할 때 사용

 

  • ③ WHERE 절 서브쿼리
    • 가장 일반적인 서브쿼리
    • 비교상수자리에 값을 전달하기 위한 목적으로 주로 사용 (상수항의 대체)
    • 리턴 데이터의 형태에 따라 단일행 서브쿼리, 다중행 서브쿼리, 다중컬럼 서브쿼리, 상호연관 서브쿼리로 구분

 

 

📍WHERE 절 서브쿼리 종류

1) 단일행 서브쿼리

  • 서브쿼리 결과가 1개의 행이 리턴되는 형태
  • 단일행 서브쿼리 연산자 종류

 

  • ex) 전체 직원의 평균급여보다 높은 값을 받는 능력있는 직원을 추출하기

 

 

2) 다중행 서브쿼리

  • 서브쿼리 결과가 여러개의 행이 리턴되는 형태
  • =, >, < 와 같은 비교 연산자 사용불가 (여러 값이랑 동시에 같다? 그것보다 동시에 크다? 비교할 수 없는 연산자들)
  • 서브쿼리 결과를 하나로 요약하거나 다중행 서브쿼리 연산자를 사용

 

❉ ~~ > ALL(200, 300) : 200보다도 커야되고, 300보다도 커야된다~ ➡️ 최댓값인 300보다 커야된다! 라는 뜻
❉ ~~ ><ALL(200, 300) : 200보다도 작아야되고, 300보다도 작아야된다~ ➡️ 최솟값인 200보다 작아야 된다! 라는 뜻
-----------------------------------------------------------------------
❉ ~~ > ANY(200, 300) : 200보다 커도되고, 300보다 커도된다~ ➡️ 최솟값인 200보다 크면된다! 라는 뜻
❉ ~~ < ANY(200, 300) : 200보다 작아도되고, 300보다 작아도된다~ ➡️ 최댓값인 300보다 작으면된다! 라는 뜻

 

 

10번 부서의 급여 중 가장 작은 최솟값보다 큰 사람들!, ANY는 최솟값이 리턴되는 것

 

 

 

3) 다중컬럼 서브쿼리

  • 서브쿼리 결과가 여러 컬럼이 리턴되는 형태
  • 메인 쿼리와의 비교 컬럼이 2개 이상
  • 단점 : 2개를 묶어서 하다보니까 대소 비교 전달 불가 (두 값을 동시에 묶어 대소비교 할 수 없음)
  • ex) 부서별 최대 급여자 확인

최대 급여를 받는 사람이 누구얏, 다시 여러행이 나올 수 있으니까 IN 연산자로 찾기


4) 상호연관 서브쿼리

  • 메인쿼리와 서브쿼리의 비교를 수행하는 형태
  • 비교할 집단이나 조건은 서브쿼리에 명시 (메인 쿼리절에는 서브쿼리 컬럼이 정의되지 않았기 때문에 에러 발생)
  • ex) 그룹별 평균 급여를 구한 후에 그 그룹의 평균 급여보다 높은 급여를 받는 사람 정보

알렌이 속한 30번에서 평균급여값을 서브쿼리에서 구하고 그걸 메인쿼리에서 대소비교함

 

 

📍인라인뷰 Inline View

  • 쿼리 안의 뷰의 형태로 테이블처럼 FROM절에서 조회할 데이터를 정의하기 위해 사용
  • 서브쿼리 결과를 메인쿼리의 어떤 절에서도 모두 사용할 수 있음
  • 모든 연산자 사용가능
  • ex) 부서별로 최대 급여자를 추출하는데, 최대 급여랑 함께 출력

 

❉ 여기서 주의할 점, 인라인 뷰에서의 출력결과 MAX(SAL)은 컬럼 별칭 AS MAX_SAL 을 통해 메인 쿼리에 전달!

 

  • ex) 부서별로 해당 부서의 평균급여보다 높은 급여자를 출력하되, 평균 급여와 함께 출력

 

 

 

📍스칼라 서브쿼리

  • SELECT절에 사용하는 쿼리로, 마치 하나의 컬럼처럼 표현하기 위해 사용 (단 하나의 출력대상만 표현 가능)
  • 각 행마다 스칼라 서브쿼리 결과가 하나여야 함 (=단일행 서브쿼리)
  • 조인의 대체연산
  • 단일행이어야하므로 (각 직원당 하나의 부서이름이 필요하므로 WHERE 절에 = 식 중요★)



📍서브쿼리 주의사항

  • 특별한 경우 (TOP-N 분석 등)을 제외하고는 서브 쿼리절에 ORDER BY 절을 사용 불가
  • 단일 행 서브쿼리와 다중행 서브쿼리에 따라 연산자의 선택이 중요

 

 

 

 


 

Part2, 집합연산자

📍집합 연산자

두 개 이상의 테이블에서 조인을 사용하지 않고 연관된 데이터를 조회할 때
SELECT 절의 컬럼 수가 동일하고 SELECT 절의 동일 위치에 존재하는 컬럼의 데이터 타입이 상호호환일 때 사용 가능
  • SELECT문 결과를 하나의 집합으로 간주하고, 그 집합에 대한 합집합/교집합/차집합 연산
  • SELECT문과 SELECT 문 사이에 집합 연산자 정의
  • 두 집합의 컬럼 구성이 동일해야함 (컬럼명은 달라도 되지만, 각 컬럼의 데이터타입과 순서 일치 필요)
    • 두 집합의 컬럼 수 일치
    • 두 집합의 컬럼 순서 일치
    • 두 집합의 컬럼의 데이터 타입 일치 (숫자NUMBER↔️문자VARCHAR2)
    • 각 컬럼의 사이즈는 달라도 됨
  • 전체 집합의 데이터 타입과 컬럼명은 첫번째 집합에 의해 결정됨 

[숫자&문자] 비교할 때는 문자를 숫자로 변경한 후에 집합 연산자 사용가능

 

📍합집합 - UNION, UNION ALL

  • 두 집합의 총 합(전체) 출력
  • 1) UNION : 중복된 데이터는 한번만 출력, 합집합 정렬
    • 중복된 데이터를 제거하기 위해 내부적으로 정렬을 수행하기 때문에
    • 웬만해서 중복된 데이터가 없을 경우에는 불필요한 정렬을 방지하기 위해 UNION ALL을 쓰길 권장
  • 2) UNION ALL : 중복되더라도 ALL 모두 출력하고 싶어

 

📍교집합 - INTERSECT

  • 두 집합의 교집합(공통으로 있는 행) 출력
  • 중복 한개로

30번 부서 중복

 

 

📍차집합 - MINUS, EXCEPT

  • 두 집합의 차집합 (한쪽 집합만 존재하는 행) 출력
  • a-b, b-a는 다르므로 집합의 순서 주의
  • 중복 한개로

20, 30 - 20 = 30

 

 


 

Part3, 그룹함수

📍그룹함수 - COUNT, SUM, AVG, MIN/MAX, VARIANCE/STDDEV

  • 숫자 함수 중 여러값을 전달하여 하나의 요약값을 출력하는 다중행 함수
  • 수학/통계 함수들 (기술 통계 함수)
  • GROUP BY 에 의해 그룹별 연산처리
  • NULL은 무시하고 연산된다.

 

📍COUNT

  • 행의 수를 세는 함수
  • COUNT(*), COUNT(EMPNO) → NULL값이 없는 컬럼이나 PK를 세면, 행의 전체수를 리턴받을 수 있음

 

📍AVG

  • 그냥 AVG(COMM)하면 null값 제외하고 4명에 대한 평균 리턴
  • 합 / 카운트 하면 전체 14명에 대한 평균으로 리턴
  • 그러면 AVG(NVL(COMM,0)) 하면 널값을 다 0으로 바꾸고 14명에 대한 평균 받을 수 있음

 

📍MIN/MAX

  • 문자, 숫자, 날짜 모두 가능 (오름차순 순서대로 최소, 최대 출력)

 

📍GROUP BY FUNCTION ★

  • 여러 그룹바이 결과를 동시에 출력*(합집합) 하는 기능
  • 그룹바이로 요약된 정보에, 전체 총계를 같이 표현할 수 있는 함수
종류 설명 치환
GROUPING SETS(A,B) ① A 하나
② B 하나
각각 하나씩 하고 union all 한 결과와 동일
ROLLUP(A,B)  ① DEPTNO를 먼저썻으니까 그거별로 정리된 값 쓰고,
② 그 다음에 그 2개를 묶어서 한번에 그룹바이 해주고
③ 전체 총계
먼저 2개별로 그룹핑, 먼저 나열된 DEPTNO별로 그룹핑, 마지막에 전체 총계한 후에 UNION ALL
CUBE(A,B) ① A단독그룹핑
② B단독그룹핑
③ A-B 두개 묶어서
④ 전체 그룹 연산결과 출력
GROUPING SETS(DEPTNO, JOB, (DEPTNO, JOB), ()) ➡️ 나열한 대로 각각 단독, 단독, 집합, 총계

 

 

1. GROUPING SETS(A,B) = 각각 하나씩 하고 union all 한 결과와 동일

  • 나열된 컬럼 마다의 그룹바이 연산을 다 보여줌! (= A별, B별 그룹 연산 결과 출력) 
  • 둘다보여주니까 나열 순서 중요하지 않음
  • 기본출력에 전체 총계는 출력되지 않음

deptno별로도 그룹바이 하고 싶고, job별로도 그룹바이 하고 싶을때, 한번에 각각 그룹바이하고 합쳐줌

 

 

각각 하나씩 그룹바이 하고, 빈칸에 NULL로 컬럼 채워넣고, 그 두개 UNION ALL하면 결과 똑같음

 

+) 전체 결과의 총계 보고 싶을 때 : GROUPING SETS(DEPTNO, JOB, () );

빈 괄호를 추가하면 전체 총계 출력

 

 

2. ROLLUP(A,B) = 먼저 2개별로 그룹핑, 먼저 나열된 DEPTNO별로 그룹핑, 마지막에 전체 총계한 후에 UNION ALL

  • 나열 순서가 중요함
  • 첫번째 나열된걸 먼저 단독 그룹핑으로 묶어주고, 그 다음에 그 두개를 묶어서 그룹바이 해줌
    • 그룹핑 값이 null이면 1로 출력됨 (기본값) → CASE WHEN으로 1이면, '월별합계'라고 써라 값 지정 가능
  • 기본적으로 전체 총계가 출력됨
  • Subtotal을 생성하기 위해 사용

DEPTNO를 먼저썻으니까 그거별로 정리된 값 쓰고, 그 다음에 그 2개를 묶어서 한번에 그룹바이 해주고, 전체 총계
null인 자리는 0 이 아니라 1로 치환된다!!! 이 값이 1일 때 이런표현을써라~

 

먼저 2개별로 그룹핑한거랑, 먼저 나열된 DEPTNO별로, 마지막에 전체 총계한 후 컬럼 수 NULL로 맞춰서 UNION ALL 하면 동일한 형식

 


3. CUBE(A,B) = GROUPING SETS, UNION ALL 로 표현 가능

  • A단독그룹핑, B단독그룹핑, A-B 두개 묶어서 전체 그룹 연산결과 출력
  • 전체 총계 출력됨
  •  
  • 결합 가능한 모든 값에 대하여 다차원 집계를 생성, ROLLUP에 비해 시스템에 부하 심함. 2^N

  • 순서 상관없음 

전체총꼐, a, b, a&b => 총 4개의 집단

 

+) GROUPING SETS(DEPTNO, JOB, (DEPTNO, JOB), ()) ➡️ 나열한 대로 각각 단독, 단독, 집합, 총계

CUBE(A, B) = GROUPING SETS(A, B, (A,B ), ())

 

 

 


 

Part4, 윈도우 함수

📍WINDOW FUNCTION

  • 행과 행간의 관계를 정의하거나 행과 행간을 비교, 연산하는 함수
  • 원칙적으로는 하나의 행을 읽으면 다른 행과 비교가 어렵지만,, 그걸 가능하게 해주는게 window function
  • OVER 절을 사용해서 윈도우 함수로 사용 가능
  • GROUP BY 를 쓰지 않고 전체 데이터를 출력하면서 그룹 연산 가능
  • LAG, LEAD, SUM, AVG, MIN, MAX, COUNT, RANK

  • 윈도우함수 뒤에 내가 sum하고 싶은 대상을 쓰고,
  • PARTITION BY : 그룹연산할 group by 컬럼 (반드시 연산할 대상을 그룹함수의 입력값으로 전달)
  • ORDER BY 어떤 순서로 (rank, 누적합 같은 경우-sum, avg, min, max, count 등)
  • ROWS : 연산범위 설정 - 누적합 구할 때 범위 설정할 수 있으니까
    • 범위 설정할 때 order by 필수

 

그냥 전체 행 하나씩 출력해도되는 컬럼들이랑, sum처럼 한줄로 요약하는 함수가 함께 쓰이면서 오류남 ➡️ 윈도우 함수로 해결 가능

 

 

1. SUM OVER() : 전체 총합, 그룹별 총합 출력 가능

  • ex) 각 직원정보와 함께 급여 총합 출력

 

 

서브쿼리라서 성능이 1depth보다 좋지 않음

 

 

sal에 대한 총합, 누적합/파티션할것도 아니라서 뒤에는 아무것도 안쓰고 1depth로 총합 출력 같이 함

 

 

 

AVG OVER, MINMAX OVER, COUNT OVER 동일하게 사용하면 됨

 

 

📍WINDOW 함수의 연산범위 : 집계연산시 행의 범위 설정 가능 ★

  • ROWS, RANGE 중 하나 선택 (디폴트는 range)
    • ROWS : 값이 같더라도 한 행씩 연산 ➡️ 대신, rows를 쓰면 반드시 뒤에 범위를 적어줘야 함 (어디부터 어디까지 연산)
    • RANGE (디폴트) : 정렬을 하고, 순서대로 누적합을 계산하는데 앞뒤 같은 값이 나오면 하나로 묶어서 동시 연산
  • BETWEEN A AND B
    •  A 시작점 정의
      • CURRENT ROW : 현재행부터
      • UNBOUNDED PRECENDING : 처음부터 (디폴트값)
      • N PRECENDING : N 이전부터
    • B 마지막 시점 정의
      • CURRENT ROW : 현재행까지 (디폴트값-처음부터 현재행까지 다 더해!)
      • UNBOUNDED FOLLOWING : 마지막까지
      • N FOLLOWING : 5개 이후 라인 까지!

 

❉ 디폴트 : 처음부터 현재행까지 차례대로 누적합!, range → 값이 같은건 하나로 생각하고 누적합에서 한번에 두개 다 더함

누적합은 order by가 필수, 그래야 순서를 알 수 있으니까

 

 

 

❉ ROWS 범위 설정시 BETWEEN ➡️ 값이 같더라도 한번에 계산안하고 하나씩 누적합

UNBOUNDED PRECEDING AND CURRENT ROW : 처음부터 현재행까지

 

 

 

❉ UNBOUNDED PRECEDING AND 1 FOLLOWING : 누적합 계산시 처음부터 그 다음행까지 연산 

3번째 행의 누적합은 처음부터 그 다음 총 4개의 누적합을 3번째 자리에 적기

 

 

 

📍순위 관련 함수

순위 관련 함수 개념 예시
RANK 동일한 값에 대해서는 동일한 순위를 부여 1,2,2,4,5
DENSE_RANK 동일한 순위를 하나의 등수로 간주 1,2,2,3,4,5
ROW_NUMBER 동일한 값이라도 고유한 순위 부여 1,2,3,4,5
  • 1) RANK (순위)
    • ① RANK WITHIN GROUP : 특정 값에 대한 순위 하나만 확인하고 싶을 때 (윈도우함수 아니고 일반함수)

순위는 당연히 order by 필요

 

          ❉ 급여가 3000정도면 전체 순위가 얼마일까? :

          이런식으로 하나만 궁금할때 RANK(3000) WITHIN GROUP (ORDER BY SAL) → 으음~ 2등정도 군~!

 

 

  • ② RANK() OVER() : 전체 중, 특정 그룹 내에 값의 순위 확인, 순위 구할 대상을 order by절에 여러개 나열 가능, 그룹 내 순서 구할 시 PARTITION BY 절 사용

order by 여러개 나열될때마다 방법 지정 가능

 

          ❉ 각 직원의 급여의 전체 순위 (큰 순서대로) : 전체니까 굳이 partition by 사용 x

          동순위 나오면, 2등으로 똑같이 처리하고, 그 다음순위는 3등 아니고 4등으로!! 

RANK 는 동순위가 몇명이냐에 따라 동순위 다음 순위가 달라짐!

 

 

          ❉ 각 직원의 급여의 부서별 순위 (큰 순서대로) : 조직별로 순위가 궁금한거니까 partition by 사용 !

 

 

 

  • ③  DENSE_RANK : 누적 순위, 값이 같을 때 동일한 순위 부여 후 다음 순위가 바로 이어지는 순위 부여 방식
    ex) 1등이 5명이더라도 그 다음 순위가 2등 
  • ④ ROW_NUMBER : 그냥 일련의 연속된 행 번호, 동일한 순위를 인정하지 않고 단순히 순서대로 나열한 대로의 순서값 리턴

 

          ❉ RANK() OVER(), DENSE_RANK(), ROW_NUMBER() 비교 시험 출제

RANK() OVER() : 동순위 개수만큼 이후 숫자 +됨, 2등 2명 다음은 4등
DENSE_RANK() : 2등 다음은 그냥 3등
ROW_NUMBER() : 얜 그냥 1,2,3,4,5,6,7,8,9,~

 

 


📍LAG(파티션별 윈도우에서 이전 몇번째 행의 값), LEAD(이후 몇번째 행의 값)

  • 행 순서대로 각각 이전 값(LAG), 이후 값 (LEAD) 가져오기
  • ORDER BY 절 필수
  • LAG(가져올 컬럼, 몇번째 값을 가져올까
  • sql server 지원 X

 

❉ 바로 이전 입사자의 급여 ➡️ 우선 고용된 날짜순으로 나열하고 나서, 이전꺼 SAL을 가져와라

이전/이후값 가져올때 값이 같더라도 항상 행의 순서대로 이전,이후 하나를 가져오기 때문에
     ORDER BY 기준을 2개로 두면서 충분히 전달하고 값을 가져오면 됨

한행에 모두 출력할 수 있는 순간, 비교 가능해짐

 

 


📍FIRST_VALUE(파티션별 윈도우의 처음 값), LAST_VALUE(파티션별 윈도우의 마지막 값)

  • 정렬 순서대로 정해진 범위에서의 첫번째값, 마지막 값 출력
  • 순서, 정렬, 범위 정의 등에 따라 최솟값과 최댓값 리턴 가능해짐
  • FIRST_VALUE = 1300첫행과 2450 중에 첫번째 값, → 1300 이런식으로 첫행과 현재행까지의 최솟값/최댓값 구할 수 있음

 

  • LAST_VALUE = 처음부터 본인행까지 가장 큰 마지막 값 5000, 1300이랑 2450하면 2450.
    • LAST VALUE에서 내림차순으로 DESC 처음부터 마지막까지 정렬시 최솟값 리턴

 

 

📍NTILE (파티션별 전체건수를 인수값으로 N등분한 결과)

  • 행을 특정 컬럼 순서에 따라서 정해진 수[NTILE(N)]의 그룹으로 나누기 위한 함수
  • 그룹 번호가 리턴됨
  • ❉ EMP라는 테이블을 2개로 나누겠다. SAL 순서대로, 14명이니까 7명씩 분리

 

 

 

📍비율 관련 함수

  • 1) RATIO_TO_REPORT >0, <=1
    • 파티션내 전체 sum에 대한 행별 컬럼 값의 백분율을 소수점으로 구할 수 있다
    • 각 값의 비율을 리턴 (전체 중의 비율 또는 특정 그룹 내 비율)
    • ORDER BY 사용 불가! (그 값 하나에 대한 비율이니까, 굳이?)

  • 2) CUME_DIST : 누적비율 >0, <=1 
    • 현재 행보다 작거나 같은 건수에 대한 누적백분율을 구한다.
    • 각 값의 누적비율을 리턴 (전체 중의 비율 또는 특정 그룹 내 비율)
    • 누적비율은 항상 ORDER BY가 붙음! 필수적으로 (누적비율을 구하는 순서를 정할 수 있음)

 

  • 3) PERCENT_RANK : 분위수 출력 0>=, <=1
    • 전체 카운트 중 상대적 위치 출력 (0~1 범위 내)
    • 파티션 별 윈도우에서 처음 값을 0, 마지막 값을 1로 하여 행의 순서별 백분율을 구한다.
    • ORDER BY 필수

 

 

 

❉ RATIO_TO_REPORT, CUM  E_DIST 비교

- 부서내에서 각 값의 비율

- 누적합

    - SAL 만 오더바이 기준으로 잡을때는 3000값이 같아보이니까 두개 다 1로 잡은 건데, 

    - 결국 오더바이에 SAL, ENAME 두개 다 기준으로 잡을때는 각각 값이 달라지니까 서로 다른 값으로 해석됨 → 각각 누적값 구함

그러니까 RANGE 처리로 똑같이 처리하는데, RANGE를 ROWS로 바꾸는게 아니라 ORDER BY 절을 활용해 각각 누적값 계산하기도!

 

 

❉PERCENT_RANK 예제 : 최솟값을 0으로 최댓값을 1로 만들음

 

 

 

 

 


 

Part5, TOP N QUERY

📍TOP N QUERY

  • 페이징 처리를 효과적으로 수행하기 위해 사용
  • 한페이지를 눌렀을 때 특정 N개의 행을 추출한 목적으로 사용하는 기법
  • 성적 상위자 3명
  • TOP-N 행 추출 방법 : 1️⃣ ROWNUM, 2️⃣ RANK, 3️⃣ FETCH

 

1️⃣ ROWNUM

  • 출력된 데이터 기준으로 행 번호 부여
  • 절대적인 행 번호가 아닌 계속 출력된 결과에 따라 바뀌는 행번호
  • 또다른 순서가 그때그때 반영되니까 이퀄로 특정행을 지칭하기 어려움
  • '>' 연산 사용불가

아무것도 출력 X, 1이 먼저 정의가 되어야 행번호(rownum)가 생기기 때문에
5보다 작거나 같다 해야. 1부터 5까지 출력 가능

 

 

 

  • ex) EMP 테이블에서 급여가 높은 순서대로 상위 5명의 직원 정보 출력
  •  아래 쿼리에서는 ROWNUM 이 있는 WHERE절 먼저 → 그 다음 ORDER BY가 나오기 때문에 그냥 아무 5개나 리턴 된거임

❌❌❌

 

  • 먼저 정렬을 싸악~하고 그 서브쿼리를 가지고 와서 5개만 추출 (rownum이 결정되기 전, 먼저 데이터 정렬 순서를 바꿔놓음)

⭕️⭕️⭕️


 

  • ex) EMP 테이블에서 급여가 높은 순서대로 4~6번째 해당하는 직원 정보 출력
  •  아래 쿼리에서는 시작값이 정의가 안되었고, 1아니고 4먼저 추출하려고 해서 출력 불가능

❌❌❌

 

 

  • ① 인라인 뷰에서 각 행마다 행번호를 직접 부여
  • 일단은 순서대로 나열하고, 거기에 RONUM을 1부터 쪼ㅑ르륵 부여하고 그 다음에 4~6번째만 추출

⭕️⭕️⭕️

 

2️⃣ RANK

  • ② 윈도우함수의 RANK 사용
  • RANK를 사용해서 1부터 쪼ㅑ르르륵 순위를 부여하고, 그 다음에 4등~6등 불러오기

⭕️⭕️⭕️

 

 

3️⃣ FETCH절

  • 출력될 행의 수를 제한하는 줄
  • ORACLE 12C 이상부터 제공, sql-Server 사용 가능
  • ORDER BY 절 뒤에 사용 (내부 파싱 순서도 ORDER BY 뒤)

 

  • OFFSET : 건너뛸 행의 수 → 1명, 1등은 스킵하고 나머지 3명만 리턴하고 싶을 때
  • N : 출력할 행의 수
  • FETCH : 결과적으로 추출하려고 하는 출력할 행의 수를 전달하는 구문
  • FIRST : OFFSET을 쓰지 않았을 때 처음부터 N행 출력 명령
  • NEXT : OFFSET을 사용했으면, 그 제외한 행 다음부터 N행 추출
  • ROW | ROWS : 행의 수에 따라, 하나일 경우 단수, 여러값이면 복수 (특별히 구분 X)

 

  • ex) EMP 테이블에서 SAL 순서대로 상위 5명만 리턴해보자!
  • SAL 큰 순서대로 오더바이 하고, fetch로 5개만 추출해보기

⭕️⭕️⭕️

 

 

  • ex) EMP 테이블에서 급여가 높은 순서대로 4~6번째 해당하는 직원 정보 출력
  • 1,2,3, → 3개를 건너 뛰고 그 다음에 있는 2줄 4등과 5등을 출력해줘라

 

 

 

 

 


 

Part6, 계층형 질의

📍계층형 질의

  • 테이블의 여러개 각 행끼리 관계를 가질 때, 그 연결고리를 파악을 하고 행과 행 사이의 계층 depth를 표현하는 기법
  • DEPT2에서의 부서별 상하관계
  • PRIOR의 위치에 따라 연결하는 데이터가 달라짐

  • START WITH : 데이터를 출력할 시작점을 지정하는 조건, 계층 구조 전개의 시작 위치 지정
  • CONNECT BY : 행을 이어나갈 조건, 다음에 전개될 자식 데이터 지정
  • PRIOR : CONNECT BY 절에 사용되며, 현재 읽은 컬럼을 지정한다.
    • [PRIOR 자식 = 부모 형태] 를 사용하면 계층 구조에서 부모➡️자식 데이터 방향으로 전개하는 순방향 전개

 

 

  • ex) 각 부서의 레벨을 출력, 최상위 부서(사장실)가 1레벨
  • 사장실은 가장 상위부서여서 PDEPT(상위부서번호 컬럼)이 NULL값임 → 이걸 활용해서 PDEPT가 NULL인 사장실 행부터 시작~!
  • PRIOR는 먼저 결정되는 정보 앞, DCODE가 먼저 결정되고 PDEPT 결정되니까. (DECODE가 먼저다! 라는걸 알려줌)
  • 근데? DCODE = PRIOR PEDEPT 이런식으로 잘못 적으면 사장실이 보이긴 하지만, 반대방향으로 가서, 사장님 위에는 뭐가 없으니까 아무것도 출력되지 않는 것

 

 

  • 연결조건 START WITH, CONNECT BY 뒤에는 더 많은 추가 조건이 붙을 수 있다!!!!
  • 여기서의 조건은 WHERE절의 조건이 아니라 부모행과 자식행을 연결하기 위한, 잇기 위한 조건임!!!! [AREA = '서울지사']
    • 사장실 하위지사는 서울, 포항지사로 여러 가지가 있었는데, 그걸 이을때 서울만 잇겠다는 조건

 

 

  • 부서의 상하관계 반영해서 레벨의 수만큼 들여쓰기
  • 가장 최상위 = 뿌리, 루트 노드 // 단말, 끝나는 지점들 = 리프노드

 

 

  • 영업 1팀 기준으로 상위 부서들, 
  • 영업 1팀의 상위부서는, 상위부서코드 PDEPT가 1007인~ 
  • PRIOR이 PDEPT 앞에 붙음

 

 

 

 

📍계층형 질의 가상 칼럼

  • 1) LEVEL : 각각의 행의 depth 를 표현하는 (시작점부터 1)
  • 2) CONNECT_BY_ISLEAF : 해당 데이터가 리프데이터(최하위 노드)면 1, 그렇지 않으면 0

 

📍계층형 질의 가상 함수

  • 1) CONNECT_BY_ROOT 컬럼명 : 이 컬럼에 대한 루트노드 값이 뭐냐, 각각의 행의 depth 를 표현하는 (시작점부터 1)
    • 현재 전개할 데이터의 루트 데이터를 표현한다, 단항 연산자 
    • CONNECT_BY_ROOT DNAME  : 루트노드의 dname 값이 뭐야? 이쪽 뿌리는 자연과학부가 조상이야, 이쪽 뿌리는 컴공이 조상이야.. 알려줌
  • 2) SYS_CONNECT_BY_PATH(컬럼, 구분자) : 연결고리를 이어서 경로 출력하고 싶어짐, 이어질 때 구분자 표시
    • SYS_CONNECT_BY_PATH(DNAME, '-')  : 연결되는 dname의 관계를 하이퍼로 표현해라, 
    • 자연 과학부는 레벨 1이니까 -자연과학부, -자연과학부-수학과, 자연과학부-통계학과 • • • 
  • 3) ORDER SIBLINGS BY 컬럼 : 같은 LEVEL 일 경우 정렬 수행, 형제 노드간의 정렬 수행
    • ODRDER SIBLINGS BY DNAME : 만약에 둘다 레벨이 1로 같으면, 뭘 먼저 나타내고 싶다!

 

 

 

 

 


 

Part6, PIVOT 과 UNPIVOT (데이터의 구조를 변경하는 기능)

📍데이터의 구조

1) LONG DATA (Tidy data)

  • 아래로 추가, 길~게 생겼다, 깔끔하게 생겼다
  • 속성별로 하나의 컬럼으로 구성되는, 값들이 여러 행으로 쌓이는 구조
  • 제 1 정규화를 거치면 그 다른 값을을 가진 하나의 JOB이라는 컬럼을 만들게 됨
  • 다른 테이블과의 조인연산이 가능한 구조
  • RDBMS의 테이블 설계 방식

 

2) WIDE DATA (Cross data)

  • 옆으로 펼쳤다~
  • 행과 컬럼에 유의미한 정보 전달을 목적으로 작성하는 교차표
  • 하나의 속성값이 컬럼을 옆으로 펼쳐 여러 컬럼으로 분리되어 표현
  • RDBMS 에서 WIDE 형식으로 테이블 설계 시 값이 추가될 때마다 컬럼이 추가돼야 하므로 비효율적! (구조변경 잦)
  • 다른 테이블과 조인연산이 불가능함
  • 주로 데이터를 요약할 목적으로 사용

컬럼의 정보 = 부서번호, 하나의 관찰대상을 하나의 컬럼으로 정의하지 않고, 종류별로 컬럼을 분리

 

 

 

📍데이터의 구조 변경

1) PIVOT : LONG ➡️WIDE

  • 부서번호 형태를 오른쪽으로 펼쳤다.

 

2) UNPIVOT : WIDE➡️LONG

  • 옆으로 펼쳐져 있던 월 정보를 중복되더라도 쌓아서, 구매건수라는 새로운 칼럼명 추가해서 값 추가

 

 

 

📍PIVOT

  • 교차표를 만드는 기능 (롱 데이터를 와이드 하게 옆으로 펼친다.)
  • 구매건수라는 데이터를 옆으로 펼치니까
    month 로 고정할컬럼(stack 컬럼), 옆으로 펼칠 컬럼(unstack 컬럼), 안에 채울 값!(value 컬럼)
  • FROM 절에 STACK, UNSTACK, VALUE 컬럼명만 정의, 필요시 서브쿼리 사용해서 필요컬럼 제한★
    • FROM 절에 선언된 컬럼 중 피봇 절에서 선언한 value컬럼, unstack 컬럼을 제외한 모든 컬럼은 stack 컬럼이 됨
  • PIVOT 절에 VALUE, UNSTACK 컬럼명 정의
  • PIVOT 절 IN 연산자에 UNSTACK 컬럼 값을 정의

언스택 컬럼에 IN 조건문 가능!

 

 

 

  • 테이블에서 아래와 같이 JOB별 DEPTNO 별 도수(count) 출력
  • FROM (PIVOT 절에서 언급한 deptno, empno, job 이 3개 컬럼 외에는 프롬절에 있으면 안됨!)
  • PIVOT (어떤 컬럼을 카운트 해서 값으로 채워넣겠다, FOR 가로줄에 분류할 언스택컬럼명 IN (넣고싶은 컬럼명 10,20,30)

 

 

  • 만약에 FROM절에 3개 다 안넣고, JOB을 제외한 2개만 넣는다면,
    직업별로 분리하지 못하고 한줄로 표현하게 됨

 

 

  • 만약에 FROM 절에 서브쿼리로 3개로 제한하지 않고, 모든 테이블을 한번에 다 넣는다면,
    수없이 많은 컬럼들이 다 스택컬럼이 되고, 더 구체적인 도수가 나옴

 

 

 

  • 이미 한번 만들어진 와이드 데이터를 한번 더 피봇하기
  • 성별로 고정(stack 컬럼), 연도컬럼(unstack 컬럼), 구매량의 총합!(value 컬럼)
  • PIVOT (구매량 총합 FOR 연도 IN (2008, 2009))
    ➡️ 성별은 따로 지정안하고, 그냥 프롬절에만 포함해서 잘 쓰면, 알아서 스택으로 고정됨

 

 

 

 

📍UNPIVOT

  • WIDE 데이터를 롱 데이터로 변경하는 문법
  • UNPIVOT 때는 굳이 프롬절을 제한할 필요는 없음 !
  • STACK 컬럼 : 이미 펼쳐져 있는 여러 컬럼을 하나의 컬럼으로 새롭게 만들 이름, 컬럼명
  • VALUE : 값이 채울 때 새롭게 만들 컬럼명
  • 값1, 값2 : 실제 unstack 되어있는 컬럼이름들, 값1, 값2 자리에 명시해서 쌓겠다.

UNPIVOT (CNT FOR 년도 IN ('2008', '2009')) → 컬럼이름은 숫자일 수 없음

 

 

 

  • 컬럼명으로서의 "숫자"는 쌍따옴표로 전달필요하고
  • 문자는 컬럼명은 대문자라서 따옴표 붙으면 안됨

 

 

 

 

 


 

Part8, 정규 표현식

📍정규 표현식

  • 문자열의 공통된 규칙을 보다 일반화 하여 표현하는 방법
  • 정규표현식 사용가능한 문자 함수 제공 (regexp_replace, regexp_substr, regexp_instr,,,)
  • ex) 숫자를 포함하는, 숫자로 시작하는 4자리.., 두번째 자리가 A인 5글자

이 두개의 공통점을 뽑아내면 한번에 추출할 수 있음. 숫자 3개를 연속적으로 포함하고 있음!!!

 

 

  • 데이터 포맷과 관련한 것
    • 소문자 d : Digit 지칭 → 숫자를 표현하는 방법, 숫자 하나
    • 대문자 D : 반대집합, 숫자가 아닌 것
    • s : 공백, S : 공백이 아닌 것
    • w : 숫자, 문자(영어, 한글), _ W : 단어가 아닌 것 (언더바를 제외한 대부분의 특수 기호)
    • ^ 캐럿, 시작되는 것 
      • ^a : a로 시작하는 것
      • 반드시 맨앞에 있어야 함
    • $ : 달러는 맨뒤에 적어야 함
      • a$ : a 로 끝나는
    • • : 엔터를 제외한 모든 
      • .+ : 여러개가 나열된다.는 뜻
    • 원 기호 \ : 지금 규칙으로 나와ㅇ있는걸 뒤에 있는 기호의 의미를 제거하는 것
  • [대괄호] : 대괄호 하나당 한 글자를 의미
    • [ab] : 한글자인데, a 또는 b
    • [^ab] : 뒤에있는걸 제외하겠다. a와 b를 제외한 모든 문자
    • [A-Z] : -은 범위를 의미 → 대문자
    • [A-z] : 대소문자 구분하지 않고 모든 영문자
    • [가-힣] : 한글 표현
  • 반복횟수
    • a+ : a가 여러번 반복된다.
    • a* : 있거나 없거나, 0회 이상 반복
    • a? : 있거나 없거나, 0회에서 1회 반복
    • a{n} : n으로 횟수 지정 가능, a 가 n 회 반복됨
    • a{n1, n2} : a가 n1 반복에서 n2반복 까지 허용
    • a{n,} : 끝이 지정안되고 , 로 끝난 경우는 계~속 반복된다.는 뜻. n회 이상 반복
  • 0 그룹지정
    • \1 : 그룹번호, 1번 그룹에 대한 표현
     

 

tel) 은 무조건 들어가고, 숫자는 다 바뀔 수 있음 한글자에 [0-9] 0에서 9까지 숫자나 하이픈을 넣을 수 있다는 의미에서 [0-9-]
+ 는 위글자가 반복된다
) 이게 있고 없고 일 때는 \) 괄호가 있거나 없거나.

 

 

 

📍1. REGEXP_REPLACE

  • 정규식 표현을 사용한 문자열 치환 가능
  • 대상, 찾을 문자열, [바꿀문자열], [검색위치], [발견횟수], [옵션]
  • 대상에서 찾을 문자열을 찾아서 바꿀 문자열을 바꿔라, 바꿀문자열이 생략되면 그냥 삭제처리할수도
    • 검색위치 : 어디서부터 검색할거냐, 생략시 1로 처리됨 (처음부터 검색하겠다는 뜻)
    • 발견횟수 : 몇번째 발견되는걸 치환할거냐, 생략시 0으로 처리 (모든것들을 다 치환하거나 삭제해줌)
    • 옵션 :
      • c : 대소를 구분해서 검색할거냐
      • i : 대소를 구분하지 않고 검색할거냐
      • m : 패턴을 다중라인으로 선언 가능 (허용할거냐)
       
  • '\d' 숫자 한 자 → ' '지워버려라. 발견횟수 생략했으니까 모든 숫자를 삭제해라
  • [[:digit:]] 역시 숫자를 의미

 

 

  • '\w' : 언더바 제외한 모든 특수기호를 '' 로 replace해라. 즉, 모든 ID에 있는 모든 특수기호 삭제해라
  • 언더바까지 포함한 특수기호를 삭제하고 싶다면 \w|_ ("또는 언더바" 라는 뜻)
  • [[:punct:]] 언더바를 포함한 특수기호 지칭 - 구둣점 문자 [][!#$%&’()*+,./:;<=>?@\^_`{|}~-]

 

  • 대괄호 하나가 한글자니까 [a-z][0-9]이건 두글자. 영어소문자+숫자로 연이은 단어를 지워라.
  • 이와중에 kong-12는 하이픈이 끼어있어서 삭제가 안됨
  • [A-z0-9] 이거는 한글자, 영문이거나 숫자면 다 지워버려 → 하이픈 빼고 다 삭제됨, 이래서 한글자를 주의해야함
  • 삭제할건데, 처음부터 스캔해서 0 모든걸 삭제해라. i는 대소를 구분하지 않고
    • [a-zA-Z][0-9] = [a-z][0-9], '', 1, 0, 'i' 

 

 

 

  • 영문자 한글자, 하이픈, 숫자 이걸 한번에 지우고싶다면?
    • [A-z]-[0-9]
  • 근데 언더바도 같이 OR 기준으로 주고싶다면?, 두가지 조건 넣을 때 소괄호 안에 
    • [A-z](-|_)[0-9]

 

 

 

  • 괄호 안에 있는 그람, 밀리리터, 무게 데이터 한번에 지우고싶다면? → 근데 안에 들어가는 내용이 다양해.
  • . 쩜은 엔터를 제외한 모든 무엇이 와도 상관없음
  • '\(.+\)' : 플러스를 붙여서 1회이상으로 어떤 글자든 몇글자 이상으로 괄호안에 있는 글자를 삭제하자

 

 

 

  • 이름 마스킹 처리할때, 이름 세글자에서 두번째에서 발견된 곳에 마스킹
  • '[[:alpha:]], '' ➡️ 처음부터 발견되면 다 지워버림
  • '[[:alpha:]], '' , 1, 1 ➡️ 첫번째 발견된거 하나를 지우겠다.
  • 대상, 찾을 문자열, [바꿀문자열], [검색위치], [발견횟수], [옵션]
  • '[[:alpha:]], 'x' , 1, 2 ➡️ 처음부터 검색하되, 두번째 발견된 곳에 x로 replace 하겠다.

 

 

 

 

 

📍2. REGEXP_SUBSTR

  • 정규식 표현을 사용한 문자열 추출
  • 추출은 전체 패턴은 정규표현식으로 나타내고, 내가 뽑고싶은 추출그룹을 지정해주면 됨!
  • REGEXP_STR(대상, 패턴, [검색위치], [발견횟수], [옵션], [추출그룹])
    • 검색위치 생략하면 1
    • 몇번째 발견될걸 추출해줄까, 생략되면 1
    • 추출그룹은 서브패턴을 추출 시 그 중 추출할 서브패턴 번호
     

 

    • 지역번호가 다 다르고, 숫자들도 자릿수가 다 다를때 어떻게 지역번호만 추출해올 수 있을까?
    • 우선 d 숫자, 괄호는 두가지 의미가있는데, 진짜 문자열 '('이랑 수식상 묶기위해 필요한 괄호(이건 그냥 괄호 사용)일수도 있음
      • 진짜 문자열 괄호에는 괄호에 \ 붙임 \)
      • \d 숫자+ 여러개반복에 오른쪽 괄호 추가하려면 \) 가 붙음
      • 괄호를 통해서 그룹이 3개가 되는데
      • 자릿수를 채우기 위해 옵션값 null로 채워서
      • 이 TEL이라는 대상에서 다음과 같은 조건의 패턴을 찾아라, 처음부터 검색하고, 하나의 발견된 순간, 옵션은 null, 이고 추출그룹은 첫번째 그룹을 뽑아라!! ➡️ 괄호 이전에 지역번호가 추출됨

 

  • 이메일에서 아이디만 추출하기
  • 이메일 아이디에는 영문자, 숫자, 하이픈과 같은 특수기호 모두 사용가능 ➡️ .+로 처리
  • 그다음은 @ + 영문자 + .영문자(com, net과 같은)
  • 뽑고싶은 아이디"쪽만 괄호로 묶어주고, 뒤에는 그냥 아무거나 와라싶은 마음으로 @ 다음 .+ 처리
  • 처음부터 검색해서, 첫번째로 발견되는 이메일 주소만 가져와, 옵션은 null, 첫번째 서브패턴(그룹)을 가지고 와라!

 

 

📍3. REGEXP_INSTR

  • 정규식 표현을 사용한 문자열의 위치를 추출 (특정패턴의 시작위치를 반환)
  • INSTR은 옵션전달 불가
  • REGEXP_INSTR(원본, 찾을문자열, 시작위치, 발견횟수)
    • 시작위치 생략시 1, 처음부터 값 확인
    • 발견횟수 생략시 처음 발견된 문자열 위치 리턴 
     

 

  • ID에서 숫자하나 한글자만 가져와 '\d', 시작위치는 처음부터 스캔하고, 두번째 발견된! 숫자의 자리의 위치
  • \d+ : 플러스가 붙으면 한글자가 아니라 한 뭉치, 두번째 뭉치를 도출해야함

 

 

 

  • 숫자, 문자열, 공백도 있는 경우
  • [^ ]+ : ^는 제외한, 그 뒤에는 공백이 있으니까 공백을 제외한 것들의 반복은, 공백을 제거한 숫자든 문자든 어떤 단어!
  • 처음부터 검색하되, 두번째 단어를 가져와! → ORACLE 인데
  • 그게 몇번째 글자에서 시작되냐. 5번째!

 

 

 

 

📍4. REGEXP_LIKE

  • 주어진 문자열에서 특정 패턴을 갖는 경우 반환 (WHERE절에서만 사용 가능)
  • REGEXP_LIKE(원본, 찾을 문자열, [옵션])
  • ID 에서 숫자로 끝나는 교수명만 추출해랏!

그냥 조건만 주면 되니까 굳이 전체 식을 정규표현식으로 표현할 필요 없음

 

 

 

📍5. REGEXP_COUNT

  • 주어진 문자열에서 특정 패턴의 횟수를 반환
  • REGEXP_COUNT(원본, 찾을문자열, 시작위치, [옵션])
  • 한글자씩, +를 붙이면 숫자덩어리 ➡️ 각각 카운트값이 다름!