[SQL] JOIN, GROUP BY, HAVING

JOIN, GROUP BY, HAVING에 대해서 알아보자 :)

Apr 8, 2024
[SQL] JOIN, GROUP BY, HAVING

1. JOIN이란?

📌
기본 구성
SELECT <열 이름>
FROM <첫 번째 테이블>
JOIN <두 번째 테이블>
ON <조인 조건>
….

1-1. JOIN에 대하여

1-1-1. JOIN의 정의

데이터베이스에서 ‘두 개 이상의 테이블’을 연결하여 ‘하나의 결과의 테이블’로 만드는 것을 의미하며, 이를 통해 데이터를 효율적으로 검색하고 처리하는데 도움을 준다.

1-1-2. JOIN을 사용하는 이유

데이터베이스에서 테이블을 분리하여 ‘데이터 중복을 최소화’하고 ‘데이터의 일관성’을 유지하기 위함입니다.

1-2. JOIN의 종류

1-2-1. INNER JOIN (내부 조인)

두 테이블을 조인할 때, , 두 테이블에 모두 지정한 열의 데이터가 있어야 한다.
notion image
SELECT <열 이름>
FROM <첫 번째 테이블>
JOIN <두 번째 테이블>
ON <조인 조건>
SELECT <열 이름>
FROM <첫 번째 테이블>
INNER JOIN <두 번째 테이블>
ON <조인 조건>

1-2-2. OUTER JOIN (외부 조인)

두 테이블을 조인할 때, 1개의 테이블에만 데이터가 있어도 결과가 나온다.
notion image
notion image
notion image
SELECT <열 이름>
FROM <첫 번째 테이블>
(LEFT | RIGHT | FULL) OUTER JOIN <두 번째 테이블>
ON <조인 조건>

1-2-3. CROSS JOIN (상호 조인)

한쪽 테이블의 모든 행과 다른 쪽 테이블의 모든 행을 조인하는 기능이다.
상호 조인 결과의 전체 행 개수는, 두 테이블의 각 행의 개수를 곱한 수!
SELECT *
FROM <첫 번째 테이블>
CROSS JOIN <두 번째 테이블>

1-2-4. SELF JOIN (자체 조인)

자신이 자신과 조인한다는 의미로, 1개의 테이블을 사용한다.
SELECT <열 이름>
FROM <테이블> 별칭 A
INNER JOIN <테이블> 별칭 B

2. GROUP BY란?

📌
기본 구성
SELECT <열 이름>
FROM <첫 번째 테이블>
WHERE <조건>
GROUP BY <열 이름>

2-1. GROUP BY에 대하여

2-1-1. GROUP BY의 정의

데이터베이스에서 같은 값을 가진 행을 그룹지어 ‘하나의 그룹’을 만드는 것을 의미한다.

2-1-2. GROUP BY의 특징

  • GROUP BY절은 각 그룹의 하나만을 리턴한다.
  • GROUP BY는 일반적으로 WHERE절 뒤에 위치한다.
  • GROUP BY는 COUNT(), MAX(), MIN(), SUM(), AVG() 등 집계 함수와 함께 사용된다.
SELECT 문에 있는 모든 열은 집계 함수가 되거나 GROUP BY 절에 나타나야 한다. GROUP BY 절을 사용하는데 만약 SELECT 문에 집계 함수를 사용하지 않거나 GROUP BY 절에 언급되지 않은 열이 존재한다면 오류가 발생한다.
  1. COUNT() : 행의 개수
  1. AVG() : 행 안에 있는 값의 평균
  1. MIN() : 행 안에 있는 값의 최솟값
  1. MAX() : 행 안에 있는 값의 최댓값
  1. SUM() : 행 안에 있는 값의 합

3. HAVING이란?

📌
기본 구성
SELECT <열 이름>
FROM <첫 번째 테이블>
WHERE <조건>
GROUP BY <열 이름>
HAVING <조건>

3-1. HAVING에 대하여

3-1-1. HAVING의 정의

데이터베이스에서 WHERE 절과 비슷하지만 GROUP BY에서 사용하는 조건 구문을 의미한다.

3-1-2. HAVING의 특징

  • GROUP BY 절에 의한 소그룹별로 만들어진 집계 데이터 중, HAVING 절에서 제한 조건을 두어 조건을 만족하는 내용만 출력한다.
  • HAVING 절은 일반적으로 GROUP BY 절 뒤에 위치한다.

3-2. WHERE vs. HAVING

📌
WHERE
  • 개별 행에 적용됨. (행을 필터링 하는데 사용됨.)
  • HAVING 절에 포함된 하위 커리에 있지 않으면 집계 함수와 함께 사용할 수 없다.
  • GROUP BY 절 앞에 사용한다.
“그룹화 또는 집계가 발생하기 전에 레코드를 필터링하는데 사용된다.”
📌
HAVING
  • 그룹을 나타내는 결과 집합의 행에만 적용됨. (그룹을 필터링 하는데 사용됨.)
  • 집계 함수는 HAVING 절과 함께 사용할 수 있다.
  • GROUP BY 절 뒤에 사용한다.
“그룹화 또는 집계가 발생한 후에 레코드를 필터링하는데 사용된다.”

4. 프로그래머스 SQL

4-1. 풀면서 궁금했던 문제들

4-1-1. 대여횟수가 많은 자동차들의 월별 대여 횟수 구하기

# 오답 SELECT MONTH(START_DATE) AS MONTH, CAR_ID, COUNT(HISTORY_ID) AS RECORDS FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31' AND CAR_ID IN (SELECT CAR_ID FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY GROUP BY CAR_ID HAVING COUNT(CAR_ID) >= 5) GROUP BY MONTH, CAR_ID ORDER BY MONTH ASC, CAR_ID DESC;
구글링 해 본 결과, 서브쿼리 내에도 날짜 조건을 적어줘야하는데, 왜 적어야 하는지 모르겠음,,
SELECT CAR_ID FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY GROUP BY CAR_ID HAVING COUNT(CAR_ID) >= 5);
 
notion image
해당 코드 결과가 오른쪽 사진!
이대로 서브쿼리를 작성한다면, 결과적으로 기간 외 대여한 자동차들에 대해서도 결과가 나오지 않을까…? 하는 조심스런 생각,,
# 정답 SELECT MONTH(START_DATE) AS MONTH, CAR_ID, COUNT(HISTORY_ID) AS RECORDS FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31' AND CAR_ID IN (SELECT CAR_ID FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31' GROUP BY CAR_ID HAVING COUNT(CAR_ID) >= 5) GROUP BY MONTH, CAR_ID ORDER BY MONTH ASC, CAR_ID DESC;

4-1-2. 입양 시각 구하기 (1)

SELECT HOUR(DATETIME) as HOUR, COUNT(ANIMAL_ID) AS COUNT FROM ANIMAL_OUTS WHERE HOUR(DATETIME) BETWEEN 9 AND 19 GROUP BY HOUR(DATETIME) ORDER BY HOUR;
COUNT를 ANIMAL_ID로 하는게 맞는지? ANIMAL_ID 결과 출력해보니 맞는듯…?!

별첨

WHERE 1=1 사용 이유는?
  • 주로 동적 쿼리를 작성할 때 사용된다. 동적 쿼리는 사용자가 선택한 조건에 따라 쿼리의 WHERE 절을 동적으로 생성하는 것을 의미한다.
  • WHERE 1=1을 사용하면 이후에 추가될 조건들을 AND나 OR로 간단하게 연결할 수 있다. 또한, WHERE 절에 조건이 없는 경우 WHERE 1=1을 사용하면 전체 데이터를 가져올 수 있다.