Như đó núi đến ở trờn, khỏi niệm quan hệ của SQL khỏc với khỏi niệm quan hệ trừu tượng được trỡnh bày trong mụ hỡnh quan hệ. Một quan hệ là một tập hợp, khụng thể cú nhiều hơn một bản sao của một bộ cho trước. Khi một truy vấn SQL tạo một quan hệ mới, hệ thống SQL khụng loại bỏ cỏc trựng lặp. Như vậy, SQL trả lời cho một truy vấn cú thể liệt kờ nhiều lần cựng một bộ.
Nhớ lại rằng một định nghĩa cho một truy vấn select-from-where của SQL là như sau: Chỳng ta bắt đầu với tớch Đềcac của cỏc quan hệ được tham chiếu đến trong mệnh đề FROM. Mỗi bộ của tớch được kiểm tra bằng điều kiện trong mệnh đề WHERE và những bộ nào qua được kiểm tra sẽ được đưa cho dữ liệu ra cho phộp chiếu phự hợp với mệnh đề SELECT. Phộp chiếu này cú thể sinh ra cựng một bộ cho kết quả từ nhiều bộ khỏc nhau của tớch, và nếu như vậy, mỗi bản sao của kết quả sẽ được in ra. Hơn nữa, khụng cú gỡ sai đối với một quan hệ SQL cú trựng lặp.
Nếu chỳng ta khụng muốn cú sự trựng lặp trong kết quả, ta cú thể tiếp theo sau từ khoỏ SELECT bằng từ khoỏ DISTINCT. Từ đú núi với SQL chỉ tạo ra một bản sao cho một bộ giỏ trị. Chẳng hạn
SELECT DISTINCT Lương FROM NHÂNVIấN ;
1.4.2 Trựng lặp trong phộp hợp, phộp giao và phộp trừ
Khụng giống như lệnh SELECT giữ gỡn sự trựng lặp như mặc định và chỉ loại bỏ chỳng khi đưa vào từ khoỏ DISTINCT, cỏc phộp toỏn hợp, giao và trừ thường loại bỏ sự trựng lặp. Như vậy, cỏc tỳi được đổi thành tập hợp và
bản tập hợp của phộp toỏn được ỏp dụng. Để ngăn ngừa việc loại bỏ trựng lặp, chỳng ta phải viết sau cỏc phộp toỏn UNION, INTERSECT, EXCEPT từ khoỏ ALL. Nếu chỳng ta làm như vậy thỡ chỳng ta nhận được cỳ phỏp tỳi thụng qua cỏc phộp toỏn này.
Vớ dụ 26: Xột biểu thức hợp của vớ dụ 14 nhưng cú thờm vào từ khoỏ ALL: (SELECT MósốNV FROM NHÂNVIấN_DỰÁN WHERE MósốDA = 1) UNION ALL (SELECT MósốNV FROM NHÂNVIấN_DỰÁN WHERE MósốDA = 2) Kết quả MósốNV NV001 NV001 NV002 NV018 NV018
Ta thấy bõy giờ trong kết quả xuất hiện cỏc bộ trựng nhau. Nếu một nhõn viờn làm việc cho cả dự ỏn 1 và dự ỏn 2 thỡ mó số của nhõn viờn đú xuất hiện trong kết quả hai lần.
Cũng như đối với UNION, cỏc phộp toỏn INTERSECT ALL và EXCEPT ALL là giao và trừ của cỏc tỳi (bag). Như vậy, nếu R và S là cỏc quan hệ thỡ kết quả của biểu thức
R INTERSECT ALL S
là một quan hệ trong đú số lần xuất hiện của một bộ t là số nhỏ nhất của số lần xuất hiện của bộ đú trong R và số lần xuất hiện của bộ đú trong S.
Kết quả của biểu thức R EXCEPT ALL S
là một quan hệ trong đú số lần xuất hiện bộ t bằng số lần xuất hiện của nú trong R trừ đi số lần xuất hiện của nú trong S với điều kiện hiệu số này là dương.
1.4.3 Nhúm và sự kết hợp trong SQL
Phộp toỏn nhúm và kết hợp trong đại số quan hệ cho phộp ta phõn chia cỏc bộ của một quan hệ thành cỏc nhúm dựa trờn cỏc giỏ trị của một hoặc nhiều thuộc tớnh trong cỏc bộ. Sau đú chỳng ta cú thể kết hợp một số cỏc cột khỏc của quan hệ bằng cỏch ỏp dụng phộp toỏn kết hợp đối với cỏc cột đú. Nếu cú cỏc nhúm thỡ phộp kết hợp sẽ được thực hiện riờng rẽ cho từng nhúm. SQL cung cấp mọi khả năng của phộp toỏn trờn thụng qua việc sử dụng cỏc phộp toỏn nhúm trong mệnh đề SELECT và một mệnh đề GROUP BY đặc biệt.
1.4.4 Cỏc phộp toỏn nhúm
SQL sử dụng 5 phộp toỏn nhúm SUM, AVG, MIN, MAX, và COUNT. Cỏc phộp toỏn này được sử dụng bằng cỏch ỏp dụng chỳng cho cỏc biểu thức cú giỏ trị vụ hướng, thường là một tờn cột, ở trong mệnh đề SELECT. Cú một ngoại lệ là biểu thức COUNT(*), biểu thức này đếm tất cả cỏc bộ trong một quan hệ được thiết lập từ mệnh đề FROM và mệnh đề WHERE của truy vấn. Hơn nữa, chỳng ta cú tuỳ chọn loại trừ trựng lặp ra khỏi cột trước khi ỏp dụng phộp toỏn nhúm bằng việc sử dụng từ khoỏ DISTINCT. Như vậy, một biểu thức như là COUNT(DISTINCT x) đếm số cỏc giỏ trị khỏc nhau trong cột x. Chỳng ta cú thể sử dụng cỏc phộp toỏn khỏc ở vị trớ của COUNT ở đõy nhưng biểu thức như SUM(DISTINCT x) thường khụng cú ý nghĩa mấy, bởi vỡ nú yờu cầu ta tớnh tổng cỏc giỏ trị khỏc nhau trong cột x.
Vớ dụ 27: Truy vấn sau đõy tỡm giỏ trị lương trung bỡnh của tất cả cỏc nhõn viờn:
SELECT AVG(Lương) FROM NHÂNVIấN ;
Chỳ ý rằng ở đõy khụng cú mệnh đề WHERE. Truy vấn này xem xột cột Lương của quan hệ NHÂNVIấN, tớnh tổng cỏc giỏ trị tỡm được ở đõy, một giỏ trị cho mỗi bộ (cho dự nếu bộ là trựng lặp của một vài bộ khỏc), và chia tổng số cho số cỏc bộ. Nếu khụng cú cỏc bộ trựng lặp thỡ truy vấn này cho
lương trung bỡnh như chỳng ta mong đợi. Nếu cú cỏc bộ trựng lặp, thỡ một giỏ trị lương trựng lặp n lần sẽ được tớnh n lần trong trung bỡnh.
Vớ dụ 28:
Truy vấn sau đõy:
SELECT COUNT(*) FROM NHÂNVIấN ;
đếm số cỏc bộ trong quan hệ NHÂNVIấN. Truy vấn tương tự:
SELECT COUNT(Lương) FROM NHÂNVIấN ;
đếm số giỏ trị trong cột Lương của quan hệ. Bởi vỡ cỏc giỏ trị trựng lặp khụng bị loại bỏ khi chỳng ta chiếu lờn cột Lương trong SQL, tổng đếm này sẽ giống như tổng đếm do truy vấn với COUNT(*) sinh ra.
Nếu chỳng ta muốn chắc chắn rằng ta khụng đếm cỏc giỏ trị trựng lặp quỏ một lần, chỳng ta cú thể sử dụng từ khoỏ DISTINCT trước thuộc tớnh nhúm, như:
SELECT COUNT(DISTINCT Lương) FROM NHÂNVIấN ;
Bõy giờ mỗi lương sẽ được đếm một lần, khụng cần quan tõm đến việc nú xuất hiện trong bao nhiờu bộ.
1.4.5 Nhúm
Để nhúm cỏc bộ, chỳng ta sử dụng mệnh đề GROUP BY, đi sau mệnh đề WHERE. Theo sau từ khoỏ GROUP BY là một danh sỏch cỏc thuộc tớnh nhúm. Trong hoàn cảnh đơn giản nhất, chỉ cú một tham chiếu quan hệ trong mệnh đề FROM, và quan hệ này cú cỏc bộ của nú được nhúm theo theo cỏc giỏ trị của chỳng trong cỏc thuộc tớnh nhúm. Dự phộp toỏn nhúm nào được sử dụng trong mệnh đề SELECT cũng chỉ được ỏp dụng bờn trong cỏc nhúm.
Vớ dụ 29: Vấn đề tỡm trong quan hệ NHÂNVIấN tổng lương theo từng đơn vị:
SELECT MósốĐV, SUM(Lương) FROM NHÂNVIấN
GROUP BY MósốĐV ;
Chỳng ta cú thể tưởng tượng là cỏc bộ của quan hệ NHÂNVIấN được sắp xếp lại và được nhúm sao cho tất cỏc cỏc bộ đối với đơn vị 1 là cựng với nhau, tất cả cỏc bộ của đơn vị 4 là cựng với nhau, …. Cỏc tổng của cỏc thành phần Lương của cỏc bộ trong từng nhúm được tớnh toỏn, MósốĐV được đưa ra cựng với tổng đú.
Quan sỏt vớ dụ 29 ta thấy mệnh đề SELECT cú hai loại số hạng:
1. Cỏc kết hợp, ở đú một phộp toỏn nhúm được ỏp dụng cho một thuộc tớnh hoặc một biểu thức bao gồm cỏc thuộc tớnh. Như đó đề cập đến, cỏc số hạng này được tớnh giỏ trị trờn cơ sở từng nhúm. Trong vớ dụ này, SUM(Lương) là một kết hợp.
2.Cỏc thuộc tớnh, chẳng hạn như MósốĐV trong vớ dụ này, xuất hiện trong mệnh đề GROUP BY. Trong một mệnh đề SELECT cú cỏc phộp toỏn nhúm, chỉ những thuộc tớnh nào được đề cập đến trong mệnh đề GROUP BY mới cú thể xuất hiện như cỏc thuộc tớnh khụng nhúm trong mệnh đề SELECT. Khi cỏc truy vấn cú chứa GROUP BY núi chung cú cả cỏc thuộc tớnh nhúm và sự kết hợp trong mệnh đề SELECT, về mặt kỹ thuật khụng cần thiết cú mặt cả hai. Vớ dụ, chỳng ta cú thể viết:
SELECT MósốĐV FROM NHÂNVIấN GROUP BY MósốĐV;
Truy vấn này sẽ nhúm cỏc bộ của NHÂNVIấN theo mó số đơn vị của nú và sau đú in ra mó số đơn vị cho mỗi nhúm, khụng cần quan tõm đến cú bao nhiờu bộ cú cựng mó số đơn vị. Như vậy, truy vấn ở trờn cú cựng kết quả như
SELECT DISTINCT MósốĐV FROM NHÂNVIấN ;
Cú thể sử dụng mệnh đề GROUP BY trong một truy vấn với nhiều quan hệ. Cỏc truy vấn như vậy được thể hiện bằng dóy cỏc bước sau đõy:
1. Tớnh quan hệ R được biểu diễn bằng cỏc mệnh đề FROM và WHERE. Như vậy, quan hệ R là tớch Đềcac của cỏc quan hệ được chỉ ra trong mệnh đề FROM và ỏp dụng phộp chọn của mệnh đề WHERE đối với nú.
2.Nhúm cỏc bộ của R theo cỏc thuộc tớnh trong mệnh đề GROUP BY.
3. Kết quả là cỏc thuộc tớnh và cỏc kết hợp của mệnh đề SELECT được tạo ra cứ như là truy vấn trờn một quan hệ được lưu trữ R.
Vớ dụ 30: Giả sử chỳng ta muốn đưa ra tờn đơn vị và số lượng cỏc nhõn viờn trong từng đơn vị. Chỳng ta cần lấy thụng tin từ hai quan hệ: NHÂNVIấN và ĐƠNVỊ. Chỳng ta bắt đầu bằng cỏch nối tờta chỳng bằng cỏch so sỏnh bằng cỏc mó số đơn vị từ hai quan hệ. Bước này cho chỳng ta một quan hệ mà trong đú mỗi bộ ĐƠNVỊ được cặp với cỏc bộ NHÂNVIấN cú mó số đơn vị giống với mó số đơn vị của nú. Bõy giờ, chỳng ta cú thể nhúm cỏc bộ được chọn của quan hệ này theo tờn của đơn vị. Cuối cựng, chỳng ta đếm số cỏc nhõn viờn trong từng nhúm. Truy vấn được viết như sau:
SELECT TờnĐV, COUNT(*)
FROM NHÂNVIấN NV, ĐƠNVỊ ĐV WHERE NV.MósốĐV = ĐV.MósốĐV GROUP BY TờnĐV ; Kết quả TờnĐV COUNT(*) Nghiờncứu 4 Hànhchớnh 3 Lónhđạo 1
1.4.6 Cỏc mệnh đề HAVING
Giả sử rằng chỳng ta khụng muốn tớnh đến tất cả cỏc tờn đơn vị trong bảng của chỳng ta ở vớ dụ 30 ở trờn. Chỳng ta cú thể hạn chế cỏc bộ trước khi nhúm theo cỏch cú thể làm rỗng cỏc nhúm khụng mong muốn. Vớ dụ, nếu chỳng ta chỉ muốn số cỏc nhõn viờn của một đơn vị phải lớn hơn hoặc bằng 3. Khi đú, chỳng ta tiếp theo mệnh đề GROUP BY một mệnh đề HAVING. Mệnh đề HAVING bao gồm từ khoỏ HAVING theo sau là một điều kiện về nhúm.
Vớ dụ 31: Giả sử chỳng ta muốn in ra Tờn đơn vị và số nhõn viờn trong từng đơn vị đối với những đơn vị nào cú nhiều hơn hoặc bằng 3 nhõn viờn. Chỳng ta cú thể thờm vào vớ dụ 30 mệnh đề
HAVING COUNT(*) >= 3 ;
Truy vấn kết quả được cho như dưới đõy: Kết quả TờnĐV COUNT(*) Nghiờncứu 4
Hànhchớnh 3
Chỳng ta phải nhớ một số quy tắc về cỏc mệnh đề HAVING:
. Một phộp nhúm trong mệnh đề HAVING chỉ ỏp dụng đối với cỏc bộ của nhúm đó được kiểm tra.
. Bất kỳ thuộc tớnh nào của cỏc quan hệ trong mệnh đề FROM đều cú thể được nhúm trong mệnh đề HAVING, nhưng chỉ cú cỏc thuộc tớnh cú thể xuất hiện trong danh sỏch GROUP BY khụng được nhúm trong mệnh đề HAVING (cựng quy tắc như với mệnh đề SELECT).
Một số điều cần nhớ:
* Thứ tự của cỏc mệnh đề trong cỏc truy vấn SQL:
Cho đến bõy giờ chỳng ta đó gặp tất cả sỏu mệnh đề trong một truy vấn “select-from-where”: SELECT, FROM, WHERE, GROUP BY, HAVING và ORDER BY. Chỉ cú hai mệnh đề đầu là bắt buộc, nhưng ta khụng thể sử
dụng mệnh đề HAVING mà khụng cú mệnh đề GROUP BY. Bất kỳ mệnh đề phụ thờm nào cũng phải xuất hiện theo thứ tự ở trờn.
* Nhúm, Tập hợp và Null:
Khi cỏc bộ cú giỏ trị Null, cần nhớ một số quy tắc sau:
• Giỏ trị Null được lờ đi trong tập hợp. Nú khụng gúp phần vào sum, average, hoặc count hoặc khụng là min hoặc max trong cột của chỳng. Vớ dụ, COUNT(*) luụn luụn là một phộp đếm của số cỏc bộ trong một quan hệ, nhưng COUNT(A) là số cỏc bộ với giỏ trị của thuộc tớnh A khụng Null.
• Mặt khỏc, NULL được xử lý như là một giỏ trị thụng thường trong một thuộc tớnh nhúm. Vớ dụ, SELECT a, AVG(b) FROM R sẽ tạo ra một bộ với NULL cho giỏ trị của a và giỏ trị trung bỡnh của b đối với cỏc bộ với a =NULL, nếu cú ớt nhất một bộ trong R với thành phần a là NULL.