Written by
xi-jjun
on
on
BigQuery - 연습문제 풀이 2
BigQuery
개요
인프런 강의 추천을 받게 됐고, 회사에서 현재 사용하고 있는 툴이어서 알고쓰자는 마음에 공부하게 됐습니다.
연습문제 풀이
문제1) 포캣몬 중에서 type2 값이 없는 포캣몬의 수를 구하는 쿼리를 작성해라
NULL은 다른 값과의 직접 비교가 불가능 ex)NULL = NULL은 틀린 쿼리- 따라서
IS연산자를 사용해야 한다.
-- 총 135건
SELECT
COUNT(*) AS cnt
FROM `basic.pokemon`
WHERE
type2 IS NULL;
문제2) type2가 없는 포캣몬의 type1 과 type1 의 포캣몬의 수를 구하는 쿼리를 작성해라 (type1의 포캣몬의 수가 큰 순서로 정렬)
SELECT
type1,
COUNT(*) AS type1_cnt
FROM `basic.pokemon`
WHERE
type2 IS NULL
GROUP BY
type1
ORDER BY
type1_cnt DESC;
문제3) type2에 상관없이 type1 의 포캣몬의 수를 구하는 쿼리를 작성해라
SELECT
type1,
COUNT(*) AS cnt
FROM `basic.pokemon`
GROUP BY
type1;
문제4) 전설 여부에 따른 포켓몬 수를 구하는 쿼리를 작성해라
SELECT
is_legendary,
COUNT(*) AS cnt
FROM `basic.pokemon`
GROUP BY
is_legendary; -- GROUP BY 1 로 써도 된다. select 대상 1번째 컬럼으로 GROUP BY하겠다는 의미. 빠른 쿼리 작성이 가능해진다.
문제5) 동명이인이 존재하는 이름을 구하는 쿼리를 작성해라
WHERE: 원본 테이블에 조건을 걸 수 있음HAVING:GROUP BY결과로 나온 정보에 조건을 걸 수 있음
SELECT
name
FROM `basic.trainer`
GROUP BY
name
HAVING
COUNT(*) > 1;
문제6) trainer 테이블에서 Iris트레이너 정보를 알 수 있는 쿼리를 작성해라
- 실제였다면 아마도 요구사항에 대한 구체화가 필요할 것으로 보임
- 어떤 정보가 필요할지?
- (쿼리 결과)
Iris트레이너는 2명으로 보이는데, 이 중에서 어떤 트레이너의 정보를 알고 싶은 것일지? 혹은 단순 이름이 같은 트레이너들의 정보를 알고 싶은 것일지?
SELECT
*
FROM `basic.trainer`
WHERE
name = 'Iris';
문제7) trainer 테이블에서 Iris, Whitney, Cynthia 트레이너 정보를 구하는 쿼리를 작성해라
SELECT
*
FROM `basic.trainer`
WHERE
name IN ('Iris', 'Whitney', 'Cynthia');
문제 8~10은 스킵 (이전에 풀었던 문제와 비슷)
문제11) type2값이 존재하는 포켓몬 중 제일 많은 type1을 구하는 쿼리를 작성해라
SELECT
type1,
COUNT(*) AS cnt
FROM `basic.pokemon`
WHERE
type2 IS NOT NULL
GROUP BY
type1
ORDER BY
cnt DESC
LIMIT 1;
문제12) 하나의 타입만 존재하는 포켓몬 중 가장 많은 type1을 구하는 쿼리를 작성해라
type1이 반드시 존재한다는 보장이 없다고 생각하여 아래와 같은WHERE조건의 쿼리를 작성. 강의에서는 단순하게type2 IS NULL로 ‘하나의 타입만 존재’함을 나타냄.
SELECT
type1,
COUNT(*) AS cnt
FROM `basic.pokemon`
WHERE
(type1 IS NULL AND type2 IS NOT NULL)
OR (type1 IS NOT NULL AND type2 IS NULL)
GROUP BY
type1
ORDER BY
COUNT(*) DESC
LIMIT 1;
문제15) 트레이너가 보유한 포켓몬이 가장 많은 트레이너를 구하는 쿼리를 작성해라
trainer_pokemon테이블에서 trainer id, pokemon id 로 GROUP BY하여 검색할 생각을 했었음.- 그러나 해당 방식은 잘못된 접근. 1명의 트레이너는 여러마리의 같은종류 포켓몬을 가질 수 있어서
trainer_id로만 GROUP BY를 했어야 함.
- 그러나 해당 방식은 잘못된 접근. 1명의 트레이너는 여러마리의 같은종류 포켓몬을 가질 수 있어서
SELECT
name
FROM `basic.trainer`
WHERE id = (
SELECT
trainer_id
FROM (
SELECT
DISTINCT
trainer_id,
pokemon_id
FROM `basic.trainer_pokemon`
GROUP BY
trainer_id, pokemon_id
) AS tmp
GROUP BY
trainer_id
ORDER BY
COUNT(*) DESC
LIMIT 1
);
-- 정답
-- 간과했던 사실 : 트레이너는 같은 포켓몬을 여러마리 가질 수 있다는 사실
-- - 해당 사실을 알기 위해서는 trainer_pokemon 테이블을 잘 봤어야 했음
-- - 해당 테이블을 보면 pokemon_id가 같은 경우가 있지만, 그 이외의 데이터가 다름. 따라서 같은 종류의 포켓몬을 여러마리 가질 수 있었음을 알 수 있음.
SELECT
trainer_id,
COUNT(pokemon_id) AS pokemon_count
FROM `basic.trainer_pokemon`
GROUP BY
pokemon_id
-- 수정.
-- 개인적으로 실제로 업무를 진행할 때에는 단순 trainer_id 가 아니라, 실제로 '이름'이 누군지 궁금할 것임.
-- 따라서 서브쿼리로 가장 많은 포켓몬을 보유한 트레이너(id=17)의 이름을 구하는 쿼리를 작성
SELECT
name
FROM `basic.trainer`
WHERE id = (
SELECT
trainer_id
FROM `basic.trainer_pokemon`
GROUP BY
trainer_id
ORDER BY
COUNT(*) DESC
LIMIT 1
)
문제16) 포켓몬을 가장 많이 풀어준 트레이너를 구하는 쿼리를 작성해라
- 15번과 마찬가지로 구함.
- ‘풀어줬다’라는 의미를 파악하기 위해서
trainer_pokemon테이블의status컬럼을 참고할 필요가 존재. (해당 컬럼의 의미파악이 중요)
SELECT
name
FROM `basic.trainer`
WHERE id = (
SELECT
trainer_id
FROM `basic.trainer_pokemon`
WHERE status = 'Released'
GROUP BY
trainer_id
ORDER BY
COUNT(*) DESC
LIMIT 1
)
문제17) 포켓몬을 풀어준 비율이 20%가 넘는 트레이너를 구하는 쿼리를 작성해라
- 트레이너 별 잡은 전체 포켓몬 수 구하는 쿼리로 임시 테이블 생성
- 트레이너 별 풀어준 포켓몬 수 구하는 쿼리로 임시 테이블 생성
- 2개의 테이블
JOIN및 트레이너의 이름을 구하기 위해서trainer테이블도JOIN (풀어준 포켓몬 수 / 잡은 포켓몬 수) > 0.2조건을WHERE에 추가
SELECT
trainer.id AS trainer_id,
trainer.name AS trainer_name
FROM (
SELECT
trainer_id,
COUNT(pokemon_id) AS total_pokemon_cnt
FROM `basic.trainer_pokemon`
GROUP BY
trainer_id
) AS total_cnt
JOIN
(
SELECT
trainer_id,
COUNT(pokemon_id) AS total_released_pokemon_cnt
FROM `basic.trainer_pokemon`
WHERE status = 'Released'
GROUP BY
trainer_id
) AS released_cnt ON released_cnt.trainer_id = total_cnt.trainer_id
JOIN
`basic.trainer` AS trainer ON trainer.id = total_cnt.trainer_id
WHERE
(total_released_pokemon_cnt / total_pokemon_cnt) > 0.2
-- COUNTIF 함수에 대해서 알았으면 더 간단하게 작성이 가능했을 듯 하다
SELECT
trainer_id,
COUNTIF(status = 'Released') AS released_cnt, -- 풀어준 포켓몬 수
COUNT(pokemon_id) AS total_cnt -- 전체 잡은 포켓몬 수
FROM `basic.trainer_pokemon`
GROUP BY
trainer_id
HAVING
(released_cnt / total_cnt) > 0.2