Bài tập & đáp án
Đề bài đọc tự do. Phần đáp án và giải thích chi tiết chỉ dành cho sinh viên đang học lớp thực hành IT004, cần mã truy cập từ giảng viên.
ĐỀ BÀI · PHẦN III - NGÔN NGỮ TRUY VẤN DỮ LIỆU
Quản lý bán hàng - Câu 1 ➜ 25
Sử dụng các câu lệnh SQL trong SQL Server Management Studio để thực hiện 25 câu truy vấn dưới đây trên lược đồ Quản lý bán hàng. Tự làm trước khi xem đáp án.
<MSSV>_<HoVaTen>_BTTH2.sql (MSSV là mã số sinh viên, HoVaTen là họ và tên).- In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" sản xuất.
- In ra danh sách các sản phẩm (MASP, TENSP) có đơn vị tính là "cay", "quyen".
- In ra danh sách các sản phẩm (MASP, TENSP) có mã sản phẩm bắt đầu là "B" và kết thúc là "01".
- In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" sản xuất có giá từ 30.000 đến 40.000.
- In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" hoặc "Thai Lan" sản xuất có giá từ 30.000 đến 40.000.
- In ra các số hóa đơn, trị giá hóa đơn bán ra trong ngày 1/1/2007 và ngày 2/1/2007.
- In ra các số hóa đơn, trị giá hóa đơn trong tháng 1/2007, sắp xếp theo ngày (tăng dần) và trị giá của hóa đơn (giảm dần).
- In ra danh sách các khách hàng (MAKH, HOTEN) đã mua hàng trong ngày 1/1/2007.
- In ra số hóa đơn, trị giá các hóa đơn do nhân viên có tên "Nguyen Van B" lập trong ngày 28/10/2006.
- In ra danh sách các sản phẩm (MASP, TENSP) được khách hàng có tên "Nguyen Van A" mua trong tháng 10/2006.
- Tìm các số hóa đơn đã mua sản phẩm có mã số "BB01" hoặc "BB02".
- Tìm các số hóa đơn đã mua sản phẩm có mã số "BB01" hoặc "BB02", mỗi sản phẩm mua với số lượng từ 10 đến 20.
- Tìm các số hóa đơn mua cùng lúc 2 sản phẩm có mã số "BB01" và "BB02", mỗi sản phẩm mua với số lượng từ 10 đến 20.
- In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" sản xuất hoặc các sản phẩm được bán ra trong ngày 1/1/2007.
- In ra danh sách các sản phẩm (MASP, TENSP) không bán được.
- In ra danh sách các sản phẩm (MASP, TENSP) không bán được trong năm 2006.
- In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" sản xuất không bán được trong năm 2006.
- Thống kê số lượng hóa đơn do mỗi nhân viên lập trong năm 2006, hiển thị (MANV, HOTEN, SoLuongHD).
- In ra danh sách nhân viên và tổng số khách hàng khác nhau mà họ đã bán hàng cho trong năm 2006.
- Liệt kê sản phẩm (MASP, TENSP) có tổng số lượng bán ra nhiều nhất trong năm 2006.
- Tìm nhân viên có doanh số bán hàng cao nhất trong tháng 10/2006.
- In ra danh sách sản phẩm không bán được trong năm 2007 nhưng có bán trong năm 2006.
- Liệt kê danh sách sản phẩm (MASP, TENSP) được bán bởi ít nhất 2 nhân viên khác nhau.
- In ra danh sách khách hàng không mua sản phẩm nào do Thái Lan sản xuất.
- Tìm hóa đơn có trị giá lớn nhất trong năm 2006, in ra (SOHD, NGHD, TRIGIA).
ĐÁP ÁN
Xem đáp án
Nội dung được bảo vệ
Nhập mã truy cập để xem đáp án Tuần 2.
Mã truy cập được cung cấp bởi giảng viên.
Đáp án đầy đủ cho Câu 1 ➜ 25. Gõ lại từng câu vào SSMS để nhớ lâu hơn nhé - Nút Copy ở đây chỉ mang tính hình thức thôi.
CÂU 1 · WHERE
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" sản xuất.
SELECT MASP, TENSP
FROM SANPHAM
WHERE NUOCSX = 'Trung Quoc';WHERE lọc theo đúng 1 điều kiện so sánh bằng trên cột NUOCSX.
Đề chỉ yêu cầu 1 điều kiện duy nhất nên so sánh bằng là đủ, không cần kỹ thuật phức tạp hơn.
CÂU 2 · IN
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) có đơn vị tính là "cay", "quyen".
SELECT MASP, TENSP
FROM SANPHAM
WHERE DVT IN ('cay', 'quyen');IN kiểm tra giá trị có nằm trong một danh sách cho trước hay không.
Dùng IN gọn hơn khi so sánh 1 cột với nhiều giá trị rời rạc - Tương đương nhưng dễ đọc hơn chuỗi OR liên tiếp.
Cách khác
SELECT MASP, TENSP
FROM SANPHAM
WHERE DVT = 'cay' OR DVT = 'quyen';CÂU 3 · LIKE
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) có mã sản phẩm bắt đầu là "B" và kết thúc là "01".
SELECT MASP, TENSP
FROM SANPHAM
WHERE MASP LIKE 'B%01';LIKE khớp mẫu chuỗi; % đại diện cho bất kỳ chuỗi ký tự nào (kể cả rỗng) nằm giữa "B" và "01".
Đề yêu cầu điều kiện vị trí ký tự đầu/cuối, không phải so sánh bằng chính xác, nên phải dùng LIKE thay vì =.
CÂU 4 · BETWEEN
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" sản xuất có giá từ 30.000 đến 40.000.
SELECT MASP, TENSP
FROM SANPHAM
WHERE NUOCSX = 'Trung Quoc' AND (GIA BETWEEN 30000 AND 40000);BETWEEN a AND b tương đương >= a AND <= b, kiểm tra giá trị nằm trong khoảng đóng.
BETWEEN ngắn gọn hơn khi cần lọc khoảng giá trị liên tục như GIA từ 30.000 đến 40.000.
Cách khác
SELECT MASP, TENSP
FROM SANPHAM
WHERE NUOCSX = 'Trung Quoc' AND (GIA >= 30000 AND GIA <= 40000);CÂU 5 · IN + BETWEEN
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" hoặc "Thai Lan" sản xuất có giá từ 30.000 đến 40.000.
SELECT MASP, TENSP
FROM SANPHAM
WHERE NUOCSX IN ('Trung Quoc', 'Thai Lan') AND (GIA BETWEEN 30000 AND 40000);Kết hợp IN (nhiều giá trị nước sản xuất) và BETWEEN (khoảng giá) bằng AND.
2 điều kiện độc lập (nước SX và khoảng giá) đều phải đúng cùng lúc nên nối bằng AND; mỗi điều kiện lại rút gọn bằng IN/BETWEEN thay vì OR/so sánh dài dòng.
CÂU 6 · IN theo ngày
Đề bài: In ra các số hóa đơn, trị giá hóa đơn bán ra trong ngày 1/1/2007 và ngày 2/1/2007.
SELECT SOHD, TRIGIA
FROM HOADON
WHERE NGHD IN ('1/1/2007', '2/1/2007');So sánh cột NGHD (kiểu ngày) với danh sách 2 giá trị ngày cụ thể.
IN thay thế OR khi so sánh cùng 1 cột với nhiều giá trị rời rạc - Áp dụng được cho cả cột kiểu ngày, không chỉ chuỗi hay số.
CÂU 7 · YEAR/MONTH + ORDER BY nhiều cột
Đề bài: In ra các số hóa đơn, trị giá hóa đơn trong tháng 1/2007, sắp xếp theo ngày (tăng dần) và trị giá của hóa đơn (giảm dần).
SELECT SOHD, NGHD, TRIGIA
FROM HOADON
WHERE YEAR(NGHD) = 2007 AND MONTH(NGHD) = 1
ORDER BY NGHD ASC, TRIGIA DESC;YEAR()/MONTH() trích xuất năm/tháng từ giá trị ngày; ORDER BY có thể sắp theo nhiều cột, mỗi cột 1 chiều tăng/giảm riêng.
Lọc "tháng 1/2007" cần tách năm và tháng vì NGHD lưu ngày đầy đủ. Sắp xếp 2 tiêu chí khác chiều (ngày tăng, trị giá giảm) nên phải khai báo ASC/DESC riêng cho từng cột trong cùng ORDER BY.
CÂU 8 · JOIN
Đề bài: In ra danh sách các khách hàng (MAKH, HOTEN) đã mua hàng trong ngày 1/1/2007.
SELECT hd.MAKH, HOTEN
FROM KHACHHANG kh JOIN HOADON hd ON kh.MAKH = hd.MAKH
WHERE NGHD = '1/1/2007';JOIN kết hợp KHACHHANG với HOADON qua MAKH để lấy được HOTEN của khách đã có hóa đơn đúng ngày.
Thông tin cần lấy (HOTEN) nằm ở KHACHHANG còn điều kiện lọc (NGHD) nằm ở HOADON - Phải JOIN 2 bảng mới truy vấn được cùng lúc.
Cách khác
SELECT MAKH, HOTEN
FROM KHACHHANG
WHERE MAKH IN (SELECT MAKH
FROM HOADON
WHERE NGHD = '1/1/2007');CÂU 9 · JOIN lọc theo tên nhân viên
Đề bài: In ra số hóa đơn, trị giá các hóa đơn do nhân viên có tên "Nguyen Van B" lập trong ngày 28/10/2006.
SELECT SOHD, TRIGIA
FROM HOADON hd JOIN NHANVIEN nv ON hd.MANV = nv.MANV
WHERE HOTEN = 'Nguyen Van B' AND NGHD = '28/10/2006';JOIN HOADON với NHANVIEN qua MANV để lọc theo họ tên nhân viên.
HOADON chỉ lưu MANV (mã), không lưu tên nhân viên - Phải JOIN sang NHANVIEN mới lọc được theo tên "Nguyen Van B".
Cách khác
SELECT SOHD, TRIGIA
FROM HOADON
WHERE NGHD = '28/10/2006' AND MANV IN (SELECT MANV
FROM NHANVIEN
WHERE HOTEN = 'Nguyen Van B');CÂU 10 · JOIN 4 bảng
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) được khách hàng có tên "Nguyen Van A" mua trong tháng 10/2006.
SELECT sp.MASP, TENSP
FROM SANPHAM sp JOIN CTHD ct ON sp.MASP = ct.MASP
JOIN HOADON hd ON hd.SOHD = ct.SOHD
JOIN KHACHHANG kh ON kh.MAKH = hd.MAKH
WHERE HOTEN = 'Nguyen Van A' AND YEAR(NGHD) = 2006 AND MONTH(NGHD) = 10;Nối liên tiếp 4 bảng (SANPHAM ➜ CTHD ➜ HOADON ➜ KHACHHANG) theo đúng chuỗi khóa ngoại để đi từ "tên khách hàng" tới "sản phẩm đã mua".
Không có khóa ngoại trực tiếp giữa KHACHHANG và SANPHAM - Phải đi qua HOADON và CTHD (bảng trung gian) mới liên kết được 2 bảng cách nhau 2 lớp quan hệ.
Cách khác (subquery lồng)
SELECT MASP, TENSP
FROM SANPHAM
WHERE MASP IN (SELECT MASP
FROM CTHD
WHERE SOHD IN (SELECT SOHD
FROM HOADON
WHERE YEAR(NGHD) = 2006 AND MONTH(NGHD) = 10
AND MAKH IN (SELECT MAKH
FROM KHACHHANG
WHERE HOTEN = 'Nguyen Van A')));CÂU 11 · DISTINCT + IN
Đề bài: Tìm các số hóa đơn đã mua sản phẩm có mã số "BB01" hoặc "BB02".
SELECT DISTINCT SOHD
FROM CTHD
WHERE MASP IN ('BB01', 'BB02');DISTINCT loại bỏ SOHD trùng lặp trong kết quả trả về.
1 hóa đơn có thể mua cả BB01 và BB02 (2 dòng CTHD) - Nếu không DISTINCT, hóa đơn đó sẽ lặp lại trong kết quả.
Cách khác (UNION)
(SELECT SOHD FROM CTHD WHERE MASP = 'BB01')
UNION
(SELECT SOHD FROM CTHD WHERE MASP = 'BB02');CÂU 12 · Thêm điều kiện số lượng
Đề bài: Tìm các số hóa đơn đã mua sản phẩm có mã số "BB01" hoặc "BB02", mỗi sản phẩm mua với số lượng từ 10 đến 20.
SELECT DISTINCT SOHD
FROM CTHD
WHERE MASP IN ('BB01', 'BB02') AND (SL BETWEEN 10 AND 20);Thêm điều kiện AND (SL BETWEEN 10 AND 20) áp dụng cho từng dòng CTHD thỏa MASP.
Điều kiện số lượng áp dụng riêng cho dòng chi tiết đang xét (không phải tổng số lượng), nên chỉ cần thêm AND vào cùng WHERE, không cần GROUP BY.
CÂU 13 · INTERSECT
Đề bài: Tìm các số hóa đơn mua cùng lúc 2 sản phẩm có mã số "BB01" và "BB02", mỗi sản phẩm mua với số lượng từ 10 đến 20.
(SELECT SOHD FROM CTHD WHERE MASP = 'BB01' AND (SL BETWEEN 10 AND 20))
INTERSECT
(SELECT SOHD FROM CTHD WHERE MASP = 'BB02' AND (SL BETWEEN 10 AND 20));INTERSECT trả về các dòng xuất hiện ở cả hai tập kết quả (phần giao của 2 tập SOHD).
Câu 11/12 dùng "hoặc" (IN) vì chỉ cần 1 trong 2 sản phẩm; câu này yêu cầu "đồng thời cả 2" nên phải lấy phần giao bằng INTERSECT - IN/OR không diễn tả được yêu cầu này.
CÂU 14 · UNION
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" sản xuất hoặc các sản phẩm được bán ra trong ngày 1/1/2007.
(SELECT MASP, TENSP
FROM SANPHAM
WHERE NUOCSX = 'Trung Quoc')
UNION
(SELECT sp.MASP, TENSP
FROM SANPHAM sp JOIN CTHD ct ON sp.MASP = ct.MASP
JOIN HOADON hd ON hd.SOHD = ct.SOHD
WHERE NGHD = '1/1/2007');UNION gộp 2 tập kết quả độc lập (sản phẩm theo nước SX, sản phẩm theo ngày bán) và tự loại trùng.
2 điều kiện thuộc 2 nhánh logic khác nhau (1 chỉ cần SANPHAM, 1 cần JOIN thêm CTHD/HOADON) nên tách thành 2 SELECT riêng rồi UNION, thay vì gộp chung 1 câu.
CÂU 15 · NOT IN
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) không bán được.
SELECT MASP, TENSP
FROM SANPHAM
WHERE MASP NOT IN (SELECT DISTINCT MASP FROM CTHD);NOT IN loại các MASP đã từng xuất hiện trong CTHD (đã từng được bán).
"Không bán được" nghĩa là MASP không tồn tại trong CTHD - Phủ định của IN là NOT IN.
Cách khác (EXCEPT)
(SELECT MASP, TENSP FROM SANPHAM)
EXCEPT
(SELECT DISTINCT ct.MASP, TENSP
FROM SANPHAM sp JOIN CTHD ct ON sp.MASP = ct.MASP);CÂU 16 · NOT IN lồng qua HOADON
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) không bán được trong năm 2006.
SELECT MASP, TENSP
FROM SANPHAM
WHERE MASP NOT IN (SELECT DISTINCT MASP
FROM CTHD
WHERE SOHD IN (SELECT SOHD
FROM HOADON
WHERE YEAR(NGHD) = 2006));Subquery lồng 2 lớp: Lớp trong lọc SOHD theo năm 2006, lớp ngoài lọc MASP theo các SOHD đó.
CTHD không có cột năm - Phải lồng qua HOADON (nơi có NGHD) trước mới xác định được dòng CTHD nào thuộc năm 2006.
Cách khác (EXCEPT)
(SELECT MASP, TENSP FROM SANPHAM)
EXCEPT
(SELECT DISTINCT ct.MASP, TENSP
FROM SANPHAM sp JOIN CTHD ct ON sp.MASP = ct.MASP
JOIN HOADON hd ON ct.SOHD = hd.SOHD
WHERE YEAR(NGHD) = 2006);CÂU 17 · Kết hợp điều kiện với câu 16
Đề bài: In ra danh sách các sản phẩm (MASP, TENSP) do "Trung Quoc" sản xuất không bán được trong năm 2006.
SELECT MASP, TENSP
FROM SANPHAM
WHERE NUOCSX = 'Trung Quoc'
AND MASP NOT IN (SELECT DISTINCT MASP
FROM CTHD
WHERE SOHD IN (SELECT SOHD
FROM HOADON
WHERE YEAR(NGHD) = 2006));Kết hợp điều kiện NUOCSX (trên SANPHAM) với điều kiện NOT IN subquery giống câu 16.
Đây là câu 16 thu hẹp thêm 1 điều kiện (nước sản xuất) bằng AND - Tái sử dụng đúng logic subquery đã có, không cần viết lại từ đầu.
CÂU 18 · GROUP BY + COUNT
Đề bài: Thống kê số lượng hóa đơn do mỗi nhân viên lập trong năm 2006, hiển thị (MANV, HOTEN, SoLuongHD).
SELECT nv.MANV, HOTEN, COUNT(*) AS SoLuongHD
FROM NHANVIEN nv JOIN HOADON hd ON nv.MANV = hd.MANV
WHERE YEAR(NGHD) = 2006
GROUP BY nv.MANV, HOTEN;GROUP BY gom các hóa đơn theo từng nhân viên; COUNT(*) đếm số dòng (số hóa đơn) trong mỗi nhóm.
Đề yêu cầu số liệu "theo từng nhân viên" (không phải tổng toàn bộ) nên bắt buộc GROUP BY theo MANV (kèm HOTEN vì phụ thuộc hàm vào MANV).
CÂU 19 · COUNT DISTINCT
Đề bài: In ra danh sách nhân viên và tổng số khách hàng khác nhau mà họ đã bán hàng cho trong năm 2006.
SELECT nv.MANV, nv.HOTEN, COUNT(DISTINCT hd.MAKH) AS TongSoKH
FROM NHANVIEN nv JOIN HOADON hd ON nv.MANV = hd.MANV
JOIN KHACHHANG kh ON kh.MAKH = hd.MAKH
WHERE YEAR(NGHD) = 2006
GROUP BY nv.MANV, nv.HOTEN;COUNT(DISTINCT ...) đếm số giá trị khác nhau, bỏ qua trùng lặp.
1 nhân viên có thể bán nhiều hóa đơn cho cùng 1 khách hàng - Nếu COUNT(*) thường sẽ đếm trùng khách hàng đó nhiều lần, phải dùng DISTINCT để chỉ đếm mỗi khách 1 lần.
CÂU 20 · SUM + TOP WITH TIES
Đề bài: Liệt kê sản phẩm (MASP, TENSP) có tổng số lượng bán ra nhiều nhất trong năm 2006.
SELECT TOP 1 WITH TIES sp.MASP, TENSP, SUM(SL) AS TongSoLuong
FROM SANPHAM sp JOIN CTHD ct ON sp.MASP = ct.MASP
JOIN HOADON hd ON hd.SOHD = ct.SOHD
WHERE YEAR(NGHD) = 2006
GROUP BY sp.MASP, TENSP
ORDER BY TongSoLuong DESC;SUM(SL) cộng dồn số lượng theo từng sản phẩm; TOP 1 WITH TIES lấy dòng cao nhất và giữ luôn các dòng đồng hạng.
Phải SUM vì đề hỏi "tổng số lượng bán", không phải số lần bán. Dùng WITH TIES để không bỏ sót trường hợp nhiều sản phẩm cùng bán nhiều nhất bằng nhau.
CÂU 21 · SUM trị giá
Đề bài: Tìm nhân viên có doanh số bán hàng cao nhất trong tháng 10/2006.
SELECT TOP 1 WITH TIES nv.MANV, HOTEN, SUM(TRIGIA) AS TongDoanhSo
FROM NHANVIEN nv JOIN HOADON hd ON nv.MANV = hd.MANV
WHERE MONTH(NGHD) = 10 AND YEAR(NGHD) = 2006
GROUP BY nv.MANV, HOTEN
ORDER BY TongDoanhSo DESC;SUM(TRIGIA) cộng tổng trị giá các hóa đơn theo từng nhân viên trong tháng 10/2006.
"Doanh số" là tổng trị giá hóa đơn nhân viên đó lập, khác với câu 18 (đếm số lượng hóa đơn) - Phải SUM cột tiền chứ không COUNT.
CÂU 22 · EXCEPT
Đề bài: In ra danh sách sản phẩm không bán được trong năm 2007 nhưng có bán trong năm 2006.
(SELECT sp.MASP, TENSP
FROM SANPHAM sp JOIN CTHD ct ON sp.MASP = ct.MASP
JOIN HOADON hd ON hd.SOHD = ct.SOHD
WHERE YEAR(NGHD) = 2006)
EXCEPT
(SELECT sp.MASP, TENSP
FROM SANPHAM sp JOIN CTHD ct ON sp.MASP = ct.MASP
JOIN HOADON hd ON hd.SOHD = ct.SOHD
WHERE YEAR(NGHD) = 2007);EXCEPT lấy các dòng có trong tập thứ nhất nhưng không có trong tập thứ hai.
Yêu cầu "có ở 2006 nhưng không có ở 2007" đúng nghĩa phép trừ tập hợp - EXCEPT diễn đạt trực tiếp đúng ý này hơn viết bằng NOT IN.
CÂU 23 · HAVING
Đề bài: Liệt kê danh sách sản phẩm (MASP, TENSP) được bán bởi ít nhất 2 nhân viên khác nhau.
SELECT sp.MASP, TENSP, COUNT(DISTINCT MANV) AS SLNVBan
FROM SANPHAM sp JOIN CTHD ct ON sp.MASP = ct.MASP
JOIN HOADON hd ON hd.SOHD = ct.SOHD
GROUP BY sp.MASP, TENSP
HAVING COUNT(DISTINCT MANV) >= 2;HAVING lọc trên kết quả đã GROUP BY (khác WHERE - Lọc trước khi gom nhóm).
Điều kiện "ít nhất 2 nhân viên khác nhau" chỉ tính được sau khi đã đếm DISTINCT MANV theo từng sản phẩm - Nên phải lọc bằng HAVING, không thể dùng WHERE.
CÂU 24 · EXCEPT
Đề bài: In ra danh sách khách hàng không mua sản phẩm nào do Thái Lan sản xuất.
(SELECT MAKH, HOTEN
FROM KHACHHANG)
EXCEPT
(SELECT DISTINCT kh.MAKH, HOTEN
FROM KHACHHANG kh JOIN HOADON hd ON kh.MAKH = hd.MAKH
JOIN CTHD ct ON hd.SOHD = ct.SOHD
JOIN SANPHAM sp ON sp.MASP = ct.MASP
WHERE NUOCSX = 'Thai Lan');EXCEPT lấy các dòng có ở vế thứ nhất (toàn bộ khách hàng) nhưng không xuất hiện ở vế thứ hai (khách hàng đã từng mua ít nhất 1 sản phẩm Thái Lan, xác định qua chuỗi JOIN KHACHHANG ➜ HOADON ➜ CTHD ➜ SANPHAM).
"Không mua sản phẩm nào do Thái Lan sản xuất" tương đương "toàn bộ khách hàng trừ đi những khách hàng đã mua ít nhất 1 sản phẩm Thái Lan" - Đúng bản chất phép trừ tập hợp, nên EXCEPT là công cụ tự nhiên nhất cho dạng đề "không... nào".
Cách khác (NOT EXISTS)
SELECT kh.MAKH, HOTEN
FROM KHACHHANG kh
WHERE NOT EXISTS
(
SELECT *
FROM HOADON hd JOIN CTHD ct ON hd.SOHD = ct.SOHD
JOIN SANPHAM sp ON sp.MASP = ct.MASP
WHERE hd.MAKH = kh.MAKH
AND sp.NUOCSX = 'Thai Lan'
);CÂU 25 · TOP WITH TIES
Đề bài: Tìm hóa đơn có trị giá lớn nhất trong năm 2006, in ra (SOHD, NGHD, TRIGIA).
SELECT TOP 1 WITH TIES SOHD, NGHD, TRIGIA
FROM HOADON
WHERE YEAR(NGHD) = 2006
ORDER BY TRIGIA DESC;Sắp xếp các hóa đơn năm 2006 theo TRIGIA giảm dần rồi lấy TOP 1; WITH TIES giữ lại luôn mọi hóa đơn khác cũng đạt đúng trị giá cao nhất đó, không chỉ 1 dòng.
Nếu chỉ dùng TOP 1 (không WITH TIES) mà có 2 hóa đơn cùng đạt trị giá cao nhất, SQL Server chỉ trả về ngẫu nhiên 1 trong 2 - Bỏ sót hóa đơn còn lại. WITH TIES đảm bảo không mất dữ liệu trong trường hợp đồng hạng.
Cách khác (subquery MAX)
SELECT SOHD, NGHD, TRIGIA
FROM HOADON
WHERE YEAR(NGHD) = 2006
AND TRIGIA = (SELECT MAX(TRIGIA)
FROM HOADON
WHERE YEAR(NGHD) = 2006);