JOIN và APPLY có khả năng gần giống nhau, nhưng do JOIN là mệnh đề chính thống nên được sử dụng rộng rãi hơn. Tuy nhiên, APPLY có thể ứng dụng vào rất nhiều trường hợp mà ta không thể dùng JOIN, hoặc nếu có thể dùng thì cũng rối rắm và không hiệu quả. Cũng vì đặc tính gần giống nhau này mà nhiều lập trình viên không tìm hiểu kỹ cách thức hoạt động của APPLY một cách thấu đáo để có thể sử dụng nó tốt hơn.
Giả thử bạn có 2 bảng KhachHang và HoaDon như sau:
Để dễ so sánh tôi sẽ sử dụng JOIN và APPLY cho cùng 1 yêu cầu.
Trước hết xét 2 câu lệnh đơn giản dưới đây:
1 - select * from @khachHang kh cross join @hoaDon hd;
2 - select * from @khachHang kh cross apply @hoaDon hd;
Hai câu lệnh này hoàn toàn giống nhau về lô gíc, kết quả, cũng như cách thức hệ thống thực hiện việc truy xuất dữ liệu.
Mỗi dòng ở bảng @khachHang sẽ được kết nối với toàn bộ bảng @hoaDon (hoặc ngược lại). Vậy nếu bảng @khachHang có a dòng và bảng @hoaDon co b dòng thì kết quả sẽ có a*b dòng.
Xét tiếp 2 câu lệnh sau:
3 - select * from @khachHang kh cross join @hoaDon hd on kh.maKH=hd.maKH;
4 - select * from @khachHang kh cross apply (select * from @hoaDon hd where kh.maKH=hd.maKH)app;
Câu 3 và 4 biểu thị khách hàng với hóa đơn của họ (nếu khách hàng không có hóa đơn thì không biểu thị).
Câu 3 sử dung JOIN, câu 4 sử dung APPLY, chúng khác nhau về lô gíc, nhưng hoàn toàn giống nhau về kết quả, cũng như cách thức hệ thống thực hiện việc truy xuất dữ liệu - tức về mặt tối ưu, chúng cũng hoàn toàn giống nhau.
Với câu 3, mỗi dòng ở bảng @khachHang sẽ kết nối với toàn bảng ở bảng @hoaDon, sau đó được lọc bớt bởi lệnh ON (on kh.maKH=hd.maKH)
Với câu 4, mỗi dòng ở bảng @khachHang sẽ kết nối với 1 cửa sổ mới với số liệu là tập hợp dữ liệu từ bảng @hoaDon cùng với điều kiện được cung cấp từ bảng @khachHang (where kh.maKH=hd.maKH).
Chính vì sự khách biệt này dẫn đến nhiều sự khác biệt khác lớn hơn ở những yêu cầu phức tạp.
Nếu bạn muốn chỉ biểu thị 2 hóa đơn có số tiền lớn nhất cho mỗi khách hàng thì sự khác biệt của chúng thể hiện càng rõ. Câu lệnh như sau:
5 - select KHmaKh, tenKH, maHD, maKH, soLuong, soTien from
(
select kh.maKh as KHmaKH, kh.tenKH, hd.maHD, hd.maKH, hd.soLuong, hd.soTien
, rn=rơ_number() over(partition by hd.maKH order by hd.soTien desc)
from @khachHang kh join @hoaDon hd on kh.maKH=hd.maKH
) temp
where rn < 3;
6 - select * from @khachHang kh cross apply (select top 2 * from @hoaDon hd where kh.maKH=hd.maKH order by hd.soTien desc)app;
Câu 5 sử dụng JOIN, kết hợp với ROW_NUMBER(), còn câu 6 sử dụng APPLY, chúng cho kết quả hoàn toàn giống nhau, nhưng bạn cũng nhận thấy câu sử dụng JOIN rườm rà hơn nhiều. Và nhất là cách thức mà hệ thống truy xuất kết quả cũng khác biệt.
Căn bản là APPLY tạo ra 1 cửa sổ mới, nên nó cho phép dữ liệu được thanh lọc, thêm bớt, qua nhiều bước khác, nếu cần (ở câu 6 là TOP 2), trước khi kết nối với bảng ban đầu (@khachHang). Còn JOIN không có khả năng này, đó chính là giới hạn của JOIN.
Đó là CROSS APPLY, OUTER APPLY thì tương tự như LEFT OUTER JOIN. Có thể biểu thị qua 2 câu lệnh sau:
select * from @khachHang kh left join @hoaDon hd on kh.maKH=hd.maKH;
select * from @khachHang kh outer apply (select * from @hoaDon hd where kh.maKH=hd.maKH)app;
Hai câu lệnh này biểu thị toàn bộ khách hàng với hóa đơn tương ứng. Với những khách hàng không có hóa đơn thì các trường ở phần hóa đơn có giá trị NULL.
Ngoài ra chúng cũng có sự khác biệt tương tự ở phần CROSS APPLY trong câu lệnh 5 và 6.
NOTE : LEFT JOIN cũng là một đề mệnh đề gây nhiều ngộ nhận. Nếu bạn có thắc mắc, bạn có thể tham khảo về đề tại này ở bài viết trước đây về LEFT JOIN.
Hỏi Đáp SQL------------ Không có câu hỏi nào là sơ đẳng -------- |
hay
Trả lờiXóaQuá hay !
Trả lờiXóahay, hỉu hỉu rùi đó
Trả lờiXóaok
Trả lờiXóathax
Trả lờiXóacúp vinh danh
Trả lờiXóaCúp pha lê
Sửa máy in
Máy in canon 2900