인프런 커뮤니티 질문&답변

아경님의 프로필 이미지
아경

작성한 질문수

초보자를 위한 BigQuery(SQL) 입문

총 정리 문제 풀이 1~3번

총 정리 문제 풀이 2번 질문 있습니다

해결된 질문

작성

·

19

0

안녕하세요. 선생님

2번 풀이에서 저는 pokemon을 FROM 절에 쓰고, LEFT 함수로 trainer_pokemon을 썼는데요. 선생님과 결과가 다르게 나오더라구요.

이 경우에는 "가장 많이 포획된" 기준으로 물었기 때문에 status가 있는 trainer_pokemon을 FROM 절에 써야하는 건가요??

SELECT 
type1,
kor_name,
COUNT(tp.id) AS pokemon_cnt
FROM basic.pokemon AS p
LEFT JOIN basic.trainer_pokemon AS tp
ON p.id = tp.pokemon_id
GROUP BY type1, kor_name
ORDER BY pokemon_cnt DESC

 

답변 2

0

카일스쿨님의 프로필 이미지
카일스쿨
지식공유자

아경님 안녕하세요.

pokemon을 왼쪽으로 두셨군요.

이런 경우엔 2개의 쿼리를 둘 다 실행해보시고, 차이가 있나 확인해보시는 것을 추천드려요

 

좌 : 제가 작성한 쿼리

우 : 아경님 쿼리

편하게 비교하기 위해 ORDER BY에 kor_name을 추가했습니다

 

쿼리를 실행하면 다음과 같은 결과가 보입니다

스크린샷 2024-12-12 오후 3.04.12.png.webp

 

출력된 결과를 보면 유사한 것을 확인할 수 있습니다. 버터풀, 잉어킹, 잠만보, 팬텀, 식스테일 등 pokemon_cnt도 동일한 것을 볼 수 있죠. 다만, 페이지 결과 수를 보면 좌측 쿼리 결과는 166행, 우측 쿼리 결과는 251행입니다. 결과가 다릅니다. 이런 경우에 왜 다르지?를 직접 확인해보면 원인을 빨리 파악할 수 있습니다.

 

그래서 저는 >|을 클릭해서 맨 뒤로 데이터를 확인했습니다

 

스크린샷 2024-12-12 오후 3.06.15.png.webp

좌측 쿼리는 pokemon_cnt가 1인 경우까지 나오고, 우측 쿼리는 pokemon_cnt가 0인 경우가 나옵니다. 우측 쿼리 결과를 <을 눌러 Row 수를 맞추면 동일한 결과가 나오다가 pokemon_cnt가 0인 것이 나오는 것을 확인할 수 있을겁니다.

 

그렇다면 이 현상은 왜 발생할까요?

제 쿼리

LEFT : trainer_pokemon

RIGHT : pokemon

 

아경님의 쿼리

LEFT : pokemon

RIGHT : trainer_pokemon

 

trainer_pokemon : 트레이너가 잡은 포켓몬 현황

pokemon : 모든 포켓몬의 종류

trainer_pokemon 중에 잡힌 전적이 없는 포켓몬도 있을 수 있어요. pokemon은 1~251번의 포켓몬에 대한 데이터가 저장된거라서요. 그리고 trainer_pokemon엔 여러 포켓몬이 여러번 잡힐 수 있습니다. 이는 회사의 상황과 동일합니다. 판매하는 제품의 id가 있고, 고객이 주문을 넣을 때 주문 id가 생기죠. trainer_pokemon = 주문, pokemon = 제품이라고 생각하면 됩니다.

 

돌아와서, 아경님의 쿼리는 포켓몬 251마리를 LEFT에 두고 우측에 trainer_pokemon 기록을 붙입니다. 그렇게 되면 모든 포켓몬에 대해서 정보가 붙는데, 잡힌 정보가 없는 포켓몬이 있어서 pokemon_cnt가 0이 나오게 됩니다.

 

문제 조건에 "가장 많이 포획된"이라는 조건이 있었는데, 이것은 잡히지 않은 포켓몬은 제외하라는 것을 내포합니다.

 

그래서 아경님의 쿼리를 이렇게 수정한다면 동일한 결과가 나옵니다.

SELECT 
type1,
kor_name,
COUNT(tp.id) AS pokemon_cnt
FROM basic.pokemon AS p
LEFT JOIN basic.trainer_pokemon AS tp
ON p.id = tp.pokemon_id
GROUP BY type1, kor_name
HAVING pokemon_cnt >= 1
ORDER BY pokemon_cnt DESC

 

HAVING pokemon_cnt >= 1 조건을 주면 동일하게 나옵니다.

 

LEFT을 어디에 두어야 하나요? => 그건 상황에 따라 적절히 하면 됩니다. 공식보단 제가 쿼리를 작성한 경험에선 주문 데이터 같은 trainer_pokemon을 왼쪽에 두는 것이 의도에 맞게 나와서 이렇게 설정했습니다. 아경님이 하신대로 하고 RIGHT JOIN을 쓸 수도 있지만, 헷갈릴 위험이 있어 저는 LEFT만 쓰곤 합니다.

결과가 다를 때 어떻게 디버깅을 해야하는지도 공유드렸으니 이런 상황이 또 발생하면 이렇게 디버깅을 해보셔요.

0

안녕하세요, 인프런 AI 인턴입니다.

아경님께서 질문하신 BigQuery 코드에서 결과가 다르게 나온 이유와 관련해서 설명드리겠습니다.

우선, 쿼리의 목적은 “가장 많이 포획된 포켓몬”을 찾는 것입니다. 이 경우에는 trainer_pokemon 테이블을 주 테이블로 사용하여 포켓몬의 포획 횟수(status)와 같은 정보를 기준으로 데이터를 집계하는 것이 적절합니다.

잘못된 부분과 해결책:

쿼리에서 FROM 절에 pokemon을 사용하고 있습니다. 이렇게 되면, pokemon 테이블에 있는 모든 포켓몬 데이터가 기준이 되고, 각 포켓몬에 대해 trainer_pokemon의 상태와 상관없이 데이터를 조인하게 됩니다. 그래서 불필요한 포켓몬까지 포함되거나 결과가 부정확할 수 있습니다.

개선된 접근법:

trainer_pokemonFROM 절에 배치함으로써, 실제로 포획된 포켓몬만 기준으로 집계합니다. 이어서 LEFT JOIN을 통해 pokemon 테이블에서 포켓몬의 세부 정보를 가져오는 방식으로 수정이 필요합니다.

아래는 제안드리는 쿼리 수정안입니다:

SELECT
    tp.type1,
    p.kor_name,
    COUNT(tp.id) AS pokemon_cnt
FROM 
    basic.trainer_pokemon AS tp
LEFT JOIN 
    basic.pokemon AS p
ON 
    tp.pokemon_id = p.id
GROUP BY 
    tp.type1, p.kor_name
ORDER BY 
    pokemon_cnt DESC

위와 같이 trainer_pokemonFROM 절의 기준으로 설정하면, 포획 기록이 있는 포켓몬만으로 집계하여 보다 정확한 결과를 얻을 수 있습니다.

저는 질문자님의 이해를 돕고자 예전에 존재했던 유사한 질문과 카일스쿨님의 답변을 바탕으로 도움을 드리고 있습니다. 관련 질문 링크를 참조하시면 보다 상세한 예시를 확인할 수 있습니다.

현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

아경님의 프로필 이미지
아경

작성한 질문수

질문하기