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

이승렬님의 프로필 이미지
이승렬

작성한 질문수

SQL 코딩테스트를 위한 마지막 걸음

Date 강의 / leetcode 1321 질문

해결된 질문

작성

·

110

1

# [Setting]

USE PRACTICE;
DROP TABLE Customer;
CREATE TABLE Customer (customer_id int, name varchar(20), visited_on date, amount int);
INSERT INTO Customer (customer_id, name, visited_on, amount)
VALUES
(44, 'Ashley', '2019-01-04', 160),
(23, 'Sabo', '2019-01-04', 70),
(38, 'Moustafa', '2019-01-05', 90),
(30, 'Halley', '2019-01-06', 140),
(5, 'Elvis', '2019-01-07', 160),
(12, 'Leslie', '2019-01-08', 100),
(23, 'Sabo', '2019-01-08', 90),
(13, 'Will', '2019-01-09', 170),
(20, 'Brock', '2019-01-10', 160),
(29, 'Leo', '2019-01-10', 90),
(33, 'Isaac', '2019-01-11', 60),
(46, 'Selena', '2019-01-12', 100),
(4, 'Winston', '2019-01-13', 150),
(15, 'Marti', '2019-01-13', 160);
SELECT * FROM Customer;
# [my practice]
select b.visited_on, 
sum(amount) as amount, 
round(sum(a.amount) /7, 2) as average_amount
from customer a
inner join
(select distinct date_sub(visited_on, interval 6 day) as week_before, 
visited_on 
from customer) b
on a.visited_on between b.week_before and b.visited_on
group by b.visited_on
having count(amount) >= 7
order by b.visited_on;

올려주신 방식 외에 inner join시 date 구간으로 조건 넣는 방식으로 시도해 보았습니다.

위 데이터로 삽입하는 경우, MySQL Workbench에서는 예상 결과대로 출력 되는데 leetcode에서 오류가 나서 혹시 제가 코드 상에서 간과하고 있는 부분이 있는지 궁금해서 질문 드립니다.

leetcode 내에 PostgreSQL로 유사한 방식의 해결 법은 확인했었는데 혹시나 해서 링크 올려봅니다.

https://leetcode.com/problems/restaurant-growth/solutions/5040002/well-explained-postgresql-solution-beats-99

답변 1

1

Gemma님의 프로필 이미지
Gemma
지식공유자

승렬님 안녕하세요:)

참신한 방법으로 풀어주셨는데요!

 

먼저 승렬님께서 간과했던 부분을 말씀드리겠습니다.

승렬님처럼 작성하면 2019-01-08 데이터가 포함됩니다.

데이터는 2019-01-04부터 시작하는데, 7일치의 데이터가 만들어지기 때문에 2019-01-08 데이터는 포함되면 안됩니다. (그런 의미에서 2019-01-09도 들어가면 안되는데, 승렬님 코드로 Output에 포함됨)

 

하지만 이렇게 잘못 포함된 이유는 having count(amount) >= 7로 작성하셨기 때문입니다.

그러면 160부터 90까지의 amount 데이터가 7개 존재하기 때문에, 2019-01-08 데이터도 조건에 포함되어서 들어가게 된 것입니다.

image


그럼 승렬님과 비슷한 로직으로 올바르게 작성하려면 아래와 같이 작성하면 됩니다.

(having절을 having count(distinct a.visited_on) = 7로 바꿨습니다.)

select b.visited_on,
sum(amount) as amount,
round(sum(a.amount) /7, 2) as average_amount
from customer a
inner join (
    select distinct date_sub(visited_on, interval 6 day) as week_before, 
    visited_on 
    from customer
) b
on a.visited_on between b.week_before and b.visited_on
group by b.visited_on
having count(distinct a.visited_on) = 7
order by b.visited_on;

 

이렇게 보면 헷갈릴 수 있으니 select * inner join order by까지만 작성 후 풀어헤쳐보면 아래와 같이 결과가 나올텐데요.

여기서 2019-01-08과 같은 데이터는 포함하지 않게 하기 위해서,

having절에 distinct a.visited_on의 개수가 7개가 되어야 한다는 조건을 추가해서 제거합니다.

image



혹시 읽으시고 이해가 안가면, 편하게 질문 다시 주셔요 :)

 

 

이승렬님의 프로필 이미지
이승렬

작성한 질문수

질문하기