SQL 문제풀이 복습
문제 링크
모든 경우의 수를 다 구해놓고 join해야 하기 때문에
이 문제만큼은 서브쿼리로 해결하기가 너무 복잡해질 듯해서 cte로 풀었다.
1트(7/25) 때도 cte를 쓰긴 했는데
그 때는 불필요하게 한 단계를 더 추가했었던 거 같다.
WITH p
AS (SELECT 'IOS' AS "platform"
UNION
SELECT 'Android'
UNION
SELECT 'Web'),
e
AS (SELECT 'Reading' AS "experiment_name"
UNION
SELECT 'Sports'
UNION
SELECT 'Programming'),
cte
AS (SELECT *
FROM p,
e)
SELECT cte.platform,
cte.experiment_name,
Count(e2.experiment_id) AS "num_experiments"
FROM cte
LEFT JOIN experiments e2
ON cte.platform = e2.platform
AND cte.experiment_name = e2.experiment_name
GROUP BY 1,
2;
문제 링크
1트(7/26)와 거의 비슷하게 풀었다.
차이가 있다면 1트 때는 experience별로 숫자를 세는 부분까지
cte로 만들어서 마지막에 결과를 합쳤다면
이번에는 cte 숫자는 줄이되 마지막에 join을 해서 직접 숫자를 구했다는 점.
senior를 먼저 최대로 채용하고
남은 예산으로 junior를 최대로 채용해야 하기 때문에
window함수와 서브쿼리 활용은 필수였던 것 같다. (특히 sum over)
WITH SENIOR
AS (SELECT employee_id AS "id_senior",
pay_senior
FROM (SELECT employee_id,
salary,
Sum(salary)
OVER(
ORDER BY salary, employee_id ASC) AS "pay_senior"
FROM Candidates
WHERE experience = 'Senior') se
WHERE pay_senior <= 70000),
JUNIOR
AS (SELECT employee_id AS "id_junior"
FROM (SELECT employee_id,
salary,
Sum(salary)
OVER(
ORDER BY salary, employee_id ASC) AS "pay_junior"
FROM Candidates
WHERE experience = 'Junior') ju
WHERE pay_junior < 70000 - (SELECT IFNULL(Max(pay_senior), 0)
FROM SENIOR))
SELECT t.experience,
Count(id) AS "accepted_candidates"
FROM (SELECT 'Senior' AS "experience"
UNION
SELECT 'Junior') t
LEFT JOIN (SELECT 'Senior' AS "experience",
id_senior AS "id"
FROM SENIOR
UNION ALL
SELECT 'Junior' AS "experience",
id_junior
FROM JUNIOR) a
ON t.experience = a.experience
GROUP BY 1;
문제 링크
윗 문제랑 모든 게 다 똑같은데
마지막에 그냥 employee_id만 합쳐서 보여주면 되는 문제.
해서 본 쿼리 말고는 변한 게 없다.
집계함수를 써서 숫자를 세는 게 조금 더 복잡도가 높은데
왜 2번째 문제가 난이도가 더 쉬워졌는지 모르겠네🤔
WITH SENIOR
AS (SELECT employee_id AS "id_senior",
pay_senior
FROM (SELECT employee_id,
salary,
Sum(salary)
OVER(
ORDER BY salary, employee_id ASC) AS "pay_senior"
FROM Candidates
WHERE experience = 'Senior') se
WHERE pay_senior <= 70000),
JUNIOR
AS (SELECT employee_id AS "id_junior"
FROM (SELECT employee_id,
salary,
Sum(salary)
OVER(
ORDER BY salary, employee_id ASC) AS "pay_junior"
FROM Candidates
WHERE experience = 'Junior') ju
WHERE pay_junior < 70000 - (SELECT IFNULL(Max(pay_senior), 0)
FROM SENIOR))
SELECT id_senior AS "employee_id"
FROM SENIOR
UNION ALL
SELECT id_junior
FROM JUNIOR;
SELECT i.ANIMAL_ID,
i.NAME
FROM ANIMAL_INS i
JOIN ANIMAL_OUTS o
ON i.ANIMAL_ID = o.ANIMAL_ID
ORDER BY DATEDIFF(o.DATETIME, i.DATETIME) DESC
LIMIT 2;
문제 링크
1트를 한 게 4월 초였는데
이 때는 case when을 써서 풀었었다.
아마 ifnull을 몰랐을 때였나 보다.
SELECT ANIMAL_TYPE,
IFNULL(NAME, 'No name') AS "NAME",
SEX_UPON_INTAKE
FROM ANIMAL_INS;
문제 링크
case when에서 조건을 줄 때
when을 두 번 쓸 필요 없이 그냥 or로 연결하면 된다.
1트에서는 when을 두 번 씀.
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;
문제 링크
집계함수(이 문제에서는 count)를 쓰면
null인 것들은 자동으로 빠져서 집계되기 때문에
굳이 where절을 써서 null이 아닌 것들만 추릴 필요는 없다.
1트에서는 where name is not null을 넣어놨는데 그럴 필요 없단 얘기.
다만, count(*)는 null인 것들도 포함한 행의 갯수를 센다는 점에는 주의할 것.
SELECT COUNT(DISTINCT NAME) AS "count"
FROM ANIMAL_INS;
SELECT ANIMAL_ID
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
ORDER BY 1;