반응형

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

 

프로그래머스

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

programmers.co.kr

 

 

💡 문제
2022년 1월의 카테고리 별 도서 판매량을 합산하고, 카테고리(CATEGORY), 총 판매량(TOTAL_SALES) 리스트를 출력하는 SQL문을 작성해주세요.
결과는 카테고리명을 기준으로 오름차순 정렬해주세요.

 

 

✅ 문제 풀이
  • BOOK 테이블과 BOOK_SALES 테이블의 공통 속성인 BOOK_ID를 기준으로 INNER JOIN 해준다.
FROM BOOK A JOIN BOOK_SALES B ON A.BOOK_ID=B.BOOK_ID
  • 이 중에서 판매 날짜인 SALES_DATE가 2022-01-01과 2022-01-31 안에 있는 것만 WHERE 절로 추린다.
WHERE B.SALES_DATE BETWEEN '2022-01-01' AND '2022-01-31'
  • 카테고리 별로 묶어준다.
GROUP BY A.CATEGORY
  • 문제에서 CATEGORY 당 판매량 총합을 구하라고 했으니, CATEGORY 별로 SALES의 SUM을 구한다. 이름은 TOTAL_SALES로 출력한다.
SELECT A.CATEGORY, SUM(B.SALES) AS TOTAL_SALES
  • 조회결과를 CATEGORY에 대해 오름차순 정렬해준다.
ORDER BY CATEGORY;

 

 

✏ 코드 전문
SELECT A.CATEGORY, SUM(B.SALES) AS TOTAL_SALES
FROM BOOK A JOIN BOOK_SALES B ON A.BOOK_ID=B.BOOK_ID
WHERE B.SALES_DATE BETWEEN '2022-01-01' AND '2022-01-31'
GROUP BY A.CATEGORY
ORDER BY CATEGORY;
반응형
반응형

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

 

프로그래머스

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

programmers.co.kr

 

 

💡 문제
FOOD_PRODUCT와 FOOD_ORDER 테이블에서 생산일자가 2022년 5월인 식품들의 식품 ID, 식품 이름, 총매출을 조회하는 SQL문을 작성해주세요. 이때 결과는 총매출을 기준으로 내림차순 정렬해주시고 총매출이 같다면 식품 ID를 기준으로 오름차순 정렬해주세요.

 

 

✅ 문제 풀이
  • FOOD_PRODUCT와 FOOD_ORDER 테이블을 JOIN한다.
FOOD_PRODUCT A JOIN FOOD_ORDER B
ON A.PRODUCT_ID = B.PRODUCT_ID
  • 두 테이블의 공통 속성인 PRODUCT_ID를 기준으로 JOIN한다.

 

  • 생산일자가 2022년 5월인 식품을 추린다.
WHERE PRODUCE_DATE>='2022-05-01' AND PRODUCE_DATE<='2022-05-31'

 

 

  • 제품 당 총매출을 구해야 하기 때문에, 제품 ID를 기준으로 그룹화한다.
GROUP BY A.PRODUCT_ID

 

 

  • 조회할 정보를 가져온다.
SELECT A.PRODUCT_ID, A.PRODUCT_NAME, SUM(A.PRICE*B.AMOUNT) AS TOTAL_SALES
  • 현재 PRODUCT_ID로 그룹화 되어 있기 때문에, SUM을 통해 같은 그룹 내 상품들의 매출을 더하여 총매출을 구할 수 있다.

 

  • 조건에 따라 정렬한다.
ORDER BY TOTAL_SALES DESC, PRODUCT_ID ASC;
  • 총매출을 기준으로 내림차순 정렬, 식품 ID를 기준으로 오름차순 정렬 해준다.

 

 

✏ 코드 전문
SELECT A.PRODUCT_ID, A.PRODUCT_NAME, SUM(A.PRICE*B.AMOUNT) AS TOTAL_SALES
FROM FOOD_PRODUCT A JOIN FOOD_ORDER B
ON A.PRODUCT_ID = B.PRODUCT_ID
WHERE PRODUCE_DATE>='2022-05-01' AND PRODUCE_DATE<='2022-05-31'
GROUP BY A.PRODUCT_ID
ORDER BY TOTAL_SALES DESC, PRODUCT_ID ASC;
반응형
반응형

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

 

프로그래머스

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

programmers.co.kr

 

 

💡 문제
CAR_RENTAL_COMPANY_CAR 테이블과 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블과 CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블에서 자동차 종류가 '세단' 또는 'SUV' 인 자동차 중 2022년 11월 1일부터 2022년 11월 30일까지 대여 가능하고 30일간의 대여 금액이 50만원 이상 200만원 미만인 자동차에 대해서 자동차 ID, 자동차 종류, 대여 금액(컬럼명: FEE) 리스트를 출력하는 SQL문을 작성해주세요. 결과는 대여 금액을 기준으로 내림차순 정렬하고, 대여 금액이 같은 경우 자동차 종류를 기준으로 오름차순 정렬, 자동차 종류까지 같은 경우 자동차 ID를 기준으로 내림차순 정렬해주세요.

 

 

문제의 조건

  • CAR_TYPE 이 '세단' 또는 'SUV'
  • 2022-11-01 부터 2022-11-30 까지 대여가능
  • 30일간의 대여금액 >=500000 AND <2000000
  • 위를 만족하는 자동차의 CAR_ID, CAR_TYPE, FEE 출력
  • 단, 대여금액 기준 내림차순, 자동차 종류 기준 오름차순, 자동차 ID기준 내림차순 정렬

 

✅ 문제 풀이
  • 대여 가능 여부를 판단한다.
    HISTORY 테이블에서 START_DATE와 END_DATE가 있다. 11월 달에 대여한 적이 있는지를 보려면, START_DATE는 11월 30일 이전이어야 하고, END_DATE는 11월 1일 이후여야 한다. SQL문으로 나타내면 다음과 같다.
CAR_RENTAL_COMPANY_RENTAL_HISTORY C 
    WHERE C.START_DATE<='2022-11-30' AND C.END_DATE>='2022-11-01'
  • 그럼 이 날짜에 RENTAL한 적이 있는 자동차는 제외하면 된다. 
  • 이렇게 생각할 수도 있다. 11월 달에 대여한 적 없는 자동차만 고르면 되는 거 아닌가? 로직을 어떻게 짜냐에 다르긴 하지만, 단순하게 각 레코드 마다 11월달에 대여한 적 없는 경우를 고른다면, 11월에도 대여했었지만 다른 날짜에도 대여했던 동일한 자동차도 포함되어 버릴 수 있기 때문에, 11월에 대여한 자동차의 ID 자체를 제외하는 식으로 접근하였다. 이는 NOT IN 연산자를 통해 제외할 수 있다.
A.CAR_ID NOT IN (
    SELECT DISTINCT C.CAR_ID 
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY C 
    WHERE C.START_DATE<='2022-11-30' AND C.END_DATE>='2022-11-01'
)
  • 첫 WHERE 조건을 하나 완성하였다.

 

 

  • 30일간의 대여금액을 계산하기 위해 테이블을 조인한다.
    이를 구하기 위해서는 CAR_RENTAL_COMPANY_CAR 테이블과 CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블을 INNER 조인해주어야 한다. 그래서 각 자동차마다 CAR_TYPE에 따라 DISCOUNT 정보를 갖도록 할것이다.
FROM CAR_RENTAL_COMPANY_CAR A JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN B
ON A.CAR_TYPE=B.CAR_TYPE
  • 두 테이블의 공통 속성인 CAR_TYPE을 기준으로 JOIN한다.

 

  • 조건에 따라 WHERE 절에 조건을 추가로 작성해준다.
AND A.CAR_TYPE IN('SUV', '세단') 
AND B.DURATION_TYPE = '30일 이상' 
AND A.DAILY_FEE*30*(1-B.DISCOUNT_RATE*0.01)>=500000 
AND A.DAILY_FEE*30*(1-B.DISCOUNT_RATE*0.01)<2000000
  • CAR_TYPE이 'SUV', '세단' 중에 해당하면 조회한다. IN 연산자를 사용하였다.
  • 조인 후에는 각 자동차 마다 CAR_TYPE에 따라 3개의 DISCOUNT_RATE 정보가 엮여있을 것이다. 이 중에서 DURATION_TYPE이 '30일 이상' 인것 만 사용하도록 한다.
  • 대여금액은 조건에 해당하는 자동차의 DAILY_FEE*30*할인률 이기 때문에, 이 값이 50만원 이상 200만원 미만인 것만 추리도록 한다.

 

  • 필요한 정보를 출력한다.
SELECT A.CAR_ID, A.CAR_TYPE, CAST(A.DAILY_FEE*30*(1-B.DISCOUNT_RATE*0.01)AS SIGNED) AS FEE
  • 위에 조건에 부합하는 자동차의 CAR_ID, CAR_TYPE, FEE를 조회하도록 한다.
  • 이때 FEE의 경우 *0.01 때문에 소수점 이하 두자리 형태로 출력되게 되는데, 조건의 주의사항에서 FEE의 경우 정수 형태로 출력하도록 되어있기 때문에, CAST 연산자를 사용하여 정수형태로 출력하도록 한다. AS SIGNED는 소수점을 없애면서 부호는 그대로 유지한다는 것이다.

 

  • 조회결과를 주어진 정렬 조건에 맞도록 설정하기
ORDER BY FEE DESC, CAR_TYPE ASC, CAR_ID DESC;
  • 마지막에 ORDER BY 문을 통해서 FEE를 기준으로 내림차순, CAR_TYPE을 기준으로 오름차순, CAR_ID를 기준으로 내림차순 정렬하도록 해준다.

 

✏ 코드 전문
SELECT A.CAR_ID, A.CAR_TYPE, CAST(A.DAILY_FEE*30*(1-B.DISCOUNT_RATE*0.01)AS SIGNED) AS FEE 
FROM CAR_RENTAL_COMPANY_CAR A JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN B
ON A.CAR_TYPE=B.CAR_TYPE
WHERE A.CAR_ID NOT IN (
    SELECT DISTINCT C.CAR_ID 
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY C 
    WHERE C.START_DATE<='2022-11-30' AND C.END_DATE>='2022-11-01'
)
AND A.CAR_TYPE IN('SUV', '세단') 
AND B.DURATION_TYPE = '30일 이상' 
AND A.DAILY_FEE*30*(1-B.DISCOUNT_RATE*0.01)>=500000 
AND A.DAILY_FEE*30*(1-B.DISCOUNT_RATE*0.01)<2000000
ORDER BY FEE DESC, CAR_TYPE ASC, CAR_ID DESC;
반응형
반응형
💡 GROUP BY
  • GROUP BY 컬럼
    컬럼의 값 중 NULL도 있다면 NULL도 하나의 그룹이 될수 있음
    => 사원, 대리, 과장, 차장, 부장, 직급이 정해지지 않은(NULL)이 있을 때, 이를 직급 별로 group화 하면, 6개로 그룹화 가능
  • GROUP BY 절에서는 SELECT 절과는 달리 ALIAS 명을 사용할 수 없음
  • 집계 함수는 WHERE 절에 올 수 없음
    =>집계 함수는 GROUP BY 절에서 사용 가능
  • WHERE 절은 전체 데이터를 GROUP으로 나누기 전에 행들을 미리 제거하는 역할 

 

💡 GROUP BY - HAVING 절 [53]
  • GROUP BY가 없다고 해서 HAVING에 오류가 발생하지는 않는다
    예시)
SELECT SUM(주문금액) AS 합계
FROM 주문
HAVING AVG(주문금액) > 100;

 

=> GROUP BY가 생략된 경우, 적절한 PK로 그룹핑 되고, 그 그룹의 주문 금액 평균이 100보다 크다면 해당 주문금액들의 총합을 출력하는 쿼리이다.

주문ID | 주문금액
-----------------
1      | 80
2      | 120
3      | 90
4      | 110
5      | 95


 이와 같은 테이블이 있다면, 주문ID에 대해 자동 그룹핑될 것이고, 해당 그룹마다 평균 주문금액이 100보다 큰 것은, 주문ID 2와 4의 그룹이므로, 해당 그룹의 주문 금액 합은 120+110=230이다.

합계
-----
230

 

 

  • COUNT와 같은 집계함수를 AVG함수로 감싸 평균을 구할 수 없다
    COUNT는 말 그대로 카운트 한 값을 한 레코드로 출력하는 것이고, 이의 평균이랄 것으로 나눌 값이 명시되지 않기 때문에 AVG함수와 함께 쓸 수 없다
    예시)
SELECT 메뉴ID, 사용유형코드, AVG(COUNT(*)) AS AVGCNT
FROM 시스템사용이력
GROUP BY 메뉴ID, 사용유형코드;

 

 

💡 ORDER BY [56] [57]
  • GROUP BY를 사용할 경우 GROUP BY 표현식이 아닌 값은 기술될 수 없음
    예시)
SELECT 지역, SUM(매출금액) AS 매출금액
FROM 지역별매출
GROUP BY 지역
ORDER BY 년 DESC;

=> 지역에 대해서 그룹핑 되어 매출금액의 SUM을 구하기 때문에, 이를 년이라는 컬럼으로 ORDER할 수 없다

 

  • ORACLE에서는 NULL값을 가장 큰 값으로 간주
    => 오름차순 정렬 시 NULL이 가장 마지막에
    => 내림차순 정렬 시 NULL이 가장 먼저
  • SQL server에서는 NULL을 가장 작은 값으로 간주
    => 오름차순 정렬 시 NULL이 가장 먼저
    => 내림차순 정렬 시 NULL이 가장 마지막에
  • ORDER BY정레 컬럼명 대신 ALIAS 명이나 컬럼 순서를 나타내는 정수를 혼용하여 사용할 수 있음

 

💡 SELECT 문장 실행 순서 [59]

FROM > WHERE > GROUP BY > HAVING > SELECT > ORDER BY

 

 

💡 TOP() 질의문 
  • SQL server의 TOP N 질의문에서 N에 해당하는 값이 동일한 경우 함께 출력되도록 하는 WITH TIES 옵션을 ORDER BY 절과 함께 사용해야 함
  • 예시)
    SELECT TOP(3) WITH TIES 팀명, 승리건수
    FROM 팀별성적
    ORDER BY 승리건수 DESC;

    =>팀별성적에서 팀명과 높은 순으로 승리건수를 조회하는데, 가장 위 3개를 조회한다. 단 3위의 승리건수와 동일한 팀이 있다면 해당 팀까지도 같이 출력한다.
     

 

💡 EQUI JOIN 문장
  • SELECT 테이블1.칼럼명, 테이블2.칼럼명,...
    FROM 테이블1, 테이블2
    WHERE 테이블1.칼럼명1=테이블2.칼럼명2;
    => WHERE 절에 JOIN 조건을 넣음
  • SELECT 테이블1.칼럼명, 테이블2.칼럼명,...
    FROM 테이블1 INNER JOIN 테이블2
    ON 테이블1.칼럼명1=테이블2.칼럼명2;
    => ON 절에 JOIN 조건을 넣음

 

💡 JOIN
  • 일반적으로 JOIN은 PK와 FK 값의 연관성에 의해 성립됨
  • DBMS 옵티마이저는 FROM 절에 나열된 테이블들을 임의로 2개씩 묶어서 JOIN을 처리함
  • EQUI JOIN은 JOIN에 관여하는 테이블 간의 컬럼 값들이 정확하게 일치하는 경우에 사용되는 방법임
  • EQUI JOIN은 = 연산자에 의해서만 수행되며, 그 이외의 비교 연산자를 사용하는 경우에는 모두 NON EQUI JOIN임
  • 대부분 NON EQUI JOIN을 수행할 수 있지만, 때로는 설계상의 이유로 수행이 불가능한 경우도 있음
반응형
반응형

첫 sql문 문제 풀이이다.

데이터베이스설계를 들으면서 sql문은 어느 정도 익숙해져 있고, 정처기를 준비하면서도 복잡한 sql문을 공부해 왔어서 어렵지 않게 문제를 풀 수 있었으나...! 역시 디테일한 부분은 좀 더 공부할 필요가 있음을 느낀 첫 문제였다.

 

DATE 형식의 컬럼의 출력 형태 변환하는 방법!

이 문제에서 내가 걸렸던 부분은 주의사항에 있는 DATE 형식을 주어진 예제의 출력결과처럼 변경하여 출력할 수 있도록 하는 것이었다.

 

문제에서 PUBLISHED_DATE의 형식을 'YYYY-MM-DD' 형태로 출력하도록 요구하고 있다.

 

처음에는 이 부분을 확인하지 못하고 그냥 출력해 보았는데, 뒤에 상세한 시간까지 출력되는 것을 확인하였다.

이렇게 시간까지 표시되는 것을, 날짜만 표시되도록 변경해주어야 한다.

 

이때 사용할 수 있는 것이 DATE_FORMAT() 함수이다!!

 

 

mysql : DATE를 원하는 형식으로 변경하기

각 sql마다 다른데, 내가 사용하는 mysql을 기준으로는 다음과 같은 방식을 사용할 수 있다.

 

1. 날짜→문자열로 변환

DATE FORMAT(날짜, 출력 형식)

문제 예시 ) DATE_FORMAT(A.PUBLISHED_DATE, '%Y-%m-%d')

위의 형태의 날짜를 '2020-01-02'의 형태로 리턴해준다.

2. 문자열→날짜로 변환
 
STR_TO_DATE(문자, 출력 형식)
 
예시) 
STR_TO_DATE('20080101', '%Y-%m-%d')

20080101이라는 문자를 2008-01-01의 형태의 날짜로 리턴해준다.



여기에서 주의할 점은 '%Y-%m-%d' 이 부분인데, 여기에서 Y이면 '2020'과 같은 형태를, m이면 '03'과 같은 형태를, d이면 '23'과 같은 형태로, 보통 'yyyy-mm-dd'형식의 출력을 얻을 수 있다.
이 부분이 왜 헷갈리냐면, 저 문자를 대문자로 쓰느냐, 소문자로 쓰느냐에 따라 다른 출력이 되기 때문이다.
나도 처음에는 모두 대문자로 써서, 월은 'march', 일은 'secondary_three' 이런식으로 나왔다.
따라서 형식에 따라 잘 구분지어 주어야 한다. 
자세한 내용은 아래의 표를 참고하자.

 

**FORMAT설명

%M Month 월(Janeary, February ...)
%m Month 월(01, 02, 03 ...)
%W Day of Week 요일(Sunday, Monday ...)
%D Month 월(1st, 2dn, 3rd ...)
%Y Year 연도(1999, 2000, 2020)
%y Year 연도(99, 00, 20)
%X Year 연도(1999, 2000, 2020) %V와 같이쓰임
%x Year 연도(1999, 2000, 2020) %v와 같이쓰임
%a Day of Week요일(Sun, Mon, Tue ...)
%d Day 일(00, 01, 02 ...)
%e Day 일(0, 1, 2 ..)
%c Month(1, 2, 3 ..)
%b Month(Jen Feb ...)
%j n번째 일(100, 365)
%H Hour 시(00, 01, 24) 24시간 형태
%h Hour 시(01, 02, 12) 12시간 형태
%I(대문자 아이) Hour 시(01, 02 12) 12시간 형태
%l(소문자 엘) Hour 시(1, 2, 12) 12 시간 형태
%i Minute 분(00, 01 59)
%r hh:mm:ss AP
%T hh:mm:ss
%S, %s Second 초
%p AP, PM
%w Day Of Week (0, 1, 2) 0부터 일요일
%U Week 주(시작: 일요일)
%u Week 주(시작 월요일)
%V Week 주(시작: 일요일)
%v Week 주(시작:월요일)

 

위의 방법을 사용하고 출력한 결과이다.

원하는 출력 형태를 얻을 수 있었다!

 

전체 코드는 아래와 같다.

SELECT A.BOOK_ID, B.AUTHOR_NAME, DATE_FORMAT(A.PUBLISHED_DATE, '%Y-%m-%d') AS PUBLISHED_DATE
FROM BOOK A JOIN AUTHOR B ON A.AUTHOR_ID=B.AUTHOR_ID 
WHERE A.CATEGORY='경제' 
ORDER BY A.PUBLISHED_DATE;

join할 때 조인할 테이블을 A, B이런식으로 지정해주는 건 정처기 때 버릇.. 아주 좋은 버릇인거 같다.

가끔 안해도 돌아갈 때가 있는데, 정확하게 쓰는 거는 위가 맞기 때문에, 최대한 쓰려고 한다.

select ~ from~join~on~where~order by~ 순으로 알아보기 쉽게 줄바꿈 해 두었다.

 

* DATE_FORMAT(A.PUBLISHED_DATE, '%Y-%m-%d') AS PUBLISHED_DATE 

이런 부분의 경우, 예시 출력 형태를 보고 컬럼 이름을 잘 지정해주는 것이 중요한 포인트이다.

아깝게 틀릴 수 있는 사소한 문제이기 때문이다!

 

이상 백준허브 연동 겸 가볍게 풀어본 sql문제였다.

반응형

+ Recent posts