Find the IDs of the employees whose salary is strictly less than$30000and whose manager left the company. When a manager leaves the company, their information is deleted from theEmployeestable, but the reports still have theirmanager_idset to the manager that left.
내용 요약:
매니저가 퇴사하면, Employess 목록에서 사라지지만, 다른 직원의 매니저로서 기존 설정된 기록은 남아 있다.
퇴사하면 기록이 사라진다는 말 때문에, "NULL" 로 표현된 부분을 오해하기가 너무 쉽다.
("NULL"은 퇴사와 관련이 없음)
Table:Employees
+-------------+----------+|Column Name | Type |+-------------+----------+| employee_id |int|| name |varchar|| manager_id |int|| salary |int|+-------------+----------+InSQL, employee_id is the primary key for this table.
This tablecontains information about the employees, their salary, and the ID of their manager. Some employees do not have a manager (manager_id isnull).
Find the IDs of the employees whose salary is strictly less than$30000and whose manager left the company. When a manager leaves the company, their information is deleted from theEmployeestable, but the reports still have theirmanager_idset to the manager that left.
# salary가 3만 보다 작은 employee의 manager_id 선택
WITH cond1 AS (
SELECT manager_id
FROM Employees
WHERE salary <30000
),
# cond1 에서 선택한 manager_id 가 Employees 테이블의 employee_id에 존재하지 않는, cond1의 manager_id 선택
cond2 AS(
SELECTDISTINCT cond1.manager_id
FROM Employees, cond1 # 카타시안 곱 사용금지
WHERE cond1.manager_id NOTIN (SELECT employee_id FROM Employees)
)
# 조건에 맞는 manager_id 만을 최종 선택 후, Employees 테이블에서 해당 manager_id를 가진 employee_id를 선택
# 이 과정에서 Employees 테이블을 다시 이용하므로 salary 값이 3만보다 큰 경우가 생길 수 있어 다시 WHERE 조건에 추가
SELECT Employees.employee_id
FROM Employees
INNERJOIN cond2 ON Employees.manager_id = cond2.manager_id
WHERE Employees.manager_id = cond2.manager_id
AND Employees.salary <30000ORDERBY employee_id
replace, substring, concat, left, right, lower, upper, trim, length, format, instr 정도만 알아도 SQL 데이터 변형에 큰 문제가 없겠지만, Regex 문법 까지 익숙해지면 빠른 전처리에 큰 도움이 될 것 같다.
Write a solution to find the patient_id, patient_name, and conditions of the patients who have Type I Diabetes. Type I Diabetes always starts withDIAB1prefix.
Return the result table inany order.
The result format is in the following example.
Example 1:
Input:
Patients table:
+------------+--------------+--------------+| patient_id | patient_name | conditions |+------------+--------------+--------------+|1| Daniel | YFEV COUGH ||2| Alice |||3| Bob | DIAB100 MYOP ||4| George | ACNE DIAB100 ||5| Alain | DIAB201 |+------------+--------------+--------------+
Output:
+------------+--------------+--------------+| patient_id | patient_name | conditions |+------------+--------------+--------------+|3| Bob | DIAB100 MYOP ||4| George | ACNE DIAB100 |+------------+--------------+--------------+
Explanation: Bob and George both have a condition that starts with DIAB1.
# conditions 열에 'DIAB1'이라는 문자열을 포함하는 모든 행을 선택
SELECT*FROM patients
WHERE conditions REGEXP '\\bDIAB1'
SELECT Prices.product_id
-- ,start_date-- ,end_date-- ,price-- ,SUM(units)-- ,SUM(price*units) AS mutiply_price_units
,COALESCE(ROUND(SUM(price*units)/SUM(units),2),0) AS average_price
FROM Prices
LEFTJOIN UnitsSold ON Prices.product_id = UnitsSold.product_id
WHERE UnitsSold.purchase_date BETWEEN Prices.start_date AND Prices.end_date or UnitsSold.product_id ISNULLGROUPBY product_id
Input:
Movies table:
+-------------+--------------+
| movie_id | title |
+-------------+--------------+
| 1 | Avengers |
| 2 | Frozen 2 |
| 3 | Joker |
+-------------+--------------+
Users table:
+-------------+--------------+
| user_id | name |
+-------------+--------------+
| 1 | Daniel |
| 2 | Monica |
| 3 | Maria |
| 4 | James |
+-------------+--------------+
MovieRating table:
+-------------+--------------+--------------+-------------+
| movie_id | user_id | rating | created_at |
+-------------+--------------+--------------+-------------+
| 1 | 1 | 3 | 2020-01-12 |
| 1 | 2 | 4 | 2020-02-11 |
| 1 | 3 | 2 | 2020-02-12 |
| 1 | 4 | 1 | 2020-01-01 |
| 2 | 1 | 5 | 2020-02-17 |
| 2 | 2 | 2 | 2020-02-01 |
| 2 | 3 | 2 | 2020-03-01 |
| 3 | 1 | 3 | 2020-02-22 |
| 3 | 2 | 4 | 2020-02-25 |
+-------------+--------------+--------------+-------------+
Output:
+--------------+
| results |
+--------------+
| Daniel |
| Frozen 2 |
+--------------+
Explanation:
Daniel and Monica have rated 3 movies ("Avengers", "Frozen 2"and"Joker") but Daniel is smaller lexicographically.
Frozen 2and Joker have a rating average of 3.5in February but Frozen 2 is smaller lexicographically.
-- 1. 가장 많은 수의 영화에 평점 매긴 유저 이름 반환, 동률일경우 알파벳순으르 빠른사람 상위 1명-- 2. 2020년 2월, 평균평점이 가장 높은 영화이름 동률일경우 알파벳순으르 빠른영화 상위 1개-- 3. 위/아래 테이블 병합WITH CTE AS(
SELECT MovieRating.rating
,MovieRating.created_at
,Users.name
,Movies.title
FROM MovieRating
INNERJOIN Movies ON MovieRating.movie_id=Movies.movie_id
INNERJOIN Users ON MovieRating.user_id=Users.user_id
)
(SELECT name AS results
FROM CTE
GROUPBY name
ORDERBYcount(name) DESC, name
LIMIT 1)
UNIONALL
(SELECT title AS results
FROM CTE
WHERE DATE_FORMAT(created_at, "%Y-%m") = "2020-02"
GROUPBY title
ORDERBYAVG(rating) DESC, title
LIMIT 1)
Input:
Activity table:
+-----------+-----------+------------+--------------+
| player_id | device_id | event_date | games_played |
+-----------+-----------+------------+--------------+
| 1 | 2 | 2016-03-01 | 5 |
| 1 | 2 | 2016-03-02 | 6 |
| 2 | 3 | 2017-06-25 | 1 |
| 3 | 1 | 2016-03-02 | 0 |
| 3 | 4 | 2018-07-03 | 5 |
+-----------+-----------+------------+--------------+
Output:
+-----------+
| fraction |
+-----------+
| 0.33 |
+-----------+
Explanation:
Only the player with id 1 logged back in after the first day he had logged in so the answer is 1/3 = 0.33
SELECT ROUND(COUNT(DISTINCT player_id) / (SELECTCOUNT(DISTINCT player_id) FROM Activity), 2) AS fraction
FROM Activity
WHERE (player_id, DATE_SUB(event_date, INTERVAL1DAY))
IN (SELECT player_id
, MIN(event_date) AS first_login
FROM Activity
GROUPBY player_id)
idea
1. WHERE문의 IN 속에, player_id 별 최초접속일을 모아둔다.
2. event_date에서 하루를 뺀 값이 IN 값에 들어 있는 최초접속일과 일치하는 player_id를 찾도록 WHERE문 조건을 최종 작성한다(최초 접속 후 다음날 접속한 기록이 있다면, 해당 접속 일자에서 -1을 빼면 최초접속일이 될 것이다)
# 플레이어의 최초 로그인 날짜 구하기
1) 기본 풀이
SELECT player_id
, MIN(event_date) AS first_login
FROM Activity
GROUPBY player_id
# 플레이어의 최초 로그인 날짜 구하기
2) 윈도우 함수 +WITH 문 활용
WITH login AS
(
SELECTROW_NUMBER() OVER (PARTITIONBY player_id ORDERBY event_date) AS player_login
, player_id
, event_date AS first_login
FROM Activity
)
SELECT player_id
, first_login
FROM login
WHERE player_login =1
사람 수 (people)가 100이상일 때, 3개 이상의 연속되는 "id"값에 대한 행을 모두 조회하는 쿼리 작성
결과값은 "visit_date" 기준으로 오름차순 정렬
문제파악:
일단 visit_date는 정렬 빼고는 신경 쓸 필요는 없을 것 같았고,
우선 사람 수가 100명 이상인 테이블을 걸러낸 결과값을
WITH문으로 테이블을 새롭게 구성한 뒤 쿼리 작성을 시작하면 될 것 같다.
대략적으로 2가지 풀이법이 보인다. 셀프 조인 혹은 윈도우 함수 사용하기
풀이:
1. 'people'이 100 이상인 행들을 걸러냈을 때, id 값의 모양을 예상해본다.
데이터 사이사이에 100보다 낮은 값들이 포함되어 있었을 것이니, 아래 표와 같이 row_number()를 활용해서 강제적으로 맨 위부터 순위를 매긴 후 id 값에서 row_number값을 뺀 차이값 diff를 구하면, 연속되는 id값에서 벗어나는 순간에 diff값은 숫자가 바뀌게 된다.
ex) 아래 표를 예시로 든다면, id_1이 4에서 6으로 변할때, 차이값은 0에서 1로 변한다.
ex), id_2에서 5로 변할때, 차이값은 0에서 2로 변한다.
id_1
row_number
diff_1
id_2
row_number
diff_2
1
1
0
1
1
0
2
2
0
2
2
0
3
3
0
5
3
2
4
4
0
6
4
2
6
5
1
7
5
2
7
6
1
9
6
3
일종의 파티션을 나눈다고 생각하면 된다.
이런식의 계산을 이용하려면, 반드시 id 값을 기준으로 오름차순 정렬이 먼저 이루어져 있어야 한다.
WITH Sorted AS (
SELECT id
, visit_date
, people
, id -ROW_NUMBER() OVER (ORDERBY id) AS diff
FROM Stadium
WHERE people >=100ORDERBY id
)
2. diff를 기준으로 GROUP BY 이후, 행의 갯수 조회
기존 만들어진 WITH문을 그대로 이용해서 SELECT문에는 count(*)을 추가하고, diff 기준으로 groupby, HAVING count(*) >= 3을 조건으로 쿼리를 실행하면 diff의 그룹별 행의 갯수가 표현된다.
WITH Sorted AS (
SELECT id
, visit_date
, people
, id -ROW_NUMBER() OVER (ORDERBY id) AS diff
FROM Stadium
WHERE people >=100ORDERBY id
)
, Ranked AS (
SELECT id
, visit_date
, people
, diff
, COUNT(*) AS consecutive_num
FROM Sorted
GROUPBY diff
HAVINGCOUNT(*) >=3
)
3. 찾아낸 diff를 활용하여 정답 찾기
"consecutive_num" 은 3이상이면 나타나는 값이니 신경 쓸 필요는 없다.
2번의 테스트 케이스에 따르면, diff 가 2인 것이 연속된 id 4개를 가지고 있다는 것이니, 연속되는 id값의 행들만 찾고 싶다면, diff를 기준으로 Sorted 테이블과 inner 조인 시켜주면 된다.
문제에 날짜기준 오름차순 정렬조건도 있지만, id가 커짐에따라 방문 일자도 하루씩 늘어나기 때문.
WITH Sorted AS (
SELECT id
, visit_date
, people
, id -ROW_NUMBER() OVER (ORDERBY id) AS diff
FROM Stadium
WHERE people >=100ORDERBY id
)
, Ranked AS (
SELECT id
, visit_date
, people
, diff
, COUNT(*) AS consecutive_num
FROM Sorted
GROUPBY diff
HAVINGCOUNT(*) >=3
)
SELECT Sorted.id
, Sorted.visit_date
, Sorted.people
FROM Sorted
INNERJOIN Ranked ON Sorted.diff = Ranked.diff
PARTITION BY 이용:
WITH Sorted AS (
SELECT id
, visit_date
, people
, id -ROW_NUMBER() OVER (ORDERBY id) AS diff
FROM Stadium
WHERE people >=100
),
consecutive_count AS (
SELECT id
, visit_date
, people
, diff
, COUNT(*) OVER (PARTITIONBY diff) AS consecutive_num
FROM Sorted
)
SELECT*FROM consecutive_count
ORDERBY id
큰 차이는 없지만, PARTITION BY를 활용하면 더욱 직관적으로 쿼리를 작성할 수 있다.
무엇보다 GROUP BY는 조건에 따른 그룹의 첫번째 행만을 남기고, 이외 행은 다 날리게 되지만 (아래 output케이스는 Ranked 테이블에서 HAVING count(*) >=3 조건만 없다면 count(*) id가 2, 5인 행만 남을 것이다)
PARTITION BY는 조건에 해당하는 모든 id 행을 보여준다.
이후 consecutive_num >=3 인 값들만 찾으면 된다.
또한 Sorted테이블 이후에는, 정렬순서가 유지되지 않을 수도 있기에
+ ORDER BY id 추가해주면 된다.
(*** GROUP BY를 활용하는 경우, 이미 id 기준 오름차순 정렬된 테이블에 inner 조인하는 것이 때문에 따로 추가할 필요는 없다)
1321. Restaurant Growth -> 이전 6일 ~ 당일 amount 합산
# 방문일별 계산
WITH grouped_visit_on AS
(
SELECT visited_on
, SUM(amount) AS amount
FROM Customer
GROUPBY visited_on
)
, visit_7 AS
(
# 방문일별 이전 6일 ~0일 까지 합산 및 AVG 계산, Named windowSELECT visited_on
, SUM(amount) OVER (ORDERBY visited_on ROWSBETWEEN6 PRECEDING AND0 FOLLOWING) AS amount
, ROUND(AVG(amount) OVER (ORDERBY visited_on ROWSBETWEEN6 PRECEDING AND0 FOLLOWING),2) AS average_amount
FROM grouped_visit_on
)
# 최초 구매일로부터 6일 이후의 값들만 출력 ==1월 7일 부터
SELECT visited_on
, amount
, average_amount
FROM visit_7
WHERE visited_on >= (SELECT DATE_ADD(MIN(visited_on), INTERVAL6DAY) FROM customer)
# 1월 7일 ->WHERE 조건절 서브쿼리 삽입
#SELECT DATE_ADD(MIN(visited_on), INTERVAL6DAY
기존에 테이블 조인 방식으로 풀었던 문제이지만, LEAD() 를 활용해서도 풀어볼 수 있었다. 큰 차이는 없지만, 윈도우함수를 활용하는 방법이 조금 더 직관적으로 이해하기 좋았음.
id
NUM
next
afternext
1
1
1
1
2
1
1
2
3
1
2
1
4
2
1
2
5
1
2
2
6
2
2
null
7
2
null
null
1) 윈도우 함수 풀이: LEAD
SELECTDISTINCT l.NUM AS ConsecutiveNums
FROM(
SELECT NUM
, LEAD(NUM,1) OVER (ORDERBY id) AS next
, LEAD(NUM,2) OVER (ORDERBY id ) AS afternext
FROM logs
) l
WHERE l.Num=next AND l.next=l.afternext
2) JOIN : 기존에 풀었던 방식
SELECTDISTINCT l.num AS ConsecutiveNums
FROM logs AS l
INNERJOIN logs AS l_next ON l.id +1= l_next.id
INNERJOIN logs AS l_next2 ON l.id +2= l_next2.id
WHERE l.num = l_next.num AND l_next.num = l_next2.num
DENSE_RANK() OVER (PARTITION BY departmentid ORDER BY salary DESC)
처럼 PARTITION BY와 ORDER BY를 함께 쓸 수 있다는 점을 알게되었음.
+ 순위 정하기 함수의 차이점 - ROW_NUMBER(), RANK(), DENSE_RANK()
SELECT val
, ROW_NUMBER() OVER (ORDERBY val) AS row_number
, RANK() OVER (ORDERBY val) AS rank
, DENSE_RANK() OVER (ORDERBY val) AS dense_rank
FROM Sample;
- row_number는 어떻게 해서든 123456 으로 순위 매김 (중복포함)
- rank는 동일 값에 같은 등수를 부여, 공동 등수의 갯수를 고려한, 다음 순위를 매김. 아래 예시의 경우에는 2등과 5등은 스킵한 뒤 순위를 매김
- dense_rank는 공동 등수를 하나로 보고 다음 순위를 매김
VALUE
ROW_NUMBER()
RANK()
DENSE_RANK()
1
1
1
1
1
2
1
1
2
3
3
2
3
4
4
3
3
5
4
3
4
6
6
4
문제:
A company's executives are interested in seeing who earns the most money in each of the company's departments. A high earner in a department is an employee who has a salary in the top three unique salaries for that department.
Write a solution to find the employees who are high earners in each of the departments.
Return the result table in any order.
요약: # 각 부서에서 직원들의 급여 순으로, 부서별 1위 2위 3위 찾기 (급여가 같은 사람이 2명이상이라면 모두 포함시키기)
문제파악:
1. Foreign key가 id 이므로 Employee와 Department의 id로 테이블 조인
2. 급여가 같은 직원들의 경우에도 모두 찾아내야 하므로 dense_rank 활용
3. 파트별로 순위 매기기 위해서 PARTITION BY ~ 활용
4. WHERE 조건 활용하기 위해선, 테이블 자체를 새로 생성해야 함.
풀이:
난이도가 hard 이지만 어렵진 않았다.
전체적인 틀은 같지만,
FROM 절에 넣어도 되고 WITH 절에 넣어도 괜찮을 것 같다.
1) WITH절 활용
WITH COUNTER AS (
SELECT Dep.name DepName
, Emp.name EmpName
, salary
, DENSE_RANK() OVER (PARTITIONBY departmentid ORDERBY salary DESC) AS denserank
FROM Employee AS Emp
INNERJOIN Department AS Dep ON Dep.id = Emp.departmentId
)
SELECT DepName AS Department
, EmpName AS Employee
, salary
FROM COUNTER
WHERE denserank <=3
2) FROM절 서브쿼리 활용
SELECT t.department
, t.employee
, t.salary
FROM(
SELECT department.name AS dapartment
, employee.name AS employee
, employee.salary
, DENSE_RANK() OVER (PARTITIONBY departmentid ORDERBY salary DESC) AS dr
FROM Employee
INNERJOIN dapartment ON employee.departmentId = dapartment.id
) t
WHERE t.dr <=3
이제 까진 주로 숫자에 대한 계산을 위해 SUM(price*moment) 의 정도로 활용해왔지만,
이번 문제 풀이를 통해,
컬럼 내 존재하는 특정 문자열 데이터의 갯수를 아래 표현과 처럼 셀 수도 있었다.
SUM(status != 'completed') >>> status 컬럼 중 "completed"가 아닌 데이터의 총 갯수
COUNT(status) >>> status 컬럼의 데이터 갯수 총합
문제:
The cancellation rate is computed by dividing the number of canceled (by client or driver) requests with unbanned users by the total number of requests with unbanned users on that day.
Write a solution to find the cancellation rate of requests with unbanned users (both client and driver must not be banned) each day between "2013-10-01" and "2013-10-03". Round Cancellation Rate to two decimal points.
Return the result table in any order.
문제파악:
10/1 ~ 10/3 까지 일자별 여행 취소율을 구하는 문제이다.
취소율은
dividing the number of canceled (by client or driver) requests with unbanned users by the total number of requests with unbanned users on that day.
즉 금지되지 않은 이용자와의 전체 취소요청 건수 / 당일 금지되지 않은 이용자와의 총 요청 건수 로 구한다.
쿼리 작성 중, 테스트 케이스가 통과 안되는 건이 하나 있었다.
테스트 케이스가 참 이상했다.
저 Input대로 라면, 전체 요청건수는 1개, 그중 취소 요청건수는 1개라 취소율은 100%여야 함에도 불구하고,
Expected에는 아예 값 자체가 보이지 않았다....
그래서 그냥 취소율이 1이 되는 경우는 아예 발생하지 않도록 쿼리를 일부 수정했다.
1. banned 컬럼 값이 No 인 값들의 user_id만 찾을 수 있도록 서브쿼리 작성
2. 만들어 둔 서브 쿼리 자체를 WHERE 조건으로 활용
- clinet_id, driver_id 의 컬럼 값들 중, 서브쿼리로 만들어지는 user_id와 일치하는 조건에 만족하는 SELECT 값을 찾을 수 있도록!
4. 날짜 별 취소율을 구하는 것이기 때문에 Group by를 request_at기준으로 지정
5. 취소율을 구할 수 있도록, 완료건이 아닌 취소건의 갯수/ status의 총 갯수 를 구한 뒤, Round 활용해서 소수점 처리
6. 정렬조건은 필요없다고 나와있음
- With 구문을 활용하면 서브쿼리를 2번 적지 않을 수 있다.
- Alias 지정할 때, 중간에 빈칸이 있으면 ' ' 으로 묶어줘야 한다.
풀이:
SELECT request_at ASDAY
, ROUND(SUM(status !='completed') /COUNT(status),2) AS'Cancellation Rate'FROM Trips
WHERE client_id IN (
SELECT users_id
FROM Users
WHERE banned ='NO'
)
AND driver_id IN (
SELECT users_id
FROM Users
WHERE banned ='No'
)
AND request_at BETWEENDATE("2013-10-01") ANDDATE ("2013-10-03")
GROUPBY request_at
반복적으로 필요하지 않고 해당 함수가 꼭 필요하지 않음에도, With 구문을 습관적으로 활용해서 문제를 풀곤 했었다.
덕분에 이해하기는 편했으나, 코드 줄 수가 너무 길어지는 단점이 있었다.
결과적으론... 이해하는 것이 코드를 작성한 나만 쉽지 않을까? 생각들었다.
DA가 sql 코드 성능을 신경 쓸 필요는 별로 없겠지만, 그래도 기존에 해왔던 파이썬이나 자바처럼 좀 더 컴팩트하게 작성하면 좋지 않을까?
앞으로는 가독성도 가독성이지만, 최대한 컴팩트하게 작성해보고자 한다.
- IF구문의 새로운 활용법:
* 기본적으로 IF(조건,True값,False값) 의 형태로 작성되지만, IF(컬럼 IN (원하는 서브쿼리),True,False) 의 형태로도 작성될 수 있다.
- GROUP BY 특성:
* GROUP BY를 MAX()와 같은 함수와 사용할 때, run을 눌러서 나타나는 테이블은 컬럼들이 MAX()함수로 계산된 컬럼을 제외하고 다른 컬럼들은 서로 관계성을 지니지 않음.
* 보통 원본 테이블에서 보여지는 그룹 별 첫번째 값들이 보여지게 되어 있음.
문제:
CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블에서
2022년 10월 16일에 대여 중인 자동차인 경우 '대여중' 이라고 표시하고,
대여 중이지 않은 자동차인 경우 '대여 가능'을 표시하는 컬럼(컬럼명: AVAILABILITY)을 추가하여
자동차 ID와 AVAILABILITY 리스트를 출력하는 쿼리 작성
이때 반납 날짜가 2022년 10월 16일인 경우에도 '대여중'으로 표시
결과는 자동차 ID를 기준으로 내림차순 정렬
문제파악:
2022-10-16일에 대여가 가능한지의 여부를 찾는 문제
CAR_ID를 고유값으로 뽑아내야 해서 많이 헤맷다.
위 예시에서, CAR_ID의 2,3번째 데이터는 대여시작일과 대여종료일 사이에 10-16가 걸쳐있어서
결과테이블에서는'대여중'으로 표시되어야 하고 나머지 데이터는 표현되지 않아야 한다.
IF구문 내, 서브쿼리를 활용해서,
조건에 해당되는 값이, 서브쿼리로 인해 뽑힌 데이터 내에단 한개라도 들어있다면, '대여중',
존재하지 않는다면, '대여 가능'으로 표시되도록 작성 후 alias 를 지정한 뒤, 이를 SELECT절에 CAR_ID 컬럼과 함께 삽입했다.
이로써 조건에 맞는 CAR_ID와, 대여 여부를 판단한 AVAILABILITY를 테이블에서 확인할 수 있다.
풀이:
SELECTDISTINCT CAR_ID
, IF(CAR_ID IN(SELECT CAR_ID
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE'2022-10-16'BETWEEN START_DATE AND END_DATE),'대여중','대여 가능') AS AVAILABILTIY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
ORDERBY CAR_ID DESC
보호소를 나갈 당시에는 중성화된 동물의 아이디와 생물 종, 이름을 조회하는 아이디 순으로 조회하는 쿼리 작성.
즉, 들어올 땐, 중성화X, 나갈땐 중성화O 에 해당하는 데이터를 찾으면 된다.
문제파악:
처음 문제 딱 보고, 보호소에서 나가는 동물 중에 중성화 안된 동물이 있는지 궁금해서 찾아보니 있었다.
## 보호소에서 나가는 동물 중, 중성화 안된 동물 2마리 확인
SELECT * FROM ANIMAL_OUTS WHERE SEX_UPON_OUTCOME LIKE 'Intact%'
결국은 들어올 때의 SEX_UPON_INTAKE 컬럼은 "Intacts%" 이고,
동시조건으로 나갈 때의 SEX_UPON_OUTCOME 컬럼은 "Sprayed% 혹은 "Neutral%" 인 데이터를 찾으면 된다.
ANIMAL_ID 기준으로 테이블 2개 조인 후, WHERE 조건에 위의 2개 항목 엮어준 뒤 ORDER BY 까지 작성해주면 된다.
풀이:
보호소에서 나가는 동물 중, 중성화 안된 동물 2마리 확인
SELECT*FROM ANIMAL_OUTS
WHERE SEX_UPON_OUTCOME LIKE'Intact%'
찾는 데이터: 들어올 땐, 중성화X, 나갈땐 중성화 O
SELECT INS.ANIMAL_ID
, INS.ANIMAL_TYPE
, INS.NAME
# , SEX_UPON_INTAKE
# , SEX_UPON_OUTCOME
FROM ANIMAL_INS AS INS
INNERJOIN ANIMAL_OUTS AS OUTS ON INS.ANIMAL_ID = OUTS.ANIMAL_ID
WHERE SEX_UPON_INTAKE LIKE'Intact%'AND (SEX_UPON_OUTCOME LIKE'Spayed%'OR SEX_UPON_OUTCOME LIKE'Neutered%')
ORDERBY ANIMAL_ID
혹은 AND SEX_UPON_OUTCOME NOTLIKE'Intact%'도 가능할 것 같다.
SELECT CATEGORY
,PRICE AS MAX_PRICE
,PRODUCT_NAME
FROM FOOD_PRODUCT
WHERE PRICE IN
(
SELECTMAX(PRICE)
FROM FOOD_PRODUCT
GROUPBY CATEGORY
)
AND CATEGORY IN ('과자', '국', '김치', '식용유')
ORDERBY MAX_PRICE DESC