001. 3월에 태어난 여성 회원 목록 출력하기 / 002. 재구매가 일어난 상품과 회원 리스트 구하기
SELECT MEMBER_ID, MEMBER_NAME, GENDER, DATE_FORMAT(DATE_OF_BIRTH, "%Y-%m-%d") AS DATE_OF_BIRTH
FROM MEMBER_PROFILE
WHERE TLNO IS NOT NULL AND MONTH(DATE_OF_BIRTH) = 3 AND GENDER = "W"
ORDER BY MEMBER_ID
SELECT USER_ID, PRODUCT_ID
FROM ONLINE_SALE
GROUP BY USER_ID, PRODUCT_ID
HAVING COUNT(*) > 1
ORDER BY USER_ID ASC, PRODUCT_ID DESC
✨
(1) DATE_FORMAT()으로 %Y-%m-%d로 나타내기
(2) MONTH(DATE_OF_BIRTH) = 3으로 MONTH 함수로 3임을 나타내기
✨
** FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
: SQL은 위 절 순서로 진행되기 때문에 먼저 FROM 테이블에서 WHERE 조건문으로 알맞는 레코드를 뽑는다. 그 다음, GROUP BY로 USER_ID, PRODUCT_ID 순서로 그룹화 진행 뒤, COUNT(*) > 1인 경우, 즉 동일한 회원이 동일한 상품을 구매한 경우만 뽑는다. 그 다음 SELECT문으로 나타낼 칼럼을 고르고, ORDER BY로 첫 순서부터 칼럼 순서 표현.
003. 업그레이드 된 아이템 구하기
SELECT ITEM_ID, ITEM_NAME, RARITY
FROM ITEM_INFO
WHERE ITEM_ID IN (SELECT A.ITEM_ID
FROM ITEM_INFO I, ITEM_TREE A
WHERE I.ITEM_ID = A.PARENT_ITEM_ID AND I.RARITY = 'RARE')
ORDER BY ITEM_ID DESC;
✨
(1) 먼저 ITEM_INFO와 ITEM_TREE 테이블을 연결해야 하므로 FROM ITEM_INFO I, ITEM_TREE A. WHERE I.ITEM_ID = A.PARENT_ITEM_ID
(2) RARITY 값이 RARE여야 하므로 I.RARITY = 'RARE'
(3) 그 때의 A 테이블의 ITEM_ID를 가져온다.
(4) 해당 ITEM_ID를 중첩해서 큰 WHERE 문의 조건으로 넣고 큰 SQL문을 돌린다.
004. 조건에 맞는 개발자 찾기
SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS
WHERE SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE NAME = 'Python') != 0 OR SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE NAME = 'C#') != 0
ORDER BY ID;
✨
(1) Python을 가진 개발자를 찾는 법은 Python code를 SKILLCODE에서 가져와서 해당 코드와 각 개발자의 SKILL_CODE와 & 연산 진행해서 0이 아닌 결과가 나온다면 Python 지식 보유함을 알 수 있다(프로그래머스 SQL 특정 형질을 가지는 대장균 찾기 문제 풀이 참고). 이 때 0이 아닌 결과는 곧 조건 자체가 True임을 뜻하므로 != 0 없이 써도 된다.
005. 특정 물고기를 잡은 총 수 구하기
SELECT COUNT(*) AS FISH_COUNT
FROM FISH_INFO
WHERE FISH_TYPE IN (SELECT B.FISH_TYPE
FROM FISH_INFO A, FISH_NAME_INFO B
WHERE A.FISH_TYPE = B.FISH_TYPE AND B.FISH_NAME IN ('BASS', 'SNAPPER'))
✨
(1) 두 테이블을 연결해서 BASS, SNAPPER의 개수를 출력. 두 테이블 공통 부분 FISH_TYPE을 WHERE문에 넣고 IN () 안에 SELECT FISH_TYPE을 넣어 두 테이블 연결. SELECT문 중첩으로 두 테이블 연결 가능
006. 부모의 형질을 모두 가지는 대장균 찾기
SELECT A.ID, A.GENOTYPE, B.GENOTYPE AS PARENT_GENOTYPE
FROM ECOLI_DATA A, ECOLI_DATA B
WHERE A.PARENT_ID = B.ID
AND B.GENOTYPE & A.GENOTYPE = B.GENOTYPE
ORDER BY ID
✨
(1) 두 동일 테이블을 동시에 연결하기 위해 FROM에 동일 테이블 명에 별칭만 다르게 설정
(2) A를 child, B를 parent table이라 설정하고 두 테이블 연결을 위해 A.PARENT_ID = B.ID
(3) A 입장에서 A의 parent 형질, 즉 B의 GENOTYPE을 모두 A가 가질려면 A.GENOTYPE & B.GENOTYPE 결과 B의 GENOTYPE이 되어야 한다! ex) parent가 0101이고, child가 1101이라면 0101 & 1101 했을 때 0101로 parent의 형질을 모두 갖게 되는 지의 유무는 parent 자체의 결과로 알 수 있다.
007. 가격이 제일 비싼 식품의 정보 출력하기 / 008. 최솟값 구하기 / 009. 동물 수 구하기
SELECT PRODUCT_ID, PRODUCT_NAME, PRODUCT_CD, CATEGORY, PRICE
FROM FOOD_PRODUCT
WHERE PRICE IN (SELECT MAX(PRICE) FROM FOOD_PRODUCT)
SELECT DATETIME AS '시간'
FROM ANIMAL_INS
WHERE DATETIME IN (SELECT MIN(DATETIME) FROM ANIMAL_INS)
SELECT COUNT(*)
FROM ANIMAL_INS;
✨
(1) SELECT문 중첩으로 WHERE PRICE IN () 내부에 SELECT문을 또 넣어서 MAX(PRICE)와 WHERE의 PRICE 같게 한 뒤 SELECT
(2) 두번째 문제도 마찬가지. 가장 먼저 들어온 시간은 MIN(DATETIME) 돌리기
010. 중복 제거하기 / 011. 조건에 맞는 아이템들의 가격의 총합 구하기
SELECT COUNT(DISTINCT NAME)
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
SELECT SUM(PRICE) AS TOTAL_PRICE
FROM ITEM_INFO
WHERE RARITY = 'LEGEND'
✨
(1) 중복되는 이름은 하나로 치므로 DISTINCT 키워드 사용해서 중복 제거
012. 연도별 대장균 크기의 편차 구하기
SELECT
YEAR(DIFFERENTIATION_DATE) AS YEAR,
(
SELECT MAX(ED.SIZE_OF_COLONY)
FROM ECOLI_DATA AS ED
WHERE YEAR = YEAR(ED.DIFFERENTIATION_DATE)
) - SIZE_OF_COLONY AS YEAR_DEV,
ID
FROM ECOLI_DATA
ORDER BY YEAR, YEAR_DEV
✨
(1) 먼저 편차를 구하기 위해서는 각 year의 최댓값을 구해야 하므로 WHERE문으로 먼저 동일 YEAR 데이터 분류한 다음, 해당 row들 중 MAX(ED.SIZE_OF_COLONY)를 선택, 그리고 해당 최댓값에서
(2) 현재 SIZE_OF_COLONY를 뺀 결과를 YEAR_DEV로 설정
(3) YEAR로 오름차순 한 뒤, 동일 YEAR의 경우 YEAR_DEV로 오름차순 시 위와 같이 ORDER_BY에 두 컬럼 이름 연속해서 ,으로 연결
013. 자동차 종류별 특정 옵션이 포함된 자동차 수 구하기
SELECT CAR_TYPE, COUNT(CAR_ID) AS CARS
FROM CAR_RENTAL_COMPANY_CAR
WHERE OPTIONS LIKE '%가죽시트%' OR OPTIONS LIKE '%열선시트%' OR OPTIONS LIKE '%통풍시트%'
GROUP BY CAR_TYPE
ORDER BY CAR_TYPE
✨
** IN 연산자가 아니라 LIKE를 사용해야 한다. 가죽시트, 열선시트, 통풍시트 이렇게 3개 중 적어도 1개 이상이 문자열로 '포함'되어 있는 지의 여부를 묻는 것이기 때문 (주의)
* GROUP BY로 묶은 다음, COUNT() 집계 함수로 해당 차 종류별 조건을 만족하는 차의 대수를 CARS 칼럼으로 출력
014. 성분으로 구분한 아이스크림 총 주문량 / 015. 진료과별 총 예약 횟수 출력하기
SELECT B.INGREDIENT_TYPE, SUM(A.TOTAL_ORDER) AS TOTAL_ORDER
FROM FIRST_HALF AS A JOIN ICECREAM_INFO AS B ON A.FLAVOR = B.FLAVOR
GROUP BY B.INGREDIENT_TYPE
ORDER BY TOTAL_ORDER ASC
SELECT MCDP_CD AS '진료과코드', COUNT(*) AS '5월예약건수'
FROM APPOINTMENT
WHERE YEAR(APNT_YMD) = '2022' AND MONTH(APNT_YMD) = '5'
GROUP BY MCDP_CD
ORDER BY COUNT(*), MCDP_CD
✨
(1) 먼저 두 테이블 JOIN 진행하고
(2) INGREDIENT_TYPE으로 GROUP BY해서 총 주문량이므로 SUM()으로 표시하고,
(3) 마지막으로 ORDER BY로 SELECT로 만든 TOTAL_ORDER 기준 정렬 진행
✨
(1) 먼저 WHERE문으로 2022년 5월인 데이터만 추출
(2) GROUP BY문으로 MCDP_CD로 그룹화
(3) 그룹화한 내의 데이터 개수로 COUNT(*) 및 MCDP_CD SELECT
(4) 마지막 ORDER BY까지 완료
016. 고양이와 개는 몇 마리 있을까
SELECT ANIMAL_TYPE, COUNT(*) AS count
FROM ANIMAL_INS
WHERE ANIMAL_TYPE IN ('Cat', 'Dog')
GROUP BY ANIMAL_TYPE
ORDER BY ANIMAL_TYPE ASC
✨
(1) where문으로 Cat과 Dog만 필터링
(2) 그 다음 Cat별, Dog 별로 GROUP BY
(3) SELECT로 COUNT(*) 활용하여 각 그룹별 데이터 개수 출력
(4) ORDER BY로 ANIMAL_TYPE ASC 진행하여 Cat 먼저 출력, 그 다음 Dog 출력
017. 동명 동물 수 찾기 / 018. 입양 시각 구하기(1)
SELECT NAME, COUNT(*) AS COUNT
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
GROUP BY NAME
HAVING COUNT(*) > 1
ORDER BY NAME
✨
(1) WHERE문으로 이름이 없는 동물은 제외
(2) NAME으로 GROUP BY 진행 후, HAVING절을 사용해 두 번 이상 쓰인 이름에서 그룹화한 결과를 필터링
(3) SELECT로 표현하고, ORDER BY로 정렬
SELECT HOUR(DATETIME), COUNT(*) AS COUNT
FROM ANIMAL_OUTS
WHERE 9 <= HOUR(DATETIME) AND HOUR(DATETIME) <= 19
GROUP BY HOUR(DATETIME)
ORDER BY HOUR(DATETIME)
✨
(1) WHERE문으로 9시부터 19시까지의 데이터 추출
(2) GROUP BY로 HOUR() 기준 그룹화
(3) HOUR(DATETIME), COUNT(*) 그룹 내의 데이터 개수 COUNT로 SELECT
(4) ORDER BY로 HOUR 순 정렬
019. 가격대별 상품 개수 구하기 / 020. 조건에 맞는 사원 정보 조회하기
SELECT TRUNCATE(PRICE, -4) AS PRICE_GROUP, COUNT(*) AS PRODUCTS
FROM PRODUCT
GROUP BY TRUNCATE(PRICE, -4)
ORDER BY PRICE_GROUP
✨
(1) truncate(price, -4)로 15000은 10000으로 맨 앞의 자리 숫자만 남기고 나머지 숫자 모두 0으로 설정.
SELECT SUM(SCORE) AS SCORE, B.EMP_NO, B.EMP_NAME, B.POSITION, B.EMAIL
FROM HR_DEPARTMENT AS A JOIN HR_EMPLOYEES AS B JOIN HR_GRADE AS C ON A.DEPT_ID = B.DEPT_ID AND B.EMP_NO = C.EMP_NO
GROUP BY YEAR, EMP_NO
HAVING C.YEAR = '2022'
ORDER BY SUM(SCORE) DESC
LIMIT 1
✨
(1) GROUP BY를 YEAR, EMP_NO로 두 컬럼으로 세부 그룹화
(2) 그 다음 HAVING 절로 2022년인 경우만 추출
(3) ORDER BY SUM(SCORE)로, 나온 SCORE 값의 합을 기준 내림차순 정렬
(4) LIMIT 1으로 맨 위의 최댓값만 추출
021. 노선별 평균 역 사이 거리 조회하기 / 022. 물고기 종류 별 잡은 수 구하기
SELECT ROUTE, CONCAT(ROUND(SUM(D_BETWEEN_DIST),1),'km') AS TOTAL_DISTANCE, CONCAT(ROUND(AVG(D_BETWEEN_DIST), 2), 'km') AS AVERAGE_DISTANCE
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY ROUND(SUM(D_BETWEEN_DIST),1) DESC
✨
(1) 소수 둘째 자리에서 반올림은 ROUND(~,2) / 소수 셋째 자리에서 반올림은 ROUND(~,3). 그리고 km 붙이기는 CONCAT(,'km') 활용
(2) 숫자 기준 내림차순 진행이므로 위 TOTAL_DISTANCE는 문자열이기 때문에 숫자로만 구한 ROUND() 결과를 가지고 DESC 진행
SELECT COUNT(*) AS FISH_COUNT, B.FISH_NAME
FROM FISH_INFO AS A JOIN FISH_NAME_INFO AS B ON A.FISH_TYPE = B.FISH_TYPE
GROUP BY B.FISH_NAME
ORDER BY COUNT(*) DESC
✨
*** GROUP BY가 들어간 경우, SELECT문에서 고르는 COLUMN은 집계함수, GROUP BY로 들어간 COLUMN 이름만 가능하다. 따라서 GROUP BY로 그룹화할 COLUMN이 무엇인지 반드시 확인
023. 월별 잡은 물고기 수 구하기 / 024. NULL 처리하기
SELECT COUNT(*) AS FISH_COUNT, MONTH(TIME) AS MONTH
FROM FISH_INFO
GROUP BY MONTH(TIME)
ORDER BY MONTH(TIME) ASC
SELECT ANIMAL_TYPE, ifnull(NAME, 'No name') AS NAME, SEX_UPON_INTAKE
FROM ANIMAL_INS
ORDER BY ANIMAL_ID
✨
ifnull() 함수를 사용해서, NULL일 경우 대체할 데이터를 두 번째 인자로 쓴다.
025. ROOT 아이템 구하기 / 026. 조건에 맞는 저자와 도서 리스트 출력하기
SELECT A.ITEM_ID, A.ITEM_NAME
FROM ITEM_INFO AS A JOIN ITEM_TREE AS B ON A.ITEM_ID = B.ITEM_ID
WHERE B.PARENT_ITEM_ID IS NULL
ORDER BY A.ITEM_ID ASC
✨
** IS NULL이라 해야 실제 데이터 NULL인 행만 SELECT 된다. 만약 = 'NULL'이라 하면 실제 NULL이 아니라 값이 0인 행만 SELECT 된다.
SELECT A.BOOK_ID, B.AUTHOR_NAME, DATE_FORMAT(A.PUBLISHED_DATE, "%Y-%m-%d") AS PUBLISHED_DATE
FROM BOOK AS A INNER JOIN AUTHOR AS B ON A.AUTHOR_ID = B.AUTHOR_ID
WHERE A.CATEGORY = '경제'
ORDER BY PUBLISHED_DATE ASC
✨
* DATE_FORMAT()을 활용하여 %Y-%m-%d 형태로 표현해야 한다. %M이 아니라 %m, %D가 아니라 %d인 점 주의
027. 상품 별 오프라인 매출 구하기
SELECT A.PRODUCT_CODE AS PRODUCT_CODE, SUM(SALES_AMOUNT) * A.PRICE AS SALES
FROM PRODUCT AS A JOIN OFFLINE_SALE AS B ON A.PRODUCT_ID = B.PRODUCT_ID
GROUP BY A.PRODUCT_CODE
ORDER BY SALES DESC, A.PRODUCT_CODE ASC
✨
* SUM(SALES_AMOUNT) * A.PRICE인, 즉 판매가 * 판매량의 합계를 새롭게 SALES 칼럼으로 생성
* SELECT 문 진행 후 ORDER BY문 진행하므로 ORDER BY SALES라고 새롭게 만든 컬럼 이름 써도 가능함
028. 자동차 평균 대여 기간 구하기
SELECT CAR_ID, ROUND(AVG(DATEDIFF(END_DATE, START_DATE) + 1),1) AS AVERAGE_DURATION
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP BY CAR_ID
HAVING AVG(DATEDIFF(END_DATE, START_DATE) + 1) >= 7
ORDER BY AVERAGE_DURATION DESC, CAR_ID DESC
✨
* DATEDIFF()를 활용하여 두 날짜 사이의 날짜를 구할 수 있다. 다만, 하루 날짜 포함해야만 앞과 뒤의 날짜 모두 포함되므로 + 1 필수.
* HAVING 절 사용해서 AVG(DATEDIFF()) 결과로 7일 이상인 경우만 그룹화 진행
029. 조건에 부합하는 중고거래 상태 조회하기
SELECT BOARD_ID, WRITER_ID, TITLE, PRICE,
CASE
WHEN STATUS = 'SALE' THEN '판매중'
WHEN STATUS = 'RESERVED' THEN '예약중'
ELSE '거래완료'
END AS STATUS
FROM USED_GOODS_BOARD
WHERE CREATED_DATE = '2022-10-05'
ORDER BY BOARD_ID DESC
✨
CASE ~ WHEN THEN ~ ELSE ~ END AS 문으로 SQL IF문을 사용하여 직접 조건별로 칼럼 내용 설정
030. 루시와 엘라 찾기 / 031. 이름에 el이 들어가는 동물 찾기
SELECT ANIMAL_ID, NAME, SEX_UPON_INTAKE
FROM ANIMAL_INS
WHERE NAME IN ('Ella', 'Lucy', 'Pickle', 'Rogan', 'Sabrina', 'Mitty')
ORDER BY ANIMAL_ID
SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
WHERE NAME LIKE '%EL%' AND ANIMAL_TYPE = 'Dog'
ORDER BY NAME
032. 중성화 여부 파악하기 / 033. 카테고리 별 상품 개수 구하기
SELECT ANIMAL_ID, NAME,
CASE WHEN SEX_UPON_INTAKE LIKE '%Neutered%' OR SEX_UPON_INTAKE LIKE '%Spayed%' THEN 'O'
ELSE 'X'
END AS '중성화'
FROM ANIMAL_INS
SELECT SUBSTR(PRODUCT_CODE,1,2) AS CATEGORY, COUNT(*) AS PRODUCTS
FROM PRODUCT
GROUP BY SUBSTR(PRODUCT_CODE,1,2)
ORDER BY CATEGORY ASC
✨
(1) SUBSTR(X,1,2)라면 주어진 X라는 문자열의 첫번째부터 두번째 문자까지 추출. 추출된 두 문자를 CATEGORY로 만든다.
034. DATETIME에서 DATE로 형 변환 / 035. 연도 별 평균 미세먼지 농도 조회하기
SELECT ANIMAL_ID, NAME, DATE_FORMAT(DATETIME, "%Y-%m-%d") AS '날짜'
FROM ANIMAL_INS
ORDER BY ANIMAL_ID
SELECT YEAR(YM) AS 'YEAR', ROUND(AVG(PM_VAL1),2) AS 'PM10', ROUND(AVG(PM_VAL2),2) AS 'PM2.5'
FROM AIR_POLLUTION
WHERE LOCATION2 = '수원'
GROUP BY YEAR(YM)
ORDER BY YEAR(YM) ASC
036. 분기별 분화된 대장균의 개체 수 구하기
SELECT CONCAT(CEIL(MONTH(DIFFERENTIATION_DATE) / 3), 'Q') AS QUARTER, COUNT(*) AS ECOLI_COUNT
FROM ECOLI_DATA
GROUP BY QUARTER
ORDER BY QUARTER
✨
* CEIL(MONTH(~)/3)으로 분기 수를 구할 수 있다. 그리고 SELECT로 정한 QUARTER 새로운 칼럼을 가지고 GROUP BY에 적용 가능하다. (반드시 기억!)
'Database > SQL' 카테고리의 다른 글
✈️ SQL Programmers Level 1 - 27 Solved (3) | 2024.10.17 |
---|---|
why SQL? & Relational Databases (0) | 2022.03.30 |
댓글