SQL(4)(group by, having, case, distinct, join)

GROUP BY

데이터를 그룹으로 분리하여 서로 독립적으로 집계할 수 있다.

1
2
3
4
SELECT year,
       COUNT(*) AS count
  FROM tutorial.aapl_historical_stock_price
 GROUP BY year
cs












1
2
3
4
5
SELECT year,
       month,
       COUNT(*) AS count
  FROM tutorial.aapl_historical_stock_price
 GROUP BY year, month
cs

여러 열로 그룹화 할 수 있지만 위와 같이 쉼표로 열 이름을 구분해야한다.









연습문제

매일 거래되는 총 주식 수를 계산하고, 결과를 시간순으로 정렬하십시오.

1
2
3
4
5
6
SELECT year,
       month,
       SUM(volume) AS volume_sum
  FROM tutorial.aapl_historical_stock_price
 GROUP BY year, month
 ORDER BY year, month
cs










열번호

열 이름을 숫자로 대체할 수 있다. 

1
2
3
4
5
SELECT year,
       month,
       COUNT(*) AS count
  FROM tutorial.aapl_historical_stock_price
 GROUP BY 12
cs









ORDER BY와 함께 사용

1
2
3
4
5
6
SELECT year,
       month,
       COUNT(*) AS count
  FROM tutorial.aapl_historical_stock_price
 GROUP BY year, month
 ORDER BY month, year
cs









연습문제

연도별로 그룹화 된 Apple 주식의 일일 평균 가격 변동을 계산하는 쿼리

1
2
3
4
5
SELECT year,
       AVG(close - open) AS avg_daily_change
  FROM tutorial.aapl_historical_stock_price
 GROUP BY year
 ORDER BY year
cs












Apple 주식이 매달 달성한 최저 및 최고 가격을 계산하는 쿼리

1
2
3
4
5
6
7
SELECT year,
      month,
      min(low) as low,
      max(high) as high
  FROM tutorial.aapl_historical_stock_price
 GROUP BY year, month
 ORDER BY year, month
cs








HAVING

where절은 집계 열을 필터링 할 수 없기 때문에 having절을 사용한다.

1
2
3
4
5
6
7
SELECT year,
       month,
       MAX(high) AS month_high
  FROM tutorial.aapl_historical_stock_price
 GROUP BY year, month
HAVING MAX(high) > 400
 ORDER BY year, month
cs










쿼리 절 순서

절을 작성하는 순서가 중요하다. 지금까지 배운 내용의 순서는 다음과 같다.

1. SELECT

2. FROM

3. WHERE

4. GROUP BY

5. HAVING

6. ORDER BY

CASE

1
2
3
4
5
SELECT player_name,
       year,
       CASE WHEN year = 'SR' THEN 'yes'
            ELSE 'no' END AS is_a_senior
  FROM benn.college_football_players
cs

위와 같이 작성하면 'year'가 'SR'이면 'yes', 그렇지 않다면 'no'로 is_a_senior라는 열을 생성한다.










연습문제

플레이어가 캘리포니아 출신인 경우 'yes' 플래그가 지정된 열을 포함하는 쿼리를 작성하고, 해당 플레이어와 함께 결과를 먼저 정렬한다.

1
2
3
4
5
6
SELECT player_name,
       state,
       CASE WHEN state = 'CA' THEN 'yes'
            ELSE NULL END AS from_california
  FROM benn.college_football_players
 ORDER BY player_name
cs










여러 조건문

1
2
3
4
5
6
7
SELECT player_name,
       weight,
       CASE WHEN weight > 250 THEN 'over 250'
            WHEN weight > 200 THEN '201-250'
            WHEN weight > 175 THEN '176-200'
            ELSE '175 or under' END AS weight_group
  FROM benn.college_football_players
cs

1
2
3
4
5
6
7
SELECT player_name,
       weight,
       CASE WHEN weight > 250 THEN 'over 250'
            WHEN weight > 200 AND weight <= 250 THEN '201-250'
            WHEN weight > 175 AND weight <= 200 THEN '176-200'
            ELSE '175 or under' END AS weight_group
  FROM benn.college_football_players
cs

위의 두 결과는 같지만 겹치치 않게 문장을 만드는 것이 좋다.









연습문제

선수의 이름과 키를 기준으로 네 가지 범주로 분류하는 열을 포함하는 쿼리를 작성

1
2
3
4
5
6
7
SELECT player_name,
       height,
       CASE WHEN height > 74 THEN 'over 74'
            WHEN height > 72 AND height <= 74 THEN '73-74'
            WHEN height > 70 AND height <= 72 THEN '71-72'
            ELSE 'under 70' END AS height_group
  FROM benn.college_football_players
cs










1
2
3
4
SELECT player_name,
       CASE WHEN year = 'FR' AND position = 'WR' THEN 'frosh_wr'
            ELSE NULL END AS sample_case_statement
  FROM benn.college_football_players
cs

다음과 같이 and, or을 사용할 수 있다.











연습문제

모든 열을 선택하는 쿼리를 작성하고 해당 플레이어가 주니어 또는 시니어인 경우 플레이어의 이름을 표시하는 추가 열을 추가합니다.

1
2
3
SELECT *,
       CASE WHEN year IN ('JR''SR') THEN player_name ELSE NULL END AS upperclass_player_name
  FROM benn.college_football_players
cs















집계함수와 함께 사용

1
2
3
4
5
6
SELECT CASE WHEN year = 'FR' THEN 'FR'
            ELSE 'Not FR' END AS year_group,
            COUNT(1) AS count
  FROM benn.college_football_players
 GROUP BY CASE WHEN year = 'FR' THEN 'FR'
               ELSE 'Not FR' END
cs





1
2
3
4
5
6
7
8
SELECT CASE WHEN year = 'FR' THEN 'FR'
            WHEN year = 'SO' THEN 'SO'
            WHEN year = 'JR' THEN 'JR'
            WHEN year = 'SR' THEN 'SR'
            ELSE 'No Year Data' END AS year_group,
            COUNT(1) AS count
  FROM benn.college_football_players
 GROUP BY year_group
cs







1
2
3
4
5
6
7
8
9
10
11
12
SELECT CASE WHEN year = 'FR' THEN 'FR'
            WHEN year = 'SO' THEN 'SO'
            WHEN year = 'JR' THEN 'JR'
            WHEN year = 'SR' THEN 'SR'
            ELSE 'No Year Data' END AS year_group,
            COUNT(1) AS count
  FROM benn.college_football_players
 GROUP BY CASE WHEN year = 'FR' THEN 'FR'
               WHEN year = 'SO' THEN 'SO'
               WHEN year = 'JR' THEN 'JR'
               WHEN year = 'SR' THEN 'SR'
               ELSE 'No Year Data' END
cs







1
2
3
4
5
6
7
SELECT CASE WHEN year = 'FR' THEN 'FR'
            WHEN year = 'SO' THEN 'SO'
            WHEN year = 'JR' THEN 'JR'
            WHEN year = 'SR' THEN 'SR'
            ELSE 'No Year Data' END AS year_group,
            *
  FROM benn.college_football_players
cs















연습문제

 West Coast(CA, OR, WA), Texas 및 기타 모든지역에 대해 300파운드 이상의 플레이어 수를 계산하는 쿼리

1
2
3
4
5
6
7
SELECT CASE WHEN state IN ('CA''OR''WA') THEN 'West Coast'
            WHEN state = 'TX' THEN 'Texas'
            ELSE 'Other' END AS arbitrary_regional_designation,
            COUNT(1) AS players
  FROM benn.college_football_players
 WHERE weight >= 300
 GROUP BY arbitrary_regional_designation
cs






캘리포니아의 모든 하위 클래스 선수(FR/SO)의 합산 가중치와 캘리포니아의 모든 상위 선수(JR/SR)의 합산 가중치를 계산하는 쿼리

1
2
3
4
5
6
7
SELECT CASE WHEN year IN ('FR''SO') THEN 'underclass'
            WHEN year IN ('JR''SR') THEN 'upperclass'
            ELSE NULL END AS class_group,
       SUM(weight) AS combined_player_weight
  FROM benn.college_football_players
 WHERE state = 'CA'
 GROUP BY class_group
cs





집계함수 내에서 사용

이전 예에서는 데이터가 세로로 표시되었지만 경우에 따라 데이터를 가로로 표시할 수 있ㄷ다.

1
2
3
4
5
SELECT COUNT(CASE WHEN year = 'FR' THEN 1 ELSE NULL END) AS fr_count,
       COUNT(CASE WHEN year = 'SO' THEN 1 ELSE NULL END) AS so_count,
       COUNT(CASE WHEN year = 'JR' THEN 1 ELSE NULL END) AS jr_count,
       COUNT(CASE WHEN year = 'SR' THEN 1 ELSE NULL END) AS sr_count
  FROM benn.college_football_players
cs




연습문제

FR, SO, JR, SR 플레이어를 별도의 열에 표시하고 총 플레이어 수에 대한 다른 열을 사용하여 각주의 플레이어 수를 표시하는 쿼리, 가장 많은 플레이어가 있는 상태가 먼저 오도록 결과를 정렬

1
2
3
4
5
6
7
8
9
SELECT state,
       COUNT(CASE WHEN year = 'FR' THEN 1 ELSE NULL END) AS fr_count,
       COUNT(CASE WHEN year = 'SO' THEN 1 ELSE NULL END) AS so_count,
       COUNT(CASE WHEN year = 'JR' THEN 1 ELSE NULL END) AS jr_count,
       COUNT(CASE WHEN year = 'SR' THEN 1 ELSE NULL END) AS sr_count,
       COUNT(1) AS total_players
  FROM benn.college_football_players
 GROUP BY state
 ORDER BY total_players DESC
cs








이름이 A부터 M까지 시작하는 학교의 선수 수와 N~Z로 시작하는 이름을 가진 학교의 수를 표시하는 쿼리

1
2
3
4
5
6
SELECT CASE WHEN school_name < 'n' THEN 'A-M'
            WHEN school_name >= 'n' THEN 'N-Z'
            ELSE NULL END AS school_name_group,
       COUNT(1) AS players
  FROM benn.college_football_players
 GROUP BY school_name_group
cs





DISTINCT

특정 열의 고유한 값만 보고싶을 때 사용

1
2
SELECT DISTINCT month
  FROM tutorial.aapl_historical_stock_price
cs









1
2
SELECT DISTINCT year, month
  FROM tutorial.aapl_historical_stock_price
cs









연습문제

year열의 고유값을 시간순으로 반환하는 쿼리를 작성

1
2
3
SELECT DISTINCT year
  FROM tutorial.aapl_historical_stock_price
 ORDER BY year
cs









집계에서 사용

1
2
SELECT COUNT(DISTINCT month) AS unique_months
  FROM tutorial.aapl_historical_stock_price
cs

집계에서 사용하면 쿼리 속도가 느려질 수 있다.






1
2
3
4
5
SELECT month,
       AVG(volume) AS avg_trade_volume
  FROM tutorial.aapl_historical_stock_price
 GROUP BY month
 ORDER BY avg_trade_volume DESC
cs









연습문제

month의 고유값 수를 계산하는 쿼리

1
2
3
4
5
SELECT year,
       COUNT(DISTINCT month) AS months_count
  FROM tutorial.aapl_historical_stock_price
 GROUP BY year
 ORDER BY year
cs









month열의 고유값 수와 year열의 고유값 수를 별도로 계산하는 쿼리

1
2
3
SELECT COUNT(DISTINCT year) AS years_count,
       COUNT(DISTINCT month) AS months_count
  FROM tutorial.aapl_historical_stock_price
cs





JOIN

여러 테이블의 정보를 쉽게 결합 할 수 있다.

on으로 각 테이블의 동일한 필드에 의해 결합한다.

1
2
3
4
5
6
7
SELECT teams.conference AS conference,
       AVG(players.weight) AS average_weight
  FROM benn.college_football_players players
  JOIN benn.college_football_teams teams
    ON teams.school_name = players.school_name
 GROUP BY teams.conference
 ORDER BY AVG(players.weight) DESC
cs









연습문제

조지아의 모든 선수에 대한 학교 이름, 선수이름, 위치 및 체중을 선택하는 쿼리를 체중순으로 작성

1
2
3
4
5
6
7
SELECT players.school_name,
       players.player_name,
       players.position,
       players.weight
  FROM benn.college_football_players players
 WHERE players.state = 'GA'
 ORDER BY players.weight DESC
cs









join의 종류와 더 자세한 내용은 SQL(5)에서 계속해서 다룰 예정이다.



댓글

이 블로그의 인기 게시물

SQL(9)(performance tuning queries, pivoting data)

데이터 크롤링(3주차)

SQL(8)(writing subqueries, window functions)