SELECT YEAR(ED.DIFFERENTIATION_DATE) AS YEAR, 
(( select max(ed2.size_of_colony) from ecoli_data as ed2 where year(ed2.DIFFERENTIATION_DATE) = year(ed.DIFFERENTIATION_DATE) ) - ED.SIZE_OF_COLONY) AS YEAR_DEV, ED.ID
FROM ECOLI_DATA AS ED
ORDER BY YEAR ASC, YEAR_DEV ASC;

https://school.programmers.co.kr/learn/courses/30/lessons/299310

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

코드설명

YEAR + DATE_FORMAT + LEFT OUTER JOIN + GROUP BY + MAX + SCALAR SUBQUERY 를 활용합니다.

 

문제에서 특이한점은 DATE_FORMAT을 사용할시 보기에는 같은 결과를 반환하는데 제출시 틀리다는 것 입니다.

DATE_FORMAT과 YEAR, MONTH, DAY 는 어떤 차이가 있을까요??

 

먼저, 제가 주로 DATE_FORMAT을 사용했던 이유는 DATE_FORMAT은 원하는 형식으로 쉽게 데이터를 PARSING할 수 있기 떄문이었습니다.

예를 들어, '2019-08' 이 주어졌다고 했을떄 DATE_FORMAT을 사용할경우에는 아래와 같이 쉽게 작성할 수 있습니다.

DATE_FORMAT(YEARDATE, '%Y-%m')

 

두 함수 모두 각각의 장단점이 있습니다. DATE_FORMAT은 위와 같이 원하는 형식으로 쉽게 만들 수 있다는 점, YEAR, MONTH, DAY는 손쉽게 '년도, 월, 날짜'를 가져올 수 있다는 것 입니다.

 

가장 큰 차이점은 반환형식입니다.

DATE_FORMAT은 문자열을 반환하는 반면, YEAR는 숫자를 반환합니다.

 

이 문제에서 DATE_FORMAT을 사용하지 못하는 것은 정답 CASE에 INTEGER 타입으로 고정시켜놓았기 때문으로 보입니다. 

 

 

이와 같이 SUBQUERY를 사용해도 되지만, LEFT OUTER JOIN으로 처리하는것이 더 빠를 것 입니다.

 

ECOLI_DATA ED1는 기존 테이블.

ECOLI_DATA ED2는 각 연도별로 최대 SIZE_OF_COLONY를 구한 테이블.

 

이 ED1과 ED2를 LEFT OUTER JOIN합니다.

즉, ED1에 ED2를 연결시킵니다. (LEFT OUTER JOIN이기에 만약 ED2값이 존재하지 않는다면 NULL값으로 갱신될 것 입니다. 하지만, 이 문제같은경우 ECOLI_DATA 테이블 1개를 기준으로 작업하기에 NULL이 나올 가능성은 전혀 없습니다.)

SELECT YEAR(ED1.DIFFERENTIATION_DATE) AS YEAR, (ED2_SUB.MAX_COLONY - ED1.SIZE_OF_COLONY) AS YEAR_DEV, ED1.ID
FROM ECOLI_DATA AS ED1
LEFT OUTER JOIN ( SELECT YEAR(ED2.DIFFERENTIATION_DATE) AS YEAR, MAX(ED2.SIZE_OF_COLONY) AS MAX_COLONY FROM ECOLI_DATA AS ED2 GROUP BY YEAR(ED2.DIFFERENTIATION_DATE)) AS ED2_SUB
ON YEAR(ED1.DIFFERENTIATION_DATE) = ED2_SUB.YEAR
ORDER BY YEAR ASC, YEAR_DEV

위와 같이 작성하면, 서브쿼리로 작성한 것보다 훨씬 빠를 것으로 예상됩니다.

코드

INNER JOIN을 활용한 코드입니다.

SELECT YEAR(ED1.DIFFERENTIATION_DATE) AS YEAR, (ED2.MAX_SIZE - ED1.SIZE_OF_COLONY) AS YEAR_DEV, ED1.ID 
FROM ECOLI_DATA AS ED1
INNER JOIN ( SELECT MAX(SIZE_OF_COLONY) AS MAX_SIZE, YEAR(DIFFERENTIATION_DATE) AS MAX_DATE
FROM ECOLI_DATA GROUP BY MAX_DATE) AS ED2
WHERE YEAR(ED1.DIFFERENTIATION_DATE) = ED2.MAX_DATE
ORDER BY YEAR(ED1.DIFFERENTIATION_DATE) ASC, YEAR_DEV ASC

LEFT OUTER JOIN을 활용한 코드입니다. ( 어처피 년도별로 모든 년도가 있으므로 NULL일 경우는 없기에 INNER JOIN과 똑같은 결과가 반환됩니다. )

SELECT YEAR(ED1.DIFFERENTIATION_DATE) AS YEAR, (ED2_SUB.MAX_COLONY - ED1.SIZE_OF_COLONY) AS YEAR_DEV, ED1.ID
FROM ECOLI_DATA AS ED1
LEFT OUTER JOIN ( SELECT YEAR(ED2.DIFFERENTIATION_DATE) AS YEAR, MAX(ED2.SIZE_OF_COLONY) AS MAX_COLONY FROM ECOLI_DATA AS ED2 GROUP BY YEAR(ED2.DIFFERENTIATION_DATE)) AS ED2_SUB
ON YEAR(ED1.DIFFERENTIATION_DATE) = ED2_SUB.YEAR
ORDER BY YEAR ASC, YEAR_DEV

YEAR과 SCALAR SUBQUERY를 활용한 코드입니다..

SELECT 
    YEAR(ED1.DIFFERENTIATION_DATE) AS YEAR, 
    ( ( SELECT MAX(ED2.SIZE_OF_COLONY) FROM ECOLI_DATA AS ED2 WHERE YEAR(ED2.DIFFERENTIATION_DATE) = YEAR(ED1.DIFFERENTIATION_DATE) ) - ED1.SIZE_OF_COLONY) AS YEAR_DEV,
    ED1.ID AS ID
FROM ECOLI_DATA AS ED1
ORDER BY YEAR ASC, YEAR_DEV ASC;

 

DATE_FORMAT을 활용한경우(제출시 결과는 같아보이는데 틀림)

SELECT 
    DATE_FORMAT(ED1.DIFFERENTIATION_DATE, '%Y') AS YEAR, 
    ( ( SELECT MAX(ED2.SIZE_OF_COLONY) FROM ECOLI_DATA AS ED2 WHERE YEAR(ED2.DIFFERENTIATION_DATE) = YEAR(ED1.DIFFERENTIATION_DATE) ) - ED1.SIZE_OF_COLONY) AS YEAR_DEV,
    ED1.ID AS ID
FROM ECOLI_DATA AS ED1
ORDER BY YEAR ASC, YEAR_DEV ASC;

 

 

SELECT절에 서브쿼리를 사용합니다. (매번 연산이 필요하므로 느릴 것으로 예상됩니다.)

 

SELECT YEAR(ED.DIFFERENTIATION_DATE) AS YEAR, (( select max(ed2.size_of_colony) from ecoli_data as ed2 where year(ed2.DIFFERENTIATION_DATE) = year(ed.DIFFERENTIATION_DATE) ) - ED.SIZE_OF_COLONY) AS YEAR_DEV, ED.ID
FROM ECOLI_DATA AS ED
ORDER BY YEAR ASC, YEAR_DEV ASC;

테이블을 조인한뒤, 처리합니다. 이떄 중요점은, MAX(SIZE_OF_COLONY) 해당 년도의 최대 크기를 계산하고, YEAR(DIFFERENTIATION_DATE)는 INNER JOIN을 할떄 결합조건으로 사용되므로 함꼐 SELECT해서 가져와야 합니다. 이떄 서브쿼리는 GROUP BY "년도"로 처리합니다.

SELECT YEAR(ED1.DIFFERENTIATION_DATE) AS YEAR, ED2.MAX_SIZE - ED1.SIZE_OF_COLONY AS YEAR_DEV, ED1.ID AS ID
FROM ECOLI_DATA AS ED1
INNER JOIN (
    select max(size_of_colony) as max_size, year(DIFFERENTIATION_DATE) as max_year from ecoli_data group by year(DIFFERENTIATION_DATE) 
) as ED2
ON YEAR(ED1.DIFFERENTIATION_DATE) = ED2.max_year
ORDER BY YEAR ASC, YEAR_DEV ASC

+ Recent posts