백엔드/SQL 첫걸음

5장 집계와 서브쿼리

dlng23 2024. 10. 11. 22:46

20강. 행 개수 구하기 - COUNT

대표적인 집계함수

COUNT(집합)
SUM(집합)
AVG(집합)
MIN(집합)
MAX(집합)

 

1. COUNT로 행 개수 구하기

집계함수(집합함수)는 인수로 집합을 지정함, 집합을 특정 방법으로 계산하여 그 결과를 반환

 

COUNT 함수 : 인수로 주어진 집합의 '개수'를 구해 반환

<예제 5-1> sample51의 행 개수 구하기

COUNT 함수를 사용하여 sample51 테이블의 행 개수를 구함

 

인수로 지정되어 있는 *  는 SELECT 구에서 '모든 열'을 나타낼 때 사용하는 메타문자와 같음

COUNT 집계함수에서는 '모든 열 = 테이블 전체'라는 의미로 사용됨

COUNT는 인수로 지정된 집합의 개수를 계산

 

집계함수의 특징

복수의 값(집합)에서 하나의 값을 계산해냄

일반적인 함수는 하나의 행에 대하여 하나의 값을 반환하지만, 집계함수는 집합으로부터 하나의 값을 반환

 

'집계' : 집합으로부터 하나의 값을 계산하는 것

 

- WHERE 구 지정하기

<예제 5-2> sample51의 행 개수를 WHERE 구를 지정하여 구하기

SELECT 구는 WHERE 구보다 나중에 내부적으로 처리됨

WHERE 구로 조건을 지정하면 테이블 전체가 아닌, 검색된 행이 COUNT로 넘겨짐

① WHERE로 행 검색 → ② COUNT로 행의 개수를 집계

 

 

2. 집계함수와 NULL값

COUNT의 인수로 열명을 지정할 수 있음

열명을 지정하면 그 열에 한해 행의 개수를 구함

*를 인수로 사용할 수 있는 것은 COUNT 함수 뿐 (다른 집계함수에서는 열명이나 식을 인수로 지정)

 

집계함수는 집합 안에 NULL 값이 있을 경우 이를 제외하고 처리

<예제 5-3> 행 개수를 구할 때 NULL 값 다루기

no 열의 행 개수는 5, name 열의 행 개수는 4로 나타남

→ name 열에는 NULL 값을 가지는 행이 하나 존재하므로 이를 제외한 개수 4가 됨

 다만, COUNT(*)의 경우 모든 열의 행 수를 카운트하기때문에 NULL 값이 있어도 해당 정보가 무시되지 않고 5가 됨

 

3. DISTINCT로 중복 제거

집합 안에 중복된 값이 있는지 여부가 문제될 때도 있음

sample 51의 no 열은 1, 2, 3...과 같이 일련의 숫자로 되어 있어 중복X, name 열의 값은 맨 위 두 줄이 A로 중복됨

DISTINCT : 중복된 값을 제거하는 함수 를 사용할 수 있음

<예제 5-5> DISTINCT로 중복 제거하기

 

DISTINCT는 예약어

ALL 은 중복 유무와 관계없이 문자 그대로 모든 행을 반환

ALL과 DISTINCT 둘 다 사용하지 않고 생략할 경우, ALL로 간주

 

4. 집계함수에서 DISTINCT

NULL 값을 제외하고, 중복하지 않는 데이터의 개수를 구하려고 함

→ 집계함수의 인수로 DISTINCT를 사용할 수 있음

<예제 5-6> 중복을 제거한 뒤 개수 구하기

 

 

21강. COUNT 이외의 집계함수

1. SUM으로 합계 구하기

SUM 집계함수를 사용해 집합의 합계를 구할 수 있음

<예제 5-7> SUM으로 합계 구하기

SUM 집계함수에 지정되는 집합은 수치형 뿐

문자열형이나 날짜시간형의 집합에서 합계 구할 수 없음

SUM 집계함수도 NULL 값을 무시 (NULL값을 제거한 뒤 합계를 구함)

 

2. AVG로 평균내기

합한 값을 개수로 나누어 평균값을 구할 수 있음

AVG = SUM / COUNT

AVG 집계함수에 지정되는 집합은 수치형만 가능

<예제 5-8> AVG로 평균값 구하기

AVG 함수도 NULL 값 무시 

NULL 값을 0으로 간주해서 평균을 내고 싶은 경우에는 CASE를 사용하여 NULL 값을 0으로 변환한 뒤 AVG 함수로 계산

 

3. MIN • MAX로 최소값 • 최댓값 구하기

MIN 집계함수, MAX 집계함수 를 사용하여 집합에서 최솟값과 최댓값을 구할 수 있음

이 함수들은 문자열형과 날짜열형에도 사용 가능

NULL 값은 무시

<예제 5-10> MIN, MAX로 최솟값, 최대값 구하기

 

 

22강. 그룹화 - GROUP BY

1. GROUP BY로 그룹화

GROUP BY 구를 사용해 집계함수로 넘겨줄 집합을 그룹으로 나눔

<예제 5-12> name 열로 그룹화하기

GROUP BY 구에 그룹화할 열을 name 으로 지정

지정된 열의 값이 같은 행이 하나의 그룹으로 묶임

SELECT 구에서 name 열을 지정하였기때문에 그룹화된 name 열의 데이터가 클라이언트로 반환됨

GROUP BY 구로 그룹화된 각각의 그룹이 하나의 집합으로서 집계함수의 인수로 넘겨짐

 

<예제 5-13> name 열을 그룹화해 계산하기

GROUP BY name에 의해 name 열 값이 A, B, C, NULL의 네 개 그룹으로 나뉨

A 그룹에는 두 개의 행이 있는데,  COUNT는 행의 개수를 반환하므로 2

A 그룹에 해당하는 quantity 값은 1, 2 이므로 SUM 값으로 3 반환

 

2. HAVING 구로 조건 지정

집계함수는 WHERE 구의 조건식에서는 사용할 수 없음

WHERE 구로 행을 검색하는 처리가 GROUP BY로 그룹화하는 처리보다 순서상 앞서있음

 

 

HAVING 구를 사용하면 집계함수를 사용해서 조건식을 지정할 수 있음

HAVING 구는 GROUP BY 구의 뒤에 기술

 

<예제 5-14> HAVING을 사용해 검색

 

내부처리 순서

WHERE 구 → GROUP BY 구 → HAVING 구 → SELECT 구 → ORDER BY 구

 

3. 복수열의 그룹화

GROUP BY에 지정한 열 이외의 열은 집계함수를 사용하지 않은 채 SELECT 구에 기술해서는 안 됨

SELECT no, name, quantity FROM sample51 GROUP BY name;

name은 GROUP BY에서 지정하므로 OK, no와 quantity는 X

 

집계함수를 사용하면 하나의 값으로 계산되므로 아래와 같이 작성하면 문제 X

SELECT MIN(no), name, SUM(quantity) FROM sample51 GROUP BY name;

 

no와 quantity로 그룹화하면 SELECT 구에 지정해도 OK

SELECT no, quantity FROM sample51 GROUP BY no, quantity;

 

4. 결괏값 정렬

ORDER BY 구를 사용해 결과를 순서대로 정렬할 수 있음

<예제 5-15> 집계한 결과 정렬하기

내림차순: DESC / 오름차순(default): ASC

 

 

23강. 서브쿼리

서브쿼리 : SELECT 명령에 의한 데이터 질의로, 상부가 아닌 하부의 부수적인 질의

1. DELETE의 WHERE 구에서 서브쿼리 사용하기

ex)

<예제 5-16> sample54 테이블

sample54 테이블에서 a 열 값이 가장 작은 행을 삭제하려 함

 

a 열의 값이 가장 작은 행이 어느 것인지 파악할 수 없는 경우에는 SELECT 명령으로 검색할 것임

<예제 5-17> sample54에서 a의 최솟값 검색하기

이 SELECT 명령을 DELETE 명령의 WHERE 구에서 사용하면 하나의 DELETE 명령으로 원하는 행을 삭제할 수 있음

DELETE FROM sample54 WHERE a = (SELECT MIN(a) FROM sample54);

 

서브쿼리를 사용하여 DELETE와 SELECT 결합

 

2. 스칼라 값

서브쿼리의 패턴

하나의 값을 반환하는 패턴

ex)

 

② 복수의 행이 반환되지만 열은 하나인 패턴

ex)

③ 하나의 행이 반환되지만 열이 복수인 패턴

ex)

 

④ 복수의 행, 복수의 열이 반환되는 패턴

ex)

 

패턴 만 하나의 값을 반환 → '단일 값', '스칼라 값' 을 반환

 

스칼라 값을 반환하는 SELECT 명령은 서브쿼리로서 사용하기 쉬움

WHERE 구에서 스칼라 값을 반환하는 서브쿼리는 = 연사자로 비교할 수 있음

 

3. SELECT 구에서 서브쿼리 사용하기

문법적으로 서브쿼리는 '하나의 항목'으로 취급

서브쿼리를 사용할 때는 스칼라 서브쿼리로 되어있는지 확인해야 함

SELECT
	(SELECT COUNT(*) FROM 테이블명1) AS sq1,
	(SELECT COUNT(*) FROM 테이블명2) AS sq2;

 

4. SET 구에서 서브쿼리 사용하기

ex) UPDATE sample54 SET a = (SELECT MAX(a) FROM sample54);

 

5. FROM 구에서 서브쿼리 사용하기

FROM 구에서는 스칼라 서브쿼리를 지정하지 않아도 괜찮음

 

<예제 5-23> FROM 구에서 서브쿼리 사용하기

SELECT 명령 안에 SELECT 명령이 들어있는 것처럼 보임 → '네스티드(nested) 구조', '중첩구조', '내포구조' 라고 부름

테이블이나 서브쿼리에 별명을 붙일 수 있음

'AS' 키워드를 사용해서 지정 (Oracle 에서는 AS 붙이면 에러 발생)

 

중첩 구조는 몇 단계로든 상관X

 

6. INSERT 명령과 서브쿼리

INSERT 명령과 서브쿼리를 조합해 사용할 수 있음

 

① VALUES 구의 일부로 서브쿼리를 사용하는 경우

서브쿼리는 스칼라 서브쿼리로 지정해야 하며, 자료형 일치해야 함

<예제 5-27> VALUES 구에서 서브쿼리 사용하기

 

② VALUES 구 대신 SELECT 명령을 사용하는 경우

<예제 5-28> SELECT 결과를 INSERT하기

'INSERT SELECT' 라 불리는 명령으로 INSERT와 SELECT를 합친 것과 같은 명령이 됨

SELECT 명령이 반환하는 값이 스칼라 값일 필요X

SELECT가 반환하는 열 수와 자료형이 INSERT할 테이블과 일치하면 됨

 

24강. 상관 서브쿼리

EXISTS (SELECT명령)

EXISTS 술어를 사용하면 서브쿼리가 반환하는 결과값이 있는지 조사할 수 있음

값이 있으면 참, 없으면 거짓을 반환

 

1. EXISTS

EXISTS 술어를 사용해 데이터가 존재하는지 아닌지 판별할 수 있음

<예제 5-30> sample551 테이블과 sample552 테이블
<얘재 5-31> EXISTS를 사용해 '있음'으로 갱신하기

sample 552에 no열의 값과 같은 행이 있으면 '있음' 이라는 값으로, 행이 없으면 '없음'이라는 값으로 갱신함

EXISTS 술어를 사용하여 서브쿼리가 행을 반환할 경우에 참을 돌려줌

 

2. NOT EXISTS

NOT EXISTS 를 사용하여 행이 존재하지 않는 상태가 참이 되게 함

<예제 5-32> NOT EXISTS를 사용해 '없음'으로 갱신하기

 

3. 상관 서브쿼리

UPDATE sample551 SET a = '있음' WHERE
	EXISTS (SELECT * FROM sample552 WEHRE no2 = no);

UPDATE 명령 부모 / WHERE 구에 괄호로 묶은 부분, 서브쿼리   자식

부모 명령에서는 sample551 갱신

자식인 서브쿼리에서는 sample552 테이블의 no2 열 값이 부모의 no 열 값과 일치하는 행을 검색

부모 명령과 자식인 서브쿼리가 특정 관계를 맺는 것 '상관 서브쿼리'

 

상관 서브쿼리가 아닌 서브쿼리는 단독 쿼리로 실행할 수 O

상관 서브쿼리에서는 부모 명령과 연관되어 처리되기 때문에 서브쿼리 부분만 따로 떼어내어 실행 시킬 수 X

 

- 테이블명 붙이기

 위의 예제에서 sample551의 열과 sample552의 열이 no, no2로 다르기때문에 제대로 동작했으나

만약 같은 경우 WHERE no=no 가 되면 제대로 동작하지 않음

 

이런 경우, 정상적으로 처리하기 위해 열이 어느 테이블의 것인지 명시적으로 나타내야 함

열명 앞에 '테이블명.'을 붙이면 됨

 

ex)

UPDATE sample551 SET a = '있음' WHERE
	EXISTS (SELECT * FROM sample552 WHERE sample552.no2 = sample551.no);

 

4. IN

스칼라 값끼리 비교할 때는 = 연산자 사용하지만, 집합을 비교할 때는 사용 x

IN을 사용하면 집합 안의 값이 존재하는지 조사할 수 있음

서브쿼리를 사용할 때 IN을 통해 비교

 

열명 IN(집합)

IN에서는 오른쪽에 집합을 지정

왼쪽에 지정된 값과 같은 값이 집합 안에 존재하면 참 반환

집합은 상수 리스트를 괄호로 묶어 기술

 

<예제 5-34> IN을 사용해 조건식 기술

 

 

집합 부분은 서브쿼리로도 지정할 수 있음

<예제 5-35> IN의 오른쪽을 서브쿼리로 지정하기

서브쿼리는 스칼라 서브쿼리일 필요 X

 

NOT IN으로 지정하면 집합에 값이 포함되어 있지 않을 경우 참

 

- IN과 NULL

IN에서는 집합 안에 NULL 값이 있어도 무시하지X

다만, IN을 사용해도 NULL 값은 비교할 수 없음

IS NULL을 사용해야 함

NOT IN의 경우, NULL 값이 있으면 참을 반환하지X, '불명(UNKNOWN)'이 됨