LC 569 & LC 615 & LC 1097


The following advanced-level SQL problems.

LeetCode 569

Median Employee Salary (Hard) [link]

If the occurrence is odd, median is at (cnt+1)/2 . If the occurrence is even, medians are at cnt/2 and cnt/2+1. Use the relationship between the index and the count number to find medians.

SELECT id, company, salary
FROM (
    SELECT
        id,company,salary,
        row_number() OVER(PARTITION BY company ORDER BY salary) AS rnk,
        COUNT(id) OVER(PARTITION BY company) AS cnt
    FROM Employee
) t
WHERE rnk IN (cnt/2, cnt/2+1, (cnt+1)/2);

LeetCode 615

Average Salary: Departments vs Company (Hard) [link]

Using CASE WHEN and window function AVG.

SELECT DISTINCT *
FROM(
    SELECT 
        DATE_FORMAT(s.pay_date, '%Y-%m') AS pay_month,
        e.department_id,
        CASE 
            WHEN AVG(s.amount) OVER(PARTITION BY DATE_FORMAT(s.pay_date, '%Y-%m'), e.department_id)> AVG(s.amount) OVER(PARTITION BY DATE_FORMAT(s.pay_date, '%Y-%m')) THEN 'higher'
            WHEN AVG(s.amount) OVER(PARTITION BY DATE_FORMAT(s.pay_date, '%Y-%m'), e.department_id)< AVG(s.amount) OVER(PARTITION BY DATE_FORMAT(s.pay_date, '%Y-%m')) THEN 'lower' ELSE 'same'
        END AS comparison
    FROM Salary s
    LEFT JOIN Employee e
    ON s.employee_id = e.employee_id
)t;

LeetCode 1097

Game Play Analysis V (Hard) [link]

Using window function

SELECT event_date AS install_dt, 
    COUNT(player_id) AS installs, 
    ROUND(SUM(log_back) / COUNT(player_id), 2) AS Day1_retention
FROM(
    SELECT a1.player_id,a1.event_date,
        dense_rank() OVER(PARTITION BY a1.player_id ORDER BY a1.event_date) AS rnk,
        IF(a2.event_date IS NOT NULL, 1, 0) AS log_back
    FROM Activity a1
    LEFT JOIN Activity a2
    ON DATEDIFF(a2.event_date, a1.event_date) = 1 AND a1.player_id = a2.player_id
)t
WHERE rnk = 1
GROUP BY event_date;

Without window function

SELECT a1.first_date AS install_dt, 
    COUNT(a1.player_id) AS installs, 
    ROUND(COUNT(DISTINCT a2.player_id) / COUNT(a1.player_id), 2) AS Day1_retention
FROM(
    SELECT player_id, 
        MIN(event_date) AS first_date
    FROM Activity
    GROUP BY player_id
) a1
LEFT JOIN Activity a2
ON DATEDIFF(a2.event_date, a1.first_date) = 1 AND a1.player_id = a2.player_id
GROUP BY a1.first_date;

  TOC