Chào mọi người, hiện mình đang luyện SQL với leetcode. Dưới đây là quá trình làm của mình, nếu có câu lệnh nào hay hơn thì mọi người chia sẻ dưới cmt nhé.
Lưu ý: 1 số bài mình có tham khảo cách làm của người khác. Và mình sử dùng MySQL.
Select phần 1
584. Viết truy vấn SQL với referee_id khác 2
SELECT name FROM Customer
WHERE NOT referee_id = 2 OR referee_id IS NULL;
1757. Viết truy vấn SQL gồm các product_id vừa low fat và recyclable
SELECT product_id FROM Products
WHERE low_fats = 'Y' AND recyclable = 'Y';
1683. Viết truy vấn SQL tìm ID các tweet mà content có số lượng kí tự > 15
SELECT tweet_id FROM Tweets
WHERE char_length(content) > 15;
627. Thay đổi cột sex trong bảng salary (m thành f, f thành m)
Ý tưởng: dùng IF
UPDATE Salary
SET sex = IF(sex = 'm', 'f', 'm');
1068. Viết truy vấn SQL báo cáo product_name, year và price cho từng sale_id
Ý tưởng: dùng INNER JOIN
SELECT product_name, year, price
FROM Sales s
JOIN Product p
ON s.product_id = p.product_id;
1148. Viết truy vấn SQL tìm các tác giả đã xem ít nhất 1 trong các bài viết của họ, sắp xếp tăng theo id
Ý tưởng: author_id = viewer_id
SELECT DISTINCT author_id AS id
FROM Views
WHERE author_id = viewer_id
ORDER BY id ASC;
1853. Viết truy vấn SQL chuyển đổi định dạng thời gian
Ý tưởng: dùng DATE_FORMAT
SELECT DATE_FORMAT(day, '%W, %M %e, %Y') AS day
FROM Days;
1821. Viết truy vấn những khách hàng có revenue > 0 trong năm 2021
SELECT customer_id
FROM Customers
WHERE year = 2021 AND revenue > 0;
2026. Viết truy vấn SQL báo cáo ID các vấn đề có số lượt thích trên tổng số lượt vote < 60%, sắp xếp theo problem_id tăng dần
SELECT problem_id
FROM Problems
WHERE likes / (likes + dislikes) < 0.6
ORDER BY problem_id;
2082. Viết truy vấn SQL đếm số lượng khách hàng có ít nhất 1 hóa đơn amount > 500
SELECT COUNT(DISTINCT customer_id) AS rich_count
FROM Store
WHERE amount > 500;
2377. Viết truy vấn SQL sắp xếp lại bảng huy chương Olympic (theo thứ tự vàng, bạc, đồng, nếu cùng hc đồng thì sắp xếp theo bảng chữ cái)
SELECT * FROM Olympic
ORDER BY gold_medals, silver_medals, bronze_medals, country;
Quan hệ giữa các bảng (trùng 1683, 627, 1068 ở Select phần 1)
2356. Tính số môn học DUY NHẤT mỗi giáo viên dạy
SELECT teacher_id, COUNT(DISTINCT subject_id) AS cnt
FROM Teacher
GROUP BY teacher_id;
1378. HIển thị ID của người dùng, nếu không có thì trả về null
Ý tưởng: vì xuất hiện null nên dùng LEFT JOIN
SELECT uni.unique_id AS unique_id, es.name AS name
FROM Employees es
left JOIN Employeeuni uni ON es.id = uni.id;
1795. Sắp xếp lại bảng Products, nếu cửa hàng không có sản phẩm thì không thêm vào
SELECT product_id, 'store1' AS store, store1 AS price
FROM Products WHERE store1 IS NOT NULL
UNION
SELECT product_id, 'store2' AS store, store2 AS price
FROM Products WHERE store2 IS NOT NULL
UNION
SELECT product_id, 'store3' AS store, store3 AS price
FROM Products WHERE store3 IS NOT NULL;
1587. Báo cáo tên và số dư của người dùng nếu số dư lớn hơn 10000. Số dư là tổng số tiền các giao dịch liên quan đến tài khoản đó
Ý tưởng: gom các hàng có cùng account lại để tìm số dư
SELECT u.name, SUM(t.amount) AS balance
FROM Users u
JOIN Transactions t ON u.account = t.account
GROUP BY t.account
HAVING balance > 10000;
1581. Tìm các ID đã truy cập mà không thực hiện giao dịch, và đếm số lần thực hiện như vậy
Ý tưởng: chỉ cần lọc ra các visit_id tồn tại trong bảng Visits mà không có trong bảng Transactions
SELECT customer_id, COUNT(customer_id) AS count_no_trans
FROM Visits
WHERE visit_id NOT IN (SELECT visit_id FROM Transactions)
GROUP BY customer_id;
1179. Format lại bảng sao cho có từng phòng ban và doanh thu mỗi phòng ban mỗi tháng
SELECT id,
SUM(IF (month = 'Jan', revenue, null)) AS Jan_Revenue,
SUM(IF (month = 'Feb', revenue, null)) AS Feb_Revenue,
SUM(IF (month = 'Mar', revenue, null)) AS Mar_Revenue,
SUM(IF (month = 'Apr', revenue, null)) AS Apr_Revenue,
SUM(IF (month = 'May', revenue, null)) AS May_Revenue,
SUM(IF (month = 'Jun', revenue, null)) AS Jun_Revenue,
SUM(IF (month = 'Jul', revenue, null)) AS Jul_Revenue,
SUM(IF (month = 'Aug', revenue, null)) AS Aug_Revenue,
SUM(IF (month = 'Sep', revenue, null)) AS Sep_Revenue,
SUM(IF (month = 'Oct', revenue, null)) AS Oct_Revenue,
SUM(IF (month = 'Nov', revenue, null)) AS Nov_Revenue,
SUM(IF (month = 'Dec', revenue, null)) AS Dec_Revenue
FROM Department
GROUP BY id;
1484. Liệt kê số sản phẩm khác nhau mỗi ngày bán được và tên của chúng, tên sản phẩm sắp xếp theo từ điển, bảng kết quả sắp xếp theo sell_date
Ý tưởng: công đoạn mình nghĩ khó nhất là tìm được hàm nối các giá trị trên cột thành 1 hàng, vì vậy mình đã hỏi ChatGPT và tìm được hàm GROUP_CONCAT
SELECT sell_date, COUNT(DISTINCT product) AS num_sold,
GROUP_CONCAT(DISTINCT product ORDER BY product SEPARATOR ',') AS products
FROM Activities
GROUP BY sell_date;
1890. Báo cáo lần đăng nhập mới nhất của người dùng trong năm 2020, không bao gồm người dùng không đăng nhập vào năm 2020
SELECT user_id, MAX(time_stamp) AS last_stamp
FROM Logins
WHERE YEAR(time_stamp) = 2020
GROUP BY user_id;
1251. Tìm giá bán trung bình mỗi sản phẩm, làm tròn đến 2 chữ số
Ý tưởng: hàm làm tròn ROUND
SELECT p.product_id, ROUND(SUM(p.price * u.units)/SUM(u.units), 2) AS average_price
FROM Prices p
JOIN Unitssold u ON p.product_id = u.product_id AND u.purchase_date BETWEEN p.start_date AND p.end_date
GROUP BY p.product_id;
1789. Báo cáo nhân viên và bộ phận chính của họ
SELECT employee_id, department_id
FROM Employee
WHERE employee_id IN
(
SELECT employee_id
FROM Employee
GROUP BY employee_id
HAVING count(*) = 1
) OR primary_flag = 'Y';
Các loại join khi truy vấn (phần free lặp lại)
1303. Tìm quy mô nhóm của từng nhân viên
SELECT employee_id, COUNT(employee_id) OVER (PARTITION BY team_id) AS team_size
FROM Employee;
1571. Báo cáo tổng thể tích hàng tồn kho trong mỗi kho
SELECT w.name AS warehouse_name, SUM(w.units * p.width * p.length * p.height) AS volumn
FROM Warehouse w JOIN Products p ON w.product_id = p.product_id
GROUP BY w.name;
2339. Báo cáo các trận đấu có thể có của giải đấu, cả lượt đi lẫn lượt về
Ý tưởng: dùng CROSS JOIN, loại các trận mà 2 đội cùng tên
SELECT t1.team_name AS home_team, t2.team_name AS away_team
FROM Teams t1
CROSS JOIN Teams t2
WHERE t1.team_name != t2.team_name;
1623. Liệt kê các trường hợp mà tên và ID của học sinh không được trùng nhau
SELECT a.student_name AS member_A, b.student_name AS member_B, c.student_name AS member_C
FROM SchoolA a, SchoolB b, SchoolC c
WHERE a.student_name != b.student_name
AND a.student_name != c.student_name
AND b.student_name != c.student_name
AND a.student_id != b.student_id
AND a.student_id != c.student_id
AND b.student_id != c.student_id;
1421. Tìm giá trị hàng hóa theo ID và năm
SELECT q.id, q.year, IFNULL(npv, 0) AS npv
FROM Queries q
LEFT JOIN NPV n ON q.id = n.id AND q.year = n.year;
1069. Báo cáo tổng số lượng đã bán cho mỗi sản phẩm
SELECT product_id, SUM(quantity) AS total_quantity
FROM Sales;
Select phần 2 (trùng 2356, 1179)
1741. Tính thời gian mỗi nhân viên dành ở văn phòng theo ngày
SELECT event_day AS day, emp_id, SUM(out_time - in_time) AS total_time
FROM Employees
GROUP BY day, emp_id;
1693. Tìm số lượng lãnh đạo và đối tác của từng hãng theo ngày
SELECT date_id, make_name, COUNT(DISTINCT lead_id) AS unique_leads,
COUNT(DISTINCT partner_id) AS unique_partners
FROM DailySales
GROUP BY date_id, make_name;
1350. Tìm danh sách sinh viên đăng kí vào các khoa không còn tồn tại
SELECT id, name
FROM Students
WHERE department_id NOT IN (SELECT id FROM Departments);
1777. Tìm giá từng mặt hàng của mỗi cửa hàng
SELECT product_id,
SUM(IF (store = 'store1', price, null)) AS store1,
SUM(IF (store = 'store2', price, null)) AS store2,
SUM(IF (store = 'store3', price, null)) AS store3
FROM Products
GROUP BY product_id;
1565. Đếm số lượng đơn hàng và khách hàng có hóa đơn > $20 cho mỗi tháng
SELECT DATE_FORMAT(order_date, '%Y-%m') AS month, COUNT(DISTINCT order_id) AS order_count, COUNT(DISTINCT customer_id) AS customer_count
FROM Orders
GROUP BY month;
1173. Tính tỉ lệ đơn đặt hàng ngay lập tức, làm tròn đến 2 chữ số
SELECT ROUND(100 * AVG(IF (order_date = customer_pref_delivery_date)), 2) AS immediate_percentage
FROM Delivery;
Chữa bài tập 1 (trùng 1890)
595. Tìm các nước có diện tích ít nhất là 3000000 km2 hoặc dân số ít nhất là 25000000 người
SELECT name, population, area
FROM World
WHERE area >= 3000000 OR population >= 25000000;
620. Tìm các bộ phim có ID lẻ và được mô tả không boring
, sắp xếp theo rating giảm dần
SELECT id, movie, description, rating
FROM Cinema
WHERE id % 2 = 1 AND description != 'boring'
ORDER BY rating DESC;
610. Với 3 đoạn thẳng, xem chúng có thể tạo thành 1 tam giác hay không
SELECT *, IF(x + y > z AND y + z > x AND z + x > y, 'Yes', 'No') AS triangle
FROM Triangle;
1729. Trả về số người theo dõi của mỗi người, sắp xếp theo user_id
tăng dần
SELECT user_id, COUNT(DISTINCT follower_id) AS followers_count
FROM Followers
GROUP BY user_id
ORDER BY user_id;
1050. Tìm tất cả các cặp diễn viên - đạo diễn đã hợp tác với nhau ít nhất 3 lần
SELECT actor_id, director_id
FROM ActorDirector
GROUP BY actor_id, director_id
HAVING COUNT(DISTINCT timestamp) >= 3;
Chữa bài tập 2 (trùng 1484)
511. Tìm lần đăng nhập đầu tiên của mỗi người chơi
SELECT player_id, MIN(event_date) AS first_login
FROM Activity
GROUP BY player_id;
175. Báo cáo tên và địa chỉ của mỗi người, nếu không có thì báo null
Ý tưởng: xuất hiện null
nên dùng LEFT JOIN
SELECT p.firstName, p.lastName, a.city, a.state
FROM Person p
LEFT JOIN Address a ON p.personId = a.personId;
1082. Tìm sản phẩm bán chạy nhất theo tổng giá bán, nếu có nhiều hơn 1 thì in ra tất cả
Ý tưởng: dùng Window function, cụ thể là RANK
SELECT seller_id
FROM
(
SELECT seller_id, RANK() OVER (PARTITION BY seller_id ORDER BY SUM(price) DESC) AS rank
FROM Sales
GROUP BY seller_id;
) x WHERE rank = 1;
2072. In ra tên trường đại học nào có nhiều sinh viên xuất sắc hơn, nếu bằng nhau thì hòa
WITH Student AS (
SELECT COUNT(*) AS NY FROM NewYork WHERE score >= 90
UNION
SELECT COUNT(*) AS CA FROM California WHERE score >= 90
)
SELECT CASE
WHEN NY > CA THEN 'New York University'
WHEN CA > NY THEN 'California University'
ELSE 'No Winner'
END AS winner
FROM Student;
Bình luận