[SQL 첫걸음] 5장 집계와 서브 쿼리

2025. 3. 31. 19:22·도서 공부(정리)/SQL첫걸음

📌 목차

  • 20강. 행 개수 구하기 - COUNT
  • 21강. COUNT 이외의 집계함수
  • 22강. 그룹화 - GROUP BY
  • 23강. 서브쿼리
  • 24강. 상관 서브쿼리

1. 20강 행 개수 구하기 - COUNT

집계 함수

    COUNT [ALL/DISTINCT] (집합)  // 인수로 주어진 집합의 행 개수를 구해 반환

    SUM [ALL/DISTINCT]  (집합)

    AVG [ALL/DISTINCT]  (집합)

    MIN [ALL/DISTINCT]  (집합)

    MAX [ALL/DISTINCT]  (집합)

SQL= 데이터베이스라 불리는 '데이터 집합'을 다루는 언어

집합의 개수, 합계 궁금하다면 SQL이 제공하는 집계함수 사용하여 구하기 가능

SELECT COUNT (*) FROM sample51;
//인수로 지정된 집합 ( 이 경우에는 테이블 전체)
//괄호 안에 지정할 열의 이름을 입력한다

집계함수의 특징 : 복수의 값(집합)에서 하나의 값을 계산 (=집계)

일반적 함수 하나의 행에 하나의 값
집계함수 집합에 하나의 값

더보기

mysql> SELECT COUNT(*) FROM sample51;
+----------+
| COUNT(*) |
+----------+
|        5 |
+----------+
SELECT COUNT (*) FROM sample51 WHERE name = 'A';
//name 열의 값이 A인 것의 집계

결과
count(*)
2

집계함수와 NULL값

COUNT 인수로 열명 지정 가능. *를 인수로 사용할 수 있는 것은 COUNT 함수뿐

집합 안에 NULL이 있을 경우? NULL값을 제외하고 처리함. (무시)

DISTINCT

: 중복된 값을 제거하는 키워드

SELECT [ALL / DISTINCT] name FROM sample51;

ALL 미작성시 자동으로 ALL 선택됨 => name열 쫘르륵 나온다.

중복을 제거한 뒤 개수 구하기

SELECT COUNT(ALL name), COUNT(DISTINCT name) FROM sample51;
// ALL, DISTINCT는 인수가 아니므로 콤마 안붙인다. ALL생략가능. 
// "를 사용한 수식자체를 인수로 지정가능하다.

더보기

mysql> SELECT DISTINCT name FROM sample51;
+------+
| name |
+------+
| A    |
| B    |
| C    |
| NULL |
+------+

mysql> SELECT COUNT(ALL name), COUNT(DISTINCT name) FROM sample51;
+-----------------+----------------------+
| COUNT(ALL name) | COUNT(DISTINCT name) |
+-----------------+----------------------+
|               4 |                    3 |
+-----------------+----------------------+

21강 COUNT 이외의 집계함수

mysql> SELECT * FROM sample51;
+------+------+----------+
| no   | name | quantity |
+------+------+----------+
|    1 | A    |        1 |
|    2 | A    |        2 |
|    3 | B    |       10 |
|    4 | C    |        3 |
|    5 | NULL |     NULL |
+------+------+----------+

SUM으로 합계구하기

mysql> SELECT SUM(quantity) FROM sample51;
+---------------+
| SUM(quantity) |
+---------------+
|            16 |
+---------------+

AVG로 평균내기

mysql> SELECT AVG(quantity), SUM(quantity)/COUNT(quantity) FROM sample51;
+---------------+-------------------------------+
| AVG(quantity) | SUM(quantity)/COUNT(quantity) |
+---------------+-------------------------------+
|        4.0000 |                        4.0000 |
+---------------+-------------------------------+

이때는 NULL의 값을 무시한 상태로 계산한 결과이다.

NULL의 값을 0으로 간주한 후 평균을 내고자한다면 CASE를 사용한다.

mysql> SELECT AVG(CASE WHEN quantity IS NULL THEN 0 ELSE quantity END) AS avgNULLis0 FROM sample51;
+------------+
| avgNULLis0 |
+------------+
|     3.2000 |
+------------+

MIN/ MAX로 최솟값, 최댓값 구하기

22강 그룹화 - GROUP BY

그룹화(GROUP BY) -> 집계함수 활용 범위 넓히기 가능

SELECT * FROM 테이블명 GROUP BY 열1, 열2 ...

집계함수로 넘겨줄 집합을 그룹으로 나눔

GROUP BY 구에 열 지정하여 그룹화하면 지정된 열의 값이 같은 행이 하나의 그룹으로 묶임

(=DISTINCT와 같이 중복을 제거하는 효과가 있음. )

GROUP BY 집계함수와 함께 사용해야만 의미 있음!

그룹화된 그룹이 하나의 집합으로서 집계함수의 인수로 넘겨지기 때문이다. (DISTINCT와의 차이점)

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

mysql> SELECT name, COUNT(name), SUM(quantity) FROM sample51 GROUP BY name;
+------+-------------+---------------+
| name | COUNT(name) | SUM(quantity) |
+------+-------------+---------------+
| A    |           2 |             3 |
| B    |           1 |            10 |
| C    |           1 |             3 |
| NULL |           0 |          NULL |
+------+-------------+---------------+

GROUP BY의 사용 CASE

: 점포 일별 매출 데이터가 중앙 판매 관리시스템에 전송되어 점포별 매출 실적을 집계해 어떤 점포가 매출이 올라가는지, 어떤 상품이 인기가 있는지 등을 분석할 때 사용됨.

점포별, 상품별, 월별, 일별 등 특정 단위로 집계할 때 사용함.

HAVING 구로 조건 지정

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

ex) WHERE COUNT(name)=1 이런거 안돼 xXXX!!!!

내부처리순서

WHERE 구 → GROUP BY 구 → HAVING 구 → SELECT 구 (별명지정)→ ORDER BY 구

HAVING 구

SELECT 명령 중 하나, GROUP BY 구 뒤에 기술함. 조건식이 참인 그룹값만 클라이언트에게 반환함.

결과적으로 검색 시, 2단 구조를 이룸 (WHERE 구, HAVING 구)

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

mysql> SELECT name, COUNT(name) FROM sample51 GROUP BY name HAVING COUNT(name) = 1;
+------+-------------+
| name | COUNT(name) |
+------+-------------+
| B    |           1 |
| C    |           1 |
+------+-------------+

처리순서가 SELECT보다 앞서므로 별명 사용 불가능하다.

GROUP BY에 지정한 열 이외의 열은 집계함수를 사용하지 않은 채 SELECT 구에 지정불가

SELECT 열1, 열2, 열3 FROM 테이블명 GROUP BY 열1; // 열2, 열3 때문에 에러 발생함.

위의 코드에서, 열1는 GROUP BY를 통해 지정됨.

그러나 열2, 열3을 SELECT 구에 그대로 작성시 에러 발생 << 열1 그룹에 대해 열2,열3에서 값이 여러개면 반환 못해!

GROUP BY로 그룹화 시 클라이언트로 반환되는 결과 : 그룹 당 하나의 행만 가능

ㄴ이를 위해, 집계함수를 사용해 집합을 하나의 값으로 계산시켜줌

mysql> SELECT MIN(no),name,SUM(quantity) FROM sample51 GROUP BY name;
+---------+------+---------------+
| MIN(no) | name | SUM(quantity) |
+---------+------+---------------+
|       1 | A    |             3 |
|       3 | B    |            10 |
|       4 | C    |             3 |
|       5 | NULL |          NULL |
+---------+------+---------------+
mysql> SELECT no,quantity From sample51 GROUP BY no, quantity;
// GROUP BY 구에서 지정한 열이라면 SELECT구에서 지정 OK!

GROUP BY로 지정을 통한 순서 정렬 불가 (정렬은 항상 ORDER BY구를 통해)

구/기능 WHERE 구 GROUP BY 구 HAVING 구 SELECT 구 ORDER BY 구
기능 행찾기 열을 그룹화 WHERE의 집계함수사용버전 행 선택 *선택 시 전체 선택 간주 행들 정렬
같이쓰는거 집계함수랑 같이 사용 SUM AVG MIN MAX COUNT 열명 ASC (기본값) 오름차순 DESC 내림차순
비고 DISTINCT랑 유사 w. GROUP BY
mysql> SELECT name, COUNT(name), SUM(quantity) FROM sample51 GROUP BY name ORDER BY SUM(quantity) DESC;
+------+-------------+---------------+
| name | COUNT(name) | SUM(quantity) |
+------+-------------+---------------+
| B    |           1 |            10 |
| A    |           2 |             3 |
| C    |           1 |             3 |
| NULL |           0 |          NULL |
+------+-------------+---------------+

23강 서브쿼리

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

 (SELECT 명령)

서브쿼리는 WHERE 구에서 주로 사용됨

mysql>  DELETE FROM sample54 WHERE a = (SELECT MIN(a) FROM sample54);
ERROR 1093 (HY000): You can't specify target table 'sample54' for update in FROM clause

(MySQL에선 안됨)
위의 에러는 데이터를 추가하거나 갱신할 경우 동일한 테이블을 서브쿼리에서 사용할 수 없도록 되어있기 때문.
=> 해결법 : DELETE 명령을 SELECT 명령으로 바꾸면 됨.

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

...
mysql> SELECT * FROM sample54;
+------+------+
| no   | a    |
+------+------+
|    1 |  100 |
|    2 |  900 |
|    4 |   80 |
+------+------+

SQL 에는 순차형 언어에서처럼 변수가 존재하지 않으나, 변수를 사용할 수는 있음.

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

MYSQL 예시
mysql> set @a = SELECT(MIN (a) FROM sample54);
mysql> DELETE FROM Sample54 WHERE a = @a // @a가 변수이다.

서브쿼리의 패턴

1) 하나의 값 을 반환하는 패턴 = 스칼라 값, (많이 사용한다.)

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

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

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

=연산자를 사용하여 비교할 경우에는 스칼라 값끼리 비교할 필요가 있다.

스칼라 값을 반환하는 서브쿼리 = 스칼라 서브쿼리

WHERE 구에 스칼라 서브쿼리 사용 가능, 즉 집계함수를 사용해 집계한 결과를 조건식으로 사용 가능하다.

#SELECT 구에서 서브쿼리 사용하기

상부 SELECT구에는 FROM 구가 없음. (MySQL) ,

Oracle같은 전통적인 데이터베이스 제품에는 FROM생략 불가하므로, FROM DUAL로 지정해서 실행한다.

mysql> SELECT
    -> (SELECT COUNT(*) FROM sample51) AS sq1,
    -> (SELECT COUNT(*) FROM sample54) AS sq2;
+------+------+
| sq1  | sq2  |
+------+------+
|    5 |    3 |
+------+------+

UPDATE의 SET구에서 서브쿼리 사용

UPDATE sample54 SET a = (SELECT MAX(a) FROM sample54);
ERROR 1093 (HY000): You can't specify target table 'sample54' for update in FROM clause // 오류발생

https://dev.mysql.com/doc/refman/8.4/en/subquery-errors.html

서브쿼리 에러관련 확인

- This error occurs in cases such as the following, which attempts to modify a table and select from the same table in the subquery:

UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);

즉, 같은테이블을 선택해서 수정해서그런듯?

위의 에러는 데이터를 추가하거나 갱신할 경우 동일한 테이블을 서브쿼리에서 사용할 수 없도록 되어있기 때문.

: MySQL에서만 안되는거

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

구 SELECT 구 SET 구 FROM 구
지정 스칼라 서브쿼리 스칼라값아니어도 ok
mysql> SELECT * FROM (SELECT * FROM sample54)sq; // sq는 테이블의 별명
+------+------+
| no   | a    |
+------+------+
|    1 |  100 |
|    2 |  900 |
|    4 |   80 |

//3장내용
// SELECT구에서 열이나 식에 별명 붙일 수 있다. FROM구에서는 테이블/서브쿼리에 별명 가능

네스티드 구조(nested), 중첩구조, 내포구조

SELECT명령 안에 SELECT 명령이 들어 있는 듯 보인다.

이러한 구조는 몇단계로든 구성 가능

예제 5-26 Oracle에서 LIMIT 구의 대체 명령

더보기

 SELECT * FROM(
     SELECT * FROM sample54 ORDER BY a DESC
     )sq
     WHERE ROWNUM <=2;

INSERT명령과 서브쿼리

INSERT 명령

1. VALUES 구의 일부로 서브쿼리 사용 (스칼라값만)

2. VALUES구 대신 SELECT 명령을 사용

mysql> INSERT INTO sample541 VALUES(
    -> (SELECT COUNT(*) FROM SAMPLE51),
    -> (SELECT COUNT(*) FROM SAMPLE54)
    -> );
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM sample541;
+------+------+
| a    | b    |
+------+------+
|    5 |    3 |
+------+------+
1 row in set (0.00 sec)

values 구 대신에 SELECT사용

mysql> INSERT INTO sample541 SELECT 1,2;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM sample541;
+------+------+
| a    | b    |
+------+------+
|    5 |    3 |
|    1 |    2 |
+------+------+
2 rows in set (0.00 sec)

= INSERT INTO sample541 VALUES(1, 2)

INSERT SELECT명령

SELECT명령의 결과를 모두 INSERT INTO의 테이블로 전부추가

결과를 클라이언트로 반환하지 않고, 추가만함. ← 데이터 복사, 이동에 자주 사용

24강 상관 서브쿼리

EXISTS 술어로 상관서브쿼리를 조합시키기

EXISTS : 서브쿼리가 반환하는 결괏값이 존재하는가를 조사 (스칼라외의것도 모두), 참 거짓을 반환한다.

EXISTS (SELECT 명령)
mysql> UPDATE sample551 SET a='YES' WHERE EXISTS(SELECT * FROM sample552 WHERE no2 = no);
Query OK, 2 rows affected (0.01 sec)
Rows matched: 2  Changed: 2  Warnings: 0

mysql> SELECT * FROM sample551;
+------+------+
| no   | a    |
+------+------+
|    1 | NULL |
|    2 | NULL |
|    3 | YES  |
|    4 | NULL |
|    5 | YES  |
+------+------+
5 rows in set (0.00 sec)

EXISTS 술어에서 서브쿼리 지정하면, 행을 반환할 경우(한 행, 여러 행 무관, 존재자체!)에 참을 돌려줌.

부모자식관계

NOT EXISTS

mysql> UPDATE sample551 SET a = 'NO' WHERE NOT EXISTS(SELECT * FROM sample552 WHERE no2 = no);
// sample551.no = sample552.no2 로 써도 작동함

Query OK, 3 rows affected (0.01 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> SELECT * FROM sample551;
+------+------+
| no   | a    |
+------+------+
|    1 | NO   |
|    2 | NO   |
|    3 | YES  |
|    4 | NO   |
|    5 | YES  |
+------+------+
5 rows in set (0.00 sec)

행이 존재하지 않는 경우, 참으로 반환

상관서브쿼리

중첩구조 SELECT명령에서

UPDATE(부모)

(SELECT ~~) (자식)

상관 서브쿼리 : 부모자식 관계를 가지는 것

이때, 23강의 DELETE는 상관 서브쿼리가 아님. 단순한 서브쿼리로, 단독 쿼리로 실행 가능하다. (mysql에서안댐)

상관 서브쿼리에서 부모 명령과 연관되어 처리된다. → 서브쿼리 부분만 따로 떼어내 실행 불가

열에 테이블명 붙이기

sample551.no 가능

만일 샘플의 열이 같다면 혼선 생길 것을 우려해 테이블명.열명을 알려준다. sample551.no = sample552.no2

집합을 비교할 때

=(등호) 사용 불가능.... IN을 사용 시, 집합 안의 값 존재 여부 판별 가능

특정 열의 값이 'n OR n' 라는 조건식을 지정하는 경우 사용

열명 IN (집합)

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

mysql> SELECT * FROM sample551 WHERE no IN (3,5);
+------+------+
| no   | a    |
+------+------+
|    3 | YES  |
|    5 | YES  |
+------+------+
2 rows in set (0.00 sec)

no이 3, 5인 행 찾기 //

더보기

mysql> SELECT * FROM sample551 WHERE no IN (SELECT no2 FROM sample552);
+------+------+
| no   | a    |
+------+------+
|    3 | YES  |
|    5 | YES  |
+------+------+
2 rows in set (0.00 sec)

집합부분을 서브쿼리로 지정함. 스칼라서브쿼리 될 필요 없음. //스칼라는 SELECT, SET에서만

NOT IN 은 반대

NULL값이 있을경우

집계함수에서는 무시처리

IN에서는 무시 X, but 비교할 수가 없음... 즉, IS NULL사용해야한다.

NOT IN 사용 시, 집합 안에 NULL 있으면, 왼쪽 값이 집합 안에 포함되어있지않더라도 참 반환 X , 결과 = 불명(KNOWN)

MySQL

조건식 IN사용시 , 왼쪽 값 집합에 포함/미포함 => 참 / NULL 반환

NOT IN, 왼쪽 값 집합에 포함/미포함 => 거짓/NULL 반환, 결국 집합에 NULL 포함되어 있으면 결과값0, 항상 NULL 반환

===========================

'도서 공부(정리) > SQL첫걸음' 카테고리의 다른 글

<SQL첫걸음> 7장 복수의 테이블다루기  (0) 2025.04.08
[SQL 첫걸음] 6장 데이터베이스 객체 작성과 삭제  (0) 2025.04.06
[SQL첫걸음] 4장 데이터의 추가, 삭제, 갱신  (0) 2025.03.30
[SQL첫걸음 ] 3장 정렬과 연산  (0) 2025.03.30
[SQL 첫걸음] 2장 테이블에서 데이터 검색  (0) 2025.03.23
'도서 공부(정리)/SQL첫걸음' 카테고리의 다른 글
  • <SQL첫걸음> 7장 복수의 테이블다루기
  • [SQL 첫걸음] 6장 데이터베이스 객체 작성과 삭제
  • [SQL첫걸음] 4장 데이터의 추가, 삭제, 갱신
  • [SQL첫걸음 ] 3장 정렬과 연산
sihyes
sihyes
24학번 컴퓨터공학과
  • sihyes
    시혜적으로개발
    sihyes
  • 글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기 (114)
      • 단순 설정 (10)
      • 백엔드 공부(BE, AWS) (8)
        • 로그인&회원가입 (3)
        • 파일업로드&GPT (2)
      • 컴퓨터공학과 (51)
        • 운영체제 (0)
        • Artificial Intelligence (0)
        • Java 1 & 2 (23)
        • 컴퓨터네트워크 (3)
        • 모앱JavaScript (0)
        • Data structures (9)
        • 소프트웨어공학 (5)
        • 오픈SW플랫폼 제출용 (5)
        • Python - 문해프 (1)
      • 개인 프로젝트 (2)
        • 알바솔로몬 (1)
        • PLACO 프로젝트 (0)
      • 도서 공부(정리) (20)
        • 알고리즘 코딩 테스트 자바 편 (1)
        • SQL첫걸음 (8)
        • 코딩 자율학습 스프링 부트 3 자바 백엔드 개발 .. (6)
        • Do it! 지옥에서 온 문서 관리자 깃&깃허브 .. (5)
      • 개인공부정리페이지 (12)
        • 백준 & 프로그래머스 (3)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    ㅇ
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.4
sihyes
[SQL 첫걸음] 5장 집계와 서브 쿼리
상단으로

티스토리툴바