Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

Today I Learned

sql_select & max,min,count & group by 공부 본문

프로그래머스_ sql

sql_select & max,min,count & group by 공부

꾸주니12 2022. 11. 7. 16:12

프로그래머스 스쿨 sql 고득점 Kit 문제

https://school.programmers.co.kr/learn/challenges?tab=sql_practice_kit 


select

#1. 문제

ONLINE_SALE 테이블과 OFFLINE_SALE 테이블에서 2022년 3월의 오프라인/온라인 상품 판매 데이터의 판매 날짜, 상품ID, 유저ID, 판매량을 출력하는 SQL문을 작성해주세요. OFFLINE_SALE 테이블의 판매 데이터의 USER_ID 값은 NULL 로 표시해주세요. 결과는 판매일을 기준으로 오름차순 정렬해주시고 판매일이 같다면 상품 ID를 기준으로 오름차순, 상품ID까지 같다면 유저 ID를 기준으로 오름차순 정렬해주세요

SELECT TO_CHAR(SALES_DATE, 'YYYY-MM-DD'), PRODUCT_ID, USER_ID, SALES_AMOUNT
  FROM ( (SELECT SALES_DATE
               , PRODUCT_ID
               , USER_ID
               , SALES_AMOUNT
            FROM ONLINE_SALE
           WHERE TO_CHAR(SALES_DATE, 'YYYYMM') = '202203')
         UNION ALL
         (SELECT SALES_DATE
               , PRODUCT_ID
               , NULL AS USER_ID
               , SALES_AMOUNT
            FROM OFFLINE_SALE WHERE TO_CHAR(SALES_DATE, 'YYYYMM') = '202203')
       )
 ORDER BY SALES_DATE, PRODUCT_ID, USER_ID
  • to_char : 숫자 값을 문자열로 변환하는 함수 (참고 블로그 : 숫자 형식으로 변환하기(TO_CHAR) (tistory.com))
  • union all : 합집합같은 개념. 중복값도 다 표시해줌 
  • OFFLINE_SALE 테이블의 판매 데이터의 USER_ID 값은 NULL 로 표시 : NULL AS USER_ID로 함, 여기 잘 이해안됨

 

 

#2. 

오라클에서 != , <> , ^= : 특정 값이 아닌 조건을 걸 경우 세가지가 쓰이는데 <> 를 제일 많이 쓴대

(참고 블로그 : 오라클 != <> ^= 차이 정리글 (tistory.com))

(not like를 쓴 사람도 있던데...)

 

 

 

#3. 문제

동물 보호소에 가장 먼저 들어온 동물의 이름을 조회하는 SQL 문을 작성해주세요

/*서브쿼리 사용하기 */ 
SELECT name from animal_ins where datetime = (select min(datetime) from animal_ins)

 

 

#4. 문제 -- 어려움

REST_INFO와 REST_REVIEW 테이블에서 서울에 위치한 식당들의 식당 ID, 식당 이름, 음식 종류, 즐겨찾기수, 주소, 리뷰 평균 점수를 조회하는 SQL문을 작성해주세요. 이때 리뷰 평균점수는 소수점 세 번째 자리에서 반올림 해주시고 결과는 평균점수를 기준으로 내림차순 정렬해주시고, 평균점수가 같다면 즐겨찾기수를 기준으로 내림차순 정렬해주세요.

SELECT lpad(a.rest_id,5,0), a.rest_name, a.food_type, a.favorites, a.address, round(avg(b.review_score),2) as score
from rest_info a inner join rest_review b
on a.rest_id = b.rest_id
where a.address like '서울%'
group by lpad(a.rest_id,5,0), a.rest_name, a.food_type, a.favorites, a.address
order by score desc, a.favorites desc

/*또는 where substr(a.address,2,1) = '서울' */
  • lpad()함수를 쓴 이유는 데이터가 1,2,3 으로 저장되어있어서 그런것 
  • LPAD("값","총문자길이","채움문자") (참고 블로그 : https://gent.tistory.com/190 )
  • ROUND("값","자리수") (참고 블로그 : https://gent.tistory.com/241)
  • 처음에 group by절을 쓰지않아 문제를 틀렸었다. not a single-group group function 이라고 떴는데, 이 에러는 그룹함수를 사용했는데 group by를 사용하지 않아 생긴 에러임 (참고 블로그 : https://gent.tistory.com/241)
  • group by 에 여러개 쓰는 이유는 group by 로 기준이되는 컬럼들과 연산이 되는 컬럼만 조회돼야 오류가 안나서 그런거 아닐까  (참고 q&a : https://www.inflearn.com/questions/27971)

 

 


MAX, MIN, COUNT

 

 

 

 

#5. 문제

USER_INFO 테이블에서 2021년에 가입한 회원 중 나이가 20세 이상 29세 이하인 회원이 몇 명인지 출력하는 SQL문을 작성해주세요.

/*부등호 사용하기*/
SELECT count(user_id) from user_info where to_char(joined, 'YYYY') = '2021' and age>=20 and age <=29

/*between 사용하기*/
SELECT count(user_id) from user_info where to_char(joined, 'YYYY') = '2021' and age between 20 and 29
  • 문제가 '가입한 회원중 나이가 ~ ' 라서 group by -having 절을 사용할 생각을 함. 아마 이 개념을 잘 모르는 듯.. 하지만 그냥 조건이 2개였음 

 

#6. 문제

동물 보호소에 들어온 동물의 이름은 몇 개인지 조회하는 SQL 문을 작성해주세요. 이때 이름이 NULL인 경우는 집계하지 않으며 중복되는 이름은 하나로 칩니다.

/*내가 한 방법*/
SELECT count(distinct name) as count from animal_ins 
SELECT count(distinct name) as count from animal_ins where name is not null


/*다른사람이 한 방법*/
SELECT COUNT(name)
 FROM (SELECT DISTINCT name 
        FROM ANIMAL_INS);
  • COUNT는 *가 아니면 null을 세지 않는다.

 

 


group by

 

#7. 문제

동물 보호소에 들어온 동물 이름 중 두 번 이상 쓰인 이름과 해당 이름이 쓰인 횟수를 조회하는 SQL문을 작성해주세요. 이때 결과는 이름이 없는 동물은 집계에서 제외하며, 결과는 이름 순으로 조회해주세요.

/*정답*/
SELECT name, count(name) from animal_ins group by name having count(name) > 1 order by name 

/*틀림*/
SELECT name, count(name) from animal_ins group by name having count(*) > 1 order by name

/*COUNT(*) 로 할 경우 WHERE NAME IS NOT NULL 넣어주기 -- 정답*/
SELECT NAME, COUNT(NAME) AS COUNT
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
GROUP BY NAME
HAVING COUNT(*)>=2
ORDER BY NAME;
  • 왜 틀렸을까 생각해보니 *로 해서 이름이 없는 동물까지 집계한거 아닐까 생각해본다. 위에서 배웠듯이 COUNT는 *가 아니면 null 을 세지 않기 때문에, 문제에 따라 name 을 넣어주니 정답!

 

 

#8. 문제

보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 합니다. 09:00부터 19:59까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요. 이때 결과는 시간대 순으로 정렬해야 합니다.

/*처음 한 방식*/
SELECT to_char(datetime,'HH24') as hour, count(datetime) as count 
from animal_outs group by to_char(datetime,'HH24') 
having to_char(datetime,'HH24') >=9 and to_char(datetime,'HH24') <=19 
order by hour


/*더 간단하게 */
SELECT to_char(datetime,'HH24') as hour, count(datetime) as count 
from animal_outs group by to_char(datetime,'HH24') 
having to_char(datetime,'HH24') between 9 and 19 order by hour

 

 

#9. 문제 -- 어려움 

보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 합니다. 0시부터 23시까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요. 이때 결과는 시간대 순으로 정렬해야 합니다.

 

(참고 블로그 : [Oracle] 오라클 고급쿼리 – 계층적 쿼리 (level) (tistory.com) )

(참고 블로그2 CONNECT BY LEVEL 사용법 : 오라클 계층쿼리 CONNECT BY LEVEL 사용법 | momo (tistory.com) )

(참고 블로그3 : [Oracle] CONNECT BY 계층형 쿼리가 어려울 때 (tistory.com) )

 

/*첫번째*/
select b.HOUR,count(a.HOUR) cnt
from (select to_char(datetime,'HH24') HOUR from animal_outs) a 
   , (select level-1 HOUR from dual connect by level <= 24) b
where b.HOUR=a.HOUR(+)
group by b.HOUR
order by b.HOUR

/*두번째*/
SELECT A.HOUR
     , COUNT(B.ANIMAL_TYPE) AS COUNT
  FROM (
       SELECT DISTINCT (LEVEL-1) AS HOUR
         FROM ANIMAL_OUTS
      CONNECT BY LEVEL <= 24
       ) A
  LEFT JOIN ANIMAL_OUTS B
    ON TO_CHAR(DATETIME,'HH24') = A.HOUR
 GROUP BY HOUR
 ORDER BY HOUR

 

 

#10. 문제

PRODUCT 테이블에서 만원 단위의 가격대 별로 상품 개수를 출력하는 SQL 문을 작성해주세요. 이때 컬럼명은 각각 컬럼명은 PRICE_GROUP, PRODUCTS로 지정해주시고 가격대 정보는 각 구간의 최소금액(10,000원 이상 ~ 20,000 미만인 구간인 경우 10,000)으로 표시해주세요. 결과는 가격대를 기준으로 오름차순 정렬해주세요.

/*첫번째*/
SELECT substr(price,1,1) *10000 as price_group, count(product_id) as products
from product 
group by substr(price,1,1) *10000
order by price_group


/*두번째*/
SELECT
    floor(price/10000)*10000 as price_group
    , count(product_id)
from product
group by floor(price/10000)
order by floor(price/10000) asc
;