(스압주의) 프로그래머스 SQL 고득점 kit - 오라클

salami·2023년 1월 27일
1

다때려박아봣어요.

문제 출처

  • 제가 푼 답
  • 다른 분들 답 중 기록해두고 싶은 것
  • 문제 푸는 포인트

    등을 적어 두었습니다.
    모든 문제가 있지는 않으며, 수정 중이라 부족한 부분이 많습니다.
    문제 풀면서 바로바로 기록한 걸 아무런 검토없이 냅다 올려버려서 그렇습니다... 쫌만 봐주세요 🙏
    친구가 스압주의 풀고 글을 쪼개라는데... 그냥 오른쪽 목차에서 찾아보셔요

* : 복습필수 (님들 말구 제 얘깁니다..)


SELECT

인기있는 아이스크림 (orderby 중첩)

  • 문제 설명 FIRST_HALF 테이블은 아이스크림 가게의 상반기 주문 정보를 담은 테이블입니다.FIRST_HALF 테이블 구조는 다음과 같으며, SHIPMENT_IDFLAVORTOTAL_ORDER는 각각 아이스크림 공장에서 아이스크림 가게까지의 출하 번호, 아이스크림 맛, 상반기 아이스크림 총주문량을 나타냅니다.
    NAMETYPENULLABLE
    SHIPMENT_IDINT(N)FALSE
    FLAVORVARCHAR(N)FALSE
    TOTAL_ORDERINT(N)FALSE

    문제

    상반기에 판매된 아이스크림의 맛을 총주문량을 기준으로 내림차순 정렬하고 총주문량이 같다면 출하 번호를 기준으로 오름차순 정렬하여 조회하는 SQL 문을 작성해주세요.

    예시

    예를 들어 FIRST_HALF 테이블이 다음과 같을 때
    SHIPMENT_IDFLAVORTOTAL_ORDER
    101chocolate3200
    102vanilla2800
    103mint_chocolate1700
    104caramel2600
    105white_chocolate3100
    106peach2450
    107watermelon2150
    108mango2900
    109strawberry3100
    110melon3150
    111orange2900
    112pineapple2900
    상반기 아이스크림 맛을 총주문량을 기준으로 내림차순 정렬하고 총주문량이 같은 경우 출하 번호를 기준으로 오름차순 정렬하면 chocolate, melon, white_chocolate, strawberry, mango, orange, pineapple, vanilla, caramel, peach, watermelon, mint_chocolate 순서대로 조회되어야 합니다. 따라서 SQL문을 실행하면 다음과 같이 나와야 합니다. FLAVOR
    chocolate
    melon
    white_chocolate
    strawberry
    mango
    orange
    pineapple
    vanilla
    caramel
    peach
    watermelon
    mint_chocolate
  • SELECT flavor 
    FROM FIRST_HALF
    ORDER BY total_order DESC, shipment_id
    • order by 중첩으로 이용할 수 있음

3월에 태어난 여성 회원 목록 출력하기 (날짜형식)

  • 문제

    문제 설명

    다음은 식당 리뷰 사이트의 회원 정보를 담은 MEMBER_PROFILE 테이블입니다. MEMBER_PROFILE 테이블은 다음과 같으며 MEMBER_IDMEMBER_NAMETLNOGENDERDATE_OF_BIRTH는 회원 ID, 회원 이름, 회원 연락처, 성별, 생년월일을 의미합니다.
    Column nameTypeNullable
    MEMBER_IDVARCHAR(100)FALSE
    MEMBER_NAMEVARCHAR(50)FALSE
    TLNOVARCHAR(50)TRUE
    GENDERVARCHAR(1)TRUE
    DATE_OF_BIRTHDATETRUE

    문제

    MEMBER_PROFILE 테이블에서 생일이 3월인 여성 회원의 ID, 이름, 성별, 생년월일을 조회하는 SQL문을 작성해주세요. 이때 전화번호가 NULL인 경우는 출력대상에서 제외시켜 주시고, 결과는 회원ID를 기준으로 오름차순 정렬해주세요.

    예시

    MEMBER_PROFILE 테이블이 다음과 같을 때
    MEMBER_IDMEMBER_NAMETLNOGENDERDATE_OF_BIRTH
    jiho92@naver.com이지호01076432111W1992-02-12
    jiyoon22@hotmail.com김지윤01032324117W1992-02-22
    jihoon93@hanmail.net김지훈01023258688M1993-02-23
    seoyeons@naver.com박서연01076482209W1993-03-16
    yoonsy94@gmail.com윤서연NULLW1994-03-19
    SQL을 실행하면 다음과 같이 출력되어야 합니다.
    MEMBER_IDMEMBER_NAMEGENDERDATE_OF_BIRTH
    seoyeons@naver.com박서연W1993-03-16

    주의사항

    DATE_OF_BIRTH의 데이트 포맷이 예시와 동일해야 정답처리 됩니다.
  • 정답
    SELECT MEMBER_ID, MEMBER_NAME, GENDER, TO_CHAR(DATE_OF_BIRTH, 'YYYY-MM-DD') AS DATE_OF_BIRTH
    FROM MEMBER_PROFILE 
    WHERE GENDER = 'W' 
    and TO_CHAR(DATE_OF_BIRTH, 'MM') = '03'
    and TLNO is not null
    ORDER BY MEMBER_ID ;

강원도에 위치한 생산공장 목록 출력하기

  • 문제 문제 설명 다음은 식품공장의 정보를 담은 FOOD_FACTORY 테이블입니다. FOOD_FACTORY 테이블은 다음과 같으며 FACTORY_IDFACTORY_NAMEADDRESSTLNO는 각각 공장 ID, 공장 이름, 주소, 전화번호를 의미합니다.
    Column nameTypeNullable
    FACTORY_IDVARCHAR(10)FALSE
    FACTORY_NAMEVARCHAR(50)FALSE
    ADDRESSVARCHAR(100)FALSE
    TLNOVARCHAR(20)TRUE

    문제

    FOOD_FACTORY 테이블에서 강원도에 위치한 식품공장의 공장 ID, 공장 이름, 주소를 조회하는 SQL문을 작성해주세요. 이때 결과는 공장 ID를 기준으로 오름차순 정렬해주세요.
  • SELECT FACTORY_ID, FACTORY_NAME, ADDRESS
    FROM FOOD_FACTORY 
    **WHERE ADDRESS LIKE '강원도%'**
    ORDER BY FACTORY_ID

12세 이하인 여자환자 목록 출력하기

  1. NVL(column, ‘output’)
    칼럼값이 비어있을 때 넣을 내용을 직접 지정해서 출력할 수 있음
    1. COALESCE와의 차이점은 무엇인지…?
  2. “여자”환자… ← 문제 제대로 읽기 ㅜ
  • 문제
    • 12세 이하인 여자 환자 목록 출력하기

      darklight

      sublimevimemacs

      Oracle

      문제 설명

      다음은 종합병원에 등록된 환자정보를 담은 PATIENT 테이블입니다. PATIENT 테이블은 다음과 같으며 PT_NOPT_NAMEGEND_CDAGETLNO는 각각 환자번호, 환자이름, 성별코드, 나이, 전화번호를 의미합니다.

      Column nameTypeNullable
      PT_NOVARCHAR(10)FALSE
      PT_NAMEVARCHAR(20)FALSE
      GEND_CDVARCHAR(1)FALSE
      AGEINTEGERFALSE
      TLNOVARCHAR(50)TRUE

      문제

      PATIENT 테이블에서 12세 이하인 여자환자의 환자이름, 환자번호, 성별코드, 나이, 전화번호를 조회하는 SQL문을 작성해주세요. 이때 전화번호가 없는 경우, 'NONE'으로 출력시켜 주시고 결과는 나이를 기준으로 내림차순 정렬하고, 나이 같다면 환자이름을 기준으로 오름차순 정렬해주세요.

  • 정답
    -- 코드를 입력하세요
    SELECT PT_NAME, PT_NO, GEND_CD, AGE, COALESCE(TLNO, 'NONE') AS TLNO
    FROM PATIENT 
    WHERE GEND_CD = 'W'
    AND AGE <= 12
    ORDER BY AGE DESC, PT_NAME

과일로 만든 아이스크림 고르기

  • 문제

    문제 설명

    다음은 아이스크림 가게의 상반기 주문 정보를 담은 FIRST_HALF 테이블과 아이스크림 성분에 대한 정보를 담은 ICECREAM_INFO 테이블입니다. FIRST_HALF 테이블 구조는 다음과 같으며, SHIPMENT_IDFLAVORTOTAL_ORDER 는 각각 아이스크림 공장에서 아이스크림 가게까지의 출하 번호, 아이스크림 맛, 상반기 아이스크림 총주문량을 나타냅니다. FIRST_HALF 테이블의 기본 키는 FLAVOR입니다.
    NAMETYPENULLABLE
    SHIPMENT_IDINT(N)FALSE
    FLAVORVARCHAR(N)FALSE
    TOTAL_ORDERINT(N)FALSE
    ICECREAM_INFO 테이블 구조는 다음과 같으며, FLAVORINGREDITENT_TYPE 은 각각 아이스크림 맛, 아이스크림의 성분 타입을 나타냅니다. INGREDIENT_TYPE에는 아이스크림의 주 성분이 설탕이면 sugar_based라고 입력되고, 아이스크림의 주 성분이 과일이면 fruit_based라고 입력됩니다. ICECREAM_INFO의 기본 키는 FLAVOR입니다. ICECREAM_INFO테이블의 FLAVOR는 FIRST_HALF 테이블의 FLAVOR의 외래 키입니다.
    NAMETYPENULLABLE
    FLAVORVARCHAR(N)FALSE
    INGREDIENT_TYPEVARCHAR(N)FALSE
  • 정답
    -- 코드를 입력하세요
    SELECT f.FLAVOR 
    FROM FIRST_HALF f
    LEFT JOIN ICECREAM_INFO i 
    ON f.FLAVOR = i.FLAVOR
    WHERE f.TOTAL_ORDER > 3000
    AND INGREDIENT_TYPE = 'fruit_based'
    ORDER BY TOTAL_ORDER DESC
    SELECT F.FLAVOR
    
    FROM 
    	(SELECT FLAVOR 
    	FROM FIRST_HALF 
    	WHERE TOTAL_ORDER > 3000
    	ORDER BY TOTAL_ORDER DESC ) F, 
    	ICECREAM_INFO I 
    	
    WHERE F.FLAVOR = I.FLAVOR
    AND I.INGREDIENT_TYPE = 'fruit_based'
    SELECT F.FLAVOR 
    FROM FIRST_HALF F, ICECREAM_INFO I
    WHERE F.FLAVOR = I.FLAVOR 
    AND TOTAL_ORDER > 3000 
    AND INGREDIENT_TYPE = 'fruit_based'
    ORDER BY F.FLAVOR

흉부외과 또는 일반외과 의사 목록 출력하기

  • 정답
    -- 코드를 입력하세요
    SELECT DR_NAME, DR_ID, MCDP_CD, TO_CHAR(HIRE_YMD, 'YYYY-MM-DD')
    FROM DOCTOR
    WHERE MCDP_CD = 'CS'
    OR MCDP_CD = 'GS'
    ORDER BY HIRE_YMD DESC, DR_NAME
    select dr_name, dr_id, mcdp_cd, to_char(hire_ymd, 'yyyy-mm-dd') 
    from doctor
    where mcdp_cd ~~**is**~~ in ('CS', 'GS')
    order by hire_ymd desc, dr_name

조건에 맞는 회원수 구하기 ㅇ

-- 코드를 입력하세요
SELECT count(user_id)
from user_info 
where to_char(joined, 'yy') = '21'
and age between 20 and 29

상위 n개 레코드 ㅇ

select name
from animal_ins
where datetime = (select min(datetime)
                 from animal_ins)
  • 다른 답 ****mysql****
    select name 
    from animal_ins
    **order by datetime 
    limit 1** 
    oracle using in-line view subquery
    select name
    from (select name from animal_ins order by datetime)
    where **rownum** = 1

여러 기준으로 정렬하기 ㅇ

-- 코드를 입력하세요
select animal_id, name, datetime
from animal_ins 
order by name, datetime DESC

어린 동물 찾기 o

is not (x)

-- 코드를 입력하세요
SELECT animal_id, name 
from animal_ins
where intake_condition != 'Aged'
order by animal_id

* 재구매가 일어난 상품과 회원 리스트 구하기 having

  • 문제

    문제 설명

    다음은 어느 의류 쇼핑몰의 온라인 상품 판매 정보를 담은 ONLINE_SALE 테이블 입니다. ONLINE_SALE 테이블은 아래와 같은 구조로 되어있으며 ONLINE_SALE_IDUSER_IDPRODUCT_IDSALES_AMOUNTSALES_DATE는 각각 온라인 상품 판매 ID, 회원 ID, 상품 ID, 판매량, 판매일을 나타냅니다.
    Column nameTypeNullable
    ONLINE_SALE_IDINTEGERFALSE
    USER_IDINTEGERFALSE
    PRODUCT_IDINTEGERFALSE
    SALES_AMOUNTINTEGERFALSE
    SALES_DATEDATEFALSE
    동일한 날짜, 회원 ID, 상품 ID 조합에 대해서는 하나의 판매 데이터만 존재합니다.

    문제

    ONLINE_SALE 테이블에서 동일한 회원이 동일한 상품을 재구매한 데이터를 구하여, 재구매한 회원 ID와 재구매한 상품 ID를 출력하는 SQL문을 작성해주세요. 결과는 회원 ID를 기준으로 오름차순 정렬해주시고 회원 ID가 같다면 상품 ID를 기준으로 내림차순 정렬해주세요.
  • 정답
    select user_id, product_id 
    from online_sale
    group by user_id, product_id
    having count(*) > 1
    order by user_id, product_id desc
    HAVING 문에서는 이전 포스팅에서 다룬 집계함수를 통해 조건을 추가할 수 있어요!
    • MAX : 컬럼의 최댓값을 산출
    • MIN : 컬럼의 최소값을 산출
    • SUM : 컬럼의 값을 합계를 산출
    • COUNT : 컬럼의 갯수를 산출
    • AVG : 컬럼의 평균값을 산출

오프라인/온라인 판매 데이터 통합하기 union / union all

  • 포인트
    select sales_date, product_id, **NULL AS user_id**, sales_amount
    from offline_sale
    • 없는값 null처리
    • union(distinct), union all
      • union은 중복되는 레코드를 제거
      • union all 은 그냥 결과를 내려줌.
        • union all 이 데이터처리에 있어서 빠름

          💡 **[어떤 블로거의 의견](http://intomysql.blogspot.com/2011/01/union-union-all.html)**

          결론은,

        1. UNION 이든지 UNION ALL이든지 사실 그리 좋은 SQL 작성은 아니다.

          UNION이 필요하다는 것은 사실 두 엔터티(테이블)가 하나의 엔터티(테이블)로 통합이 되었어야

          할 엔터티들이었는데, 알 수 없는 이유로 분리 운영되는 경우가 상당히 많다.

          즉 모델링 차원에서 엔터티를 적절히 통합하여 UNION의 요건을 모두 제거하자.

        2. 두 집합에 절대 중복된 튜플(레코드)가 발생할 수 없다는 보장이 있다면 UNION ALL을 꼭 사용하자.

          두 집합에서 모두 각각의 PK를 조회하는데, 그 두 집합의 PK가 절대 중복되지 않는 형태

        3. 중복이 있다 하더라도 그리 문제되지 않는다면 UNION 보다는 UNION ALL을 사용하자.

        4. 만약 UNION이나 UNION ALL을 사용해야 한다면, 최소 필요 컬럼만 SELECT 하자.

  • 정답
    1. 내 답: 전부 합친 테이블을 만들어서 거기서 조건을 추가함

      -- 판매 날짜, 상품ID, 유저ID, 판매량
      select to_char(sales_date, 'yyyy-mm-dd') as sales_date, product_id, user_id, sales_amount
      from (select sales_date, product_id, user_id, sales_amount
          from online_sale
          union 
          select sales_date, product_id, NULL AS user_id, sales_amount
          from offline_sale) 
      where to_char(sales_date, 'mm') = '03'
      order by sales_date, product_id, user_id
    2. 다른사람들 해답

      select date_format(sales_date, '%Y-%m-%d') as sales_date, product_id, user_id, sales_amount
      from online_sale
      where sales_date >= '2022-03-01' and sales_date < '2022-04-01'
      
      union all
      
      select date_format(sales_date, '%Y-%m-%d') as sales_date, product_id, NULL as user_id, sales_amount
      from offline_sale
      where sales_date >= '2022-03-01' and sales_date < '2022-04-01'
      
      order by sales_date, product_id, user_id

      조건을 적용한 각각의 테이블을 union all

* 서울에 위치한 식당 목록 출력하기

  • 포인트
    1. “서울에 위치한”
      문제 제대로 읽기 ㅜㅜ
    2. rest_id 다섯자리수 숫자로 만들기
      e.g. 2300023 lpad(대상, 범위, 넣을내용)
    3. score 소숫점 둘째자리까지 표시
      e.g. 55.00
      to_char(대상, ‘FM9.00’)
      두 자리 수 정수는 FM99.00
  • 내 코드
    select lpad(i.rest_id, 5, 0) as rest_id, i.rest_name, i.food_type, i.favorites, i.address, to_char(r.score, 'FM9.00') as score
    from (select rest_id, round(avg(review_score), 2) as score
          from rest_review
          group by rest_id) r, 
          rest_info i 
    where i.rest_id = r.rest_id 
    and address like '서울%'
    order by score desc, favorites desc
  • 다른사람들 한 방법
    1. fully right join table, group by 여러개 having address like,
    2. from (rest info table) inner join (average review score table)

SUM, MAX, MIN

중복 제거하기

  • 내 코드
    SELECT count(unique(name))
    from animal_ins
  • 다른아이디어
    1. distinct 사용

      count(distinct name)

    • DISTINCT : 중복을 없애주지만 정렬을 해주지 않는다.

    • GROUP BY : 중복을 없애주고 정렬도 해준다.

      이 때 GROUP BY는 그루핑 뿐만 아니라 정렬까지 수행하기 때문에 속도면에서 DISTINCT가 빠를 수 있다.상황에 맞게 적절히 사용하자.

      SELECT * 
      FROM FOOD_PRODUCT 
      WHERE PRICE = 
      (SELECT MAX(PRICE) PRICE FROM FOOD_PRODUCT);

GROUP BY

* **진료과별 총 예약 횟수 출력하기**

SELECT mcdp_cd 진료과코드, count(*) "5월예약건수"
from appointment
where to_char(apnt_ymd, 'yymm') = '2205'
group by mcdp_cd
**order by 2 , 1**

→ 정답은 같게 나오는데 왜 이게 오답 포인트인지..?

다른사람

SELECT "진료과코드", "5월예약건수"
FROM(SELECT MCDP_CD AS "진료과코드",
SUM(CASE WHEN TO_CHAR(APNT_YMD, 'MM') = '05' THEN 1 END) AS "5월예약건수"
FROM APPOINTMENT    
GROUP BY MCDP_CD)
WHERE "5월예약건수" IS NOT NULL
ORDER BY "5월예약건수" ASC, "진료과코드" ASC

고양이와 개는 몇 마리 있을까 ㅇ

SELECT animal_type, count(*)
from animal_ins
group by animal_type
order by animal_type

동명 동물 수 찾기

-- 코드를 입력하세요
select *
from (SELECT name, count(name) count
      from animal_ins
      group by name)
where count > 1
order by name

* 저자 별 카테고리 별 매출액 집계하기

points

  • join
  • group by 중첩
  • 내 답
    select author_id, author_name, category, sum(total_sales)
    from (select a.author_id, a.author_name, category, (price*sales) total_sales
        from book b 
        join (select book_id, sum(sales) sales
              from book_sales 
              where to_char(sales_date, 'yymm') = 2201 
              group by book_id) bs
        on b.book_id = bs.book_id
        join author a 
        on a.author_id = b.author_id)
    group by author_id,author_name, category
    order by author_id, category desc
  • 다른 답
    select a.author_id, a.author_name, b.category, sum(bs.sales * b.price) as total_sales 
    from author a
    inner join b on a.author_id = b.author_id
    inner join book_sales bs on b.book_id = bs.book_id
    where to_char(bs.sales_date, 'yymm') = '2201'
    group by a.author_id, a.author_name, b.category
    order by a.author_id, b.category desc
    https://yongku.tistory.com/entry/프로그래머스SQL-저자-별-카테고리-별-매출액-집계하기-오라클Oracle

성분으로 구분한 아이스크림 총 주문량

  • 내 답
    select ingredient_type, sum(total_order) total_order
    from first_half f, icecream_info i 
    **where f.flavor= i.flavor**
    group by ingredient_type
    order by total_order

* 가격대 별 상품 개수 구하기

내 답

select trunc(price, -4) price_group, count(*) products
from product
group by trunc(price, -4)
order by trunc(price, -4)

trunc, case when

select truncate(price, -4) as price_group, count(product_id) as products

from product

group by price_group

order by price_group

select trunc(price, -4) price_group, count(*) as products
from product
group by price_group 
order by price_group 
SELECT  FLOOR(PRICE/10000)*10000 AS PRICE_GROUP
        , COUNT(*) AS PRODUCTS
  FROM  product
 GROUP 
    BY  PRICE_GROUP
 ORDER
    BY  PRICE_GROUP ASC
SELECT  CASE WHEN (0 < PRICE) AND (PRICE < 10000) then 0
             WHEN (10000 <= PRICE) and (PRICE < 20000) then 10000
             WHEN (20000 <= PRICE) and (PRICE < 30000) then 20000
             WHEN (30000 <= PRICE) and (PRICE < 40000) then 30000
             WHEN (40000 <= PRICE) and (PRICE < 50000) then 40000
             WHEN (50000 <= PRICE) and (PRICE < 60000) then 50000
             WHEN (60000 <= PRICE) and (PRICE < 70000) then 60000
             WHEN (70000 <= PRICE) and (PRICE < 80000) then 70000
             WHEN (80000 <= PRICE) and (PRICE < 90000) then 80000
             END AS PRICE_GROUP, count(*)
  FROM  PRODUCT 
 GROUP 
    BY  PRICE_GROUP
 ORDER
    BY  PRICE_GROUP ASC

* 입양 시각 구하기

LTRIM, RTRIM

datetime hh 12시간 , HH 24시간 HH24 HH12

to_number

  • 내 답
    SELECT to_number(to_char(datetime, 'HH24')) hour, count(*) count
    from animal_outs
    where to_number(to_char(datetime, 'HH24')) between 09 and 19
    group by to_number(to_char(datetime, 'HH24'))
    order by hour
  • 다른 답 mysql인가봄
    select hour(datetime) as HOUR,
            count(*) as COUNT
    from animal_outs
    where hour(datetime) between 9 and 19
    group by HOUR
    order by HOUR asc;

ORACLE, MYSQL 날짜에서 각 값들을 추출하기 🧐

* 자동차 종류 별 특정 옵션이 포함된 자동차 수 구하기

  • hint WHERE options REGEXP '통풍시트|열선시트|가죽시트' → mysql로는 되는데 오라클은 안됨. WHERE OPTIONS LIKE '%시트%'
  • 내 답
    -- 코드를 입력하세요
    SELECT car_type, count(car_type) cars
    from car_rental_company_car
    WHERE OPTIONS LIKE '%시트%'
    group by car_type
    order by car_type

* 즐겨찾기가 가장 많은 식당 정보 출력하기

  • 내 답
    select f.food_type, rest_id, rest_name, f.favorites
    from (select food_type, max(favorites) favorites
          from rest_info
          group by food_type) f, rest_info r
    where f.food_type = r.food_type 
    **and f.favorites = r.favorites** 
    order by food_type desc
  • 다른 사람 답
    SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES
      FROM REST_INFO
     WHERE (FOOD_TYPE, FAVORITES) IN (SELECT FOOD_TYPE, MAX(FAVORITES) 
                                        FROM REST_INFO
                                       GROUP BY FOOD_TYPE) 
     ORDER BY FOOD_TYPE DESC;
    select food_type, rest_id,rest_name, favorites
    from(
    select food_type, rest_id,rest_name, favorites,
        rank() over(partition by food_type order by favorites desc) as rk
    from REST_INFO
    )
    where rk = 1
    order by food_type desc
    rank() partition by

카테고리별 도서 판매량 집계하기

  • 내 답
    select category, sum(sales) total_sales
    from (SELECT book_id, category
          from book) b,
          book_sales s 
    where b.book_id = s.book_id
    and to_char(sales_date, 'yymm') = '2201'
    group by category
    order by category asc;

대여 횟수가 많은 자동차들의 월별 대여 횟수 구하기

  • 내 답
    -- -- 코드를 입력하세요
    
    select to_number(to_char(start_date , 'mm')) month, car_id, count(car_id) records
    from (select CAR_ID, START_DATE, count(car_id) over(partition by car_id) as records
          from CAR_RENTAL_COMPANY_RENTAL_HISTORY
          **where to_char(start_date, 'yymm') in ('2208' , '2209', '2210')**) r
    where r.records **>= 5**
    group by to_char(start_date, 'mm'), car_id 
    order by to_char(start_date, 'mm'), car_id desc
  • 다른 사람 답
    SELECT MONTH, CAR_ID, RECORDS
    FROM (
        SELECT DISTINCT MONTH(START_DATE) AS MONTH
            , CAR_ID
            , COUNT(*) OVER(PARTITION BY MONTH(START_DATE), CAR_ID) AS RECORDS
            , COUNT(*) OVER(PARTITION BY CAR_ID) AS FILTER
        FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
        WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31'
        )A
    WHERE FILTER >= 5 
    ORDER BY MONTH ASC, CAR_ID DESC

식품분류별 가장 비싼 상품의 정보 조회하기

  • 내 답
    select category, price, product_name
    from (SELECT category, PRODUCT_NAME, PRICE, max(price) over (partition by category) maxprice
          from food_product) 
    where price = maxprice 
    and category in ('과자', '국', '김치', '식용유')
    order by price desc
  • 다른 사람 답
    select CATEGORY, PRICE AS MAX_PRICE, PRODUCT_NAME 
    from food_product
    where (category, price) in ( SELECT category, max(price) as price
    														 from FOOD_PRODUCT 
    														 where category in ('과자', '국', '김치', '식용유') 
    														 group by category)
    order by price desc

* 입양 시각 구하기(2)

  • points 오라클 순번 채번 CONNECT BY LEVEL 활용하기
    • connect by start with: 계층쿼리로 상하관계를 질의할 때 사용
    • level: 순위를 의미
    • connect by level: 연속된 숫자를 조회할 때 사용
      • 1-10 연속된 숫자 조회

        select level as no 
        from dual 
        connect by level <= 10 
      • 22년 1월부터 12월까지 출력

        select '2022년'||lpad(level, 2, 0)||'월' as no
        from dual 
        connect by level <= 12
      • 특정 날짜 구간 조회

  • select hour, count(datetime) count 
    from (select level -1 as hour 
          from dual 
          connect by level <= 24) t2
          **left join** animal_outs t1
          on t2.hour = to_char(t1.datetime, 'HH24')
    group by hour 
    order by hour asc
    [Oracle] 프로그래머스 - 입양 시각 구하기 (2)
    select t2.lv hour, nvl(t1.cnt, 0) count
    from (select to_char(datetime, 'HH24') hour, count(*) cnt 
        from animal_outs
        group by to_char(datetime, 'HH24')
        order by hour 
        ) t1, 
        (select level -1 lv 
        from dual 
        connect by level <= 24) t2 
    where t2.lv = t1.hou**r(+)**
    order by t2.lv
    [PROGRAMMER Level-4] 입양 시각 구하기(2)[Oracle]

* 년, 월, 성별 별 상품 구매 회원 수 구하기

  • some research
    • (+)는 outer join 연산자

      ❗️Oracle에서 OUTER JOIN 연산자는  (+)  입니다.

      ❗️조인시킬 값이 없는 조인 측에 (+)를 위치시킵니다.

      ❗️OUTER JOIN 연산자는 표현식의 한 편에만 올 수 있습니다.

      ❗️매칭되는 데이터가 없는 경우, NULL로 표시합니다.

      💡 이유는 모르겠지만 연도와 월을 추출하는 과정에서 to_char을 사용하니까 오답으로 인식하는 것 같네요

      날짜 정보 추출 함수인 extract 함수를 사용하면 정답으로 인식합니다.extract 사용법은 아래와 같습니다.extract(year from sales_date) as YEAR,extract(month from sales_date) sa MONTH

      group by 절도 extract 함수로 바꿔주세요.group by extract(year from SALES_DATE),extract(month from SALES_DATE), GENDER

      자세한 함수 사용법은 아래 블로그를 참고하세요.https://blog.naver.com/PostView.nhn?blogId=regenesis90&logNo=222226229952

  • 내 답
    -- 코드를 입력하세요
    SELECT to_char(sales_date, 'YYYY') year, to_char(sales_date, 'MM') month, u.gender, count(**distinct u.user_id**) users 
    from online_sale s, user_info u
    where s.user_id = u.user_id 
    and u.gender is not null
    group by to_char(sales_date, 'YYYY'), to_char(sales_date, 'MM'), u.gender
    order by year, month, gender
    distinct : 같은 회원이 여러 번 구매하는 경우가 있기 때문에 중복 제거를 위해 사용 … 요구사항이 연, 월 성별 구매회원이었음,, 1월에 여러번 사도 한번으로 count해야 2023.01.01 이랑 2023.01.05 는 년/월 은 같은데 날짜는 달라요


IS NULL

경기도에 위치한 식품창고 목록 출력하기

nvl

-- 코드를 입력하세요
SELECT warehouse_id, warehouse_name, address, nvl(freezer_yn, 'N') freezer_yn
from food_warehouse
where address like '경기%'
order by warehouse_id

이름이 없는 동물의 아이디 O

SELECT animal_id
from animal_ins
where name is null
order by animal_id

**이름이 있는 동물의 아이디 O**

-- 코드를 입력하세요
SELECT animal_id
from animal_ins
where name is not null
order by animal_id

나이 정보가 없는 회원 수 구하기 O

SELECT count(*) users
from user_info 
where age is null

NULL 처리하기

-- 코드를 입력하세요
SELECT animal_type, nvl(name, 'No name'), sex_upon_intake
from animal_ins 
order by animal_id

JOIN

없어진 기록 찾기

  • 문제

    문제 설명

    ANIMAL_INS 테이블은 동물 보호소에 들어온 동물의 정보를 담은 테이블입니다. ANIMAL_INS 테이블 구조는 다음과 같으며, ANIMAL_IDANIMAL_TYPEDATETIMEINTAKE_CONDITIONNAMESEX_UPON_INTAKE는 각각 동물의 아이디, 생물 종, 보호 시작일, 보호 시작 시 상태, 이름, 성별 및 중성화 여부를 나타냅니다.
    NAMETYPENULLABLE
    ANIMAL_IDVARCHAR(N)FALSE
    ANIMAL_TYPEVARCHAR(N)FALSE
    DATETIMEDATETIMEFALSE
    INTAKE_CONDITIONVARCHAR(N)FALSE
    NAMEVARCHAR(N)TRUE
    SEX_UPON_INTAKEVARCHAR(N)FALSE
    ANIMAL_OUTS 테이블은 동물 보호소에서 입양 보낸 동물의 정보를 담은 테이블입니다. ANIMAL_OUTS 테이블 구조는 다음과 같으며, ANIMAL_IDANIMAL_TYPEDATETIMENAMESEX_UPON_OUTCOME는 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별 및 중성화 여부를 나타냅니다. ANIMAL_OUTS 테이블의 ANIMAL_ID는 ANIMAL_INS의 ANIMAL_ID의 외래 키입니다.
    NAMETYPENULLABLE
    ANIMAL_IDVARCHAR(N)FALSE
    ANIMAL_TYPEVARCHAR(N)FALSE
    DATETIMEDATETIMEFALSE
    NAMEVARCHAR(N)TRUE
    SEX_UPON_OUTCOMEVARCHAR(N)FALSE
    천재지변으로 인해 일부 데이터가 유실되었습니다. 입양을 간 기록은 있는데, 보호소에 들어온 기록이 없는 동물의 ID와 이름을 ID 순으로 조회하는 SQL문을 작성해주세요.

    예시

    예를 들어, ANIMAL_INS 테이블과 ANIMAL_OUTS 테이블이 다음과 같다면 ANIMAL_INS
    ANIMAL_IDANIMAL_TYPEDATETIMEINTAKE_CONDITIONNAMESEX_UPON_INTAKE
    A352713Cat2017-04-13 16:29:00NormalGiaSpayed Female
    A350375Cat2017-03-06 15:01:00NormalMeoNeutered Male
    ANIMAL_OUTS
    ANIMAL_IDANIMAL_TYPEDATETIMENAMESEX_UPON_OUTCOME
    A349733Dog2017-09-27 19:09:00AllieSpayed Female
    A352713Cat2017-04-25 12:25:00GiaSpayed Female
    A349990Cat2018-02-02 14:18:00SpiceSpayed Female
    ANIMAL_OUTS 테이블에서
    • Allie의 ID는 ANIMAL_INS에 없으므로, Allie의 데이터는 유실되었습니다.

    • Gia의 ID는 ANIMAL_INS에 있으므로, Gia의 데이터는 유실되지 않았습니다.

    • Spice의 ID는 ANIMAL_INS에 없으므로, Spice의 데이터는 유실되었습니다.

      따라서 SQL문을 실행하면 다음과 같이 나와야 합니다.

      ANIMAL_IDNAME
      A349733Allie
      A349990Spice
  • -- 코드를 입력하세요
    SELECT o.animal_id, o.name
    from animal_ins i, animal_outs o
    where o.animal_id = i.animal_id(+)
    and sex_upon_intake is null
    order by o.animal_id
  • 다른 사람 답
    • 서브쿼리 이용

      select animal_id,name
      from animal_outs 
      where animal_id not in (select animal_id from animal_ins)
      order by 1 

있었는데요 없었습니다

  • 문제

    문제 설명

    ANIMAL_INS 테이블은 동물 보호소에 들어온 동물의 정보를 담은 테이블입니다. ANIMAL_INS 테이블 구조는 다음과 같으며, ANIMAL_IDANIMAL_TYPEDATETIMEINTAKE_CONDITIONNAMESEX_UPON_INTAKE는 각각 동물의 아이디, 생물 종, 보호 시작일, 보호 시작 시 상태, 이름, 성별 및 중성화 여부를 나타냅니다.
    NAMETYPENULLABLE
    ANIMAL_IDVARCHAR(N)FALSE
    ANIMAL_TYPEVARCHAR(N)FALSE
    DATETIMEDATETIMEFALSE
    INTAKE_CONDITIONVARCHAR(N)FALSE
    NAMEVARCHAR(N)TRUE
    SEX_UPON_INTAKEVARCHAR(N)FALSE
    ANIMAL_OUTS 테이블은 동물 보호소에서 입양 보낸 동물의 정보를 담은 테이블입니다. ANIMAL_OUTS 테이블 구조는 다음과 같으며, ANIMAL_IDANIMAL_TYPEDATETIMENAMESEX_UPON_OUTCOME는 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별 및 중성화 여부를 나타냅니다. ANIMAL_OUTS 테이블의 ANIMAL_ID는 ANIMAL_INS의 ANIMAL_ID의 외래 키입니다.
    NAMETYPENULLABLE
    ANIMAL_IDVARCHAR(N)FALSE
    ANIMAL_TYPEVARCHAR(N)FALSE
    DATETIMEDATETIMEFALSE
    NAMEVARCHAR(N)TRUE
    SEX_UPON_OUTCOMEVARCHAR(N)FALSE
    관리자의 실수로 일부 동물의 입양일이 잘못 입력되었습니다. 보호 시작일보다 입양일이 더 빠른 동물의 아이디와 이름을 조회하는 SQL문을 작성해주세요. 이때 결과는 보호 시작일이 빠른 순으로 조회해야합니다.

    예시

    예를 들어, ANIMAL_INS 테이블과 ANIMAL_OUTS 테이블이 다음과 같다면 ANIMAL_INS
    ANIMAL_IDANIMAL_TYPEDATETIMEINTAKE_CONDITIONNAMESEX_UPON_INTAKE
    A350276Cat2017-08-13 13:50:00NormalJewelSpayed Female
    A381217Dog2017-07-08 09:41:00SickCherokeeNeutered Male
    ANIMAL_OUTS
    ANIMAL_IDANIMAL_TYPEDATETIMENAMESEX_UPON_OUTCOME
    A350276Cat2018-01-28 17:51:00JewelSpayed Female
    A381217Dog2017-06-09 18:51:00CherokeeNeutered Male
    SQL문을 실행하면 다음과 같이 나와야 합니다.
    ANIMAL_IDNAME
    A381217Cherokee
  • -- 코드를 입력하세요
    SELECT i.animal_id, i.name
    from animal_ins i, animal_outs o 
    where i.animal_id = o.animal_id
    and i.datetime > o.datetime
    order by i.datetime

* 오랜 기간 보호한 동물(1)

  • 문제

    문제 설명

    ANIMAL_INS 테이블은 동물 보호소에 들어온 동물의 정보를 담은 테이블입니다. ANIMAL_INS 테이블 구조는 다음과 같으며, ANIMAL_IDANIMAL_TYPEDATETIMEINTAKE_CONDITIONNAMESEX_UPON_INTAKE는 각각 동물의 아이디, 생물 종, 보호 시작일, 보호 시작 시 상태, 이름, 성별 및 중성화 여부를 나타냅니다.
    NAMETYPENULLABLE
    ANIMAL_IDVARCHAR(N)FALSE
    ANIMAL_TYPEVARCHAR(N)FALSE
    DATETIMEDATETIMEFALSE
    INTAKE_CONDITIONVARCHAR(N)FALSE
    NAMEVARCHAR(N)TRUE
    SEX_UPON_INTAKEVARCHAR(N)FALSE
    ANIMAL_OUTS 테이블은 동물 보호소에서 입양 보낸 동물의 정보를 담은 테이블입니다. ANIMAL_OUTS 테이블 구조는 다음과 같으며, ANIMAL_IDANIMAL_TYPEDATETIMENAMESEX_UPON_OUTCOME는 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별 및 중성화 여부를 나타냅니다. ANIMAL_OUTS 테이블의 ANIMAL_ID는 ANIMAL_INS의 ANIMAL_ID의 외래 키입니다.
    NAMETYPENULLABLE
    ANIMAL_IDVARCHAR(N)FALSE
    ANIMAL_TYPEVARCHAR(N)FALSE
    DATETIMEDATETIMEFALSE
    NAMEVARCHAR(N)TRUE
    SEX_UPON_OUTCOMEVARCHAR(N)FALSE
    아직 입양을 못 간 동물 중, 가장 오래 보호소에 있었던 동물 3마리의 이름과 보호 시작일을 조회하는 SQL문을 작성해주세요. 이때 결과는 보호 시작일 순으로 조회해야 합니다.

    예시

    예를 들어, ANIMAL_INS 테이블과 ANIMAL_OUTS 테이블이 다음과 같다면 ANIMAL_INS
    ANIMAL_IDANIMAL_TYPEDATETIMEINTAKE_CONDITIONNAMESEX_UPON_INTAKE
    A354597Cat2014-05-02 12:16:00NormalArielSpayed Female
    A373687Dog2014-03-20 12:31:00NormalRosieSpayed Female
    A412697Dog2016-01-03 16:25:00NormalJackieNeutered Male
    A413789Dog2016-04-19 13:28:00NormalBenjiSpayed Female
    A414198Dog2015-01-29 15:01:00NormalShellySpayed Female
    A368930Dog2014-06-08 13:20:00NormalSpayed Female
    ANIMAL_OUTS
    ANIMAL_IDANIMAL_TYPEDATETIMENAMESEX_UPON_OUTCOME
    A354597Cat2014-05-02 12:16:00ArielSpayed Female
    A373687Dog2014-03-20 12:31:00RosieSpayed Female
    A368930Dog2014-06-13 15:52:00Spayed Female
    SQL문을 실행하면 다음과 같이 나와야 합니다.
    NAMEDATETIME
    Shelly2015-01-29 15:01:00
    Jackie2016-01-03 16:25:00
    Benji2016-04-19 13:28:00
    ※ 입양을 가지 못한 동물이 3마리 이상인 경우만 입력으로 주어집니다
  • 내 답
    1. outer join

      select * 
      from (select i.name, i.datetime
      from animal_ins i, animal_outs o
      where i.animal_id = o.animal_id (+)
      and o.datetime is null
      order by datetime
      )
      where rownum < 4
    2. subquery

      select name, datetime
      from (select *
            from animal_ins
            where animal_id not in (select animal_id
                                      from animal_outs)
            order by datetime)
      where rownum < 4
  • LIMIT 3, FETCH FIRST 3 ROW ONLY 활용하기!

* 상품별 오프라인 매출 구하기

  • 문제

    문제 설명

    다음은 어느 의류 쇼핑몰에서 판매중인 상품들의 상품 정보를 담은 PRODUCT 테이블과 오프라인 상품 판매 정보를 담은 OFFLINE_SALE 테이블 입니다. PRODUCT 테이블은 아래와 같은 구조로 PRODUCT_IDPRODUCT_CODEPRICE는 각각 상품 ID, 상품코드, 판매가를 나타냅니다.
    Column nameTypeNullable
    PRODUCT_IDINTEGERFALSE
    PRODUCT_CODEVARCHAR(8)FALSE
    PRICEINTEGERFALSE
    상품 별로 중복되지 않는 8자리 상품코드 값을 가지며, 앞 2자리는 카테고리 코드를 의미합니다. OFFLINE_SALE 테이블은 아래와 같은 구조로 되어있으며 OFFLINE_SALE_IDPRODUCT_IDSALES_AMOUNTSALES_DATE는 각각 오프라인 상품 판매 ID, 상품 ID, 판매량, 판매일을 나타냅니다.
    Column nameTypeNullable
    OFFLINE_SALE_IDINTEGERFALSE
    PRODUCT_IDINTEGERFALSE
    SALES_AMOUNTINTEGERFALSE
    SALES_DATEDATEFALSE
    동일한 날짜, 상품 ID 조합에 대해서는 하나의 판매 데이터만 존재합니다.

    문제

    PRODUCT 테이블과 OFFLINE_SALE 테이블에서 상품코드 별 매출액(판매가 * 판매량) 합계를 출력하는 SQL문을 작성해주세요. 결과는 매출액을 기준으로 내림차순 정렬해주시고 매출액이 같다면 상품코드를 기준으로 오름차순 정렬해주세요.

    예시

    예를 들어 PRODUCT 테이블이 다음과 같고
    PRODUCT_IDPRODUCT_CODEPRICE
    1A100001115000
    2A10000458000
    3C300000242000
    OFFLINE_SALE 테이블이 다음과 같다면
    OFFLINE_SALE_IDPRODUCT_IDSALES_AMOUNTSALES_DATE
    1122022-02-21
    2122022-03-02
    3332022-05-01
    4212022-05-24
    5122022-07-14
    6212022-09-22
    각 상품 별 총 판매량과 판매가는 다음과 같습니다.
    • PRODUCT_CODE 가 A1000011인 상품은 총 판매량이 6개, 판매가가 15,000원

    • PRODUCT_CODE 가 A1000045인 상품은 총 판매량이 2개, 판매가가 8,000원

    • PRODUCT_CODE 가 C3000002인 상품은 총 판매량이 3개, 판매가가 42,000원

      그러므로 각 상품 별 매출액을 계산하고 정렬하면 결과가 다음과 같이 나와야 합니다.

      PRODUCT_CODESALES
      C3000002126000
      A100001190000
      A100004516000
  • select product_code, (price*amount)sales
    from (select product_id, sum(sales_amount) amount
          from offline_sale
          group by product_id) s, product p 
    where p.product_id = s.product_id 
    order by sales desc, product_code
  • 다른 사람 답
    select p.product_code, (p.price * o.sales_amount) sales
    from offline_sale o, product p 
    where i.product_id = p.product_id 
    group by p.produdct_code
    order by sales desc, b.product_code

String, Date

profile
salami

0개의 댓글