Với kiểu cõu lệnh phức tạp đầu tiờn của PSM, chỳng ta xột cõu lệnh IF. Dạng lệnh này chỉ cú chỳt ớt khỏc lạ. Nú khỏc với C hoặc cỏc ngụn ngữ tương tự ở chỗ:
1. Cõu lệnh kết thỳc với cỏc từ khúa END IF.
2. Cõu lệnh if lồng trong mệnh đề else được mở đầu bằng từ khúa đơn ELSEIF.
Vỡ vậy, dạng chung của một cõu lệnh if giống như đề xuất trong hỡnh 3.9. Điều kiện là một biểu thức cú giỏ trị logic bất kỳ, như cú thể xuất hiện trong mệnh đề WHERE của cõu lệnh SQL. Mỗi danh sỏch cõu lệnh bao gồm những cõu lệnh kết thỳc bởi dấu chấm phảy, nhưng khụng cần được bao quanh bởi BEGIN…END. ELSE cuối cựng và những cõu lệnh của nú là tựy chọn. Vớ dụ IF…THEN…END IF một mỡnh hoặc cựng với ELSEIF đều cú thể chấp nhận.
IF < điều kiện> THEN <danh sỏch cõu lệnh>
ELSEIF <điều kiện > THEN <danh sỏch cõu lệnh>
ELSEIF …
ELSE <danh sỏch cõu lệnh> END IF;
Hỡnh 3.9: Dạng của một cõu lệnh if
Vớ dụ 3.11: Giả sử chỳng ta cú một lược đồ quan hệ
PHIM (Tờnphim, Nămsảnxuất, Độdài, Màu, Tờnxưởngphim, Tờnđạodiễn) Trong đú thuộc tớnh Màu cú kiểu Logic, cú giỏ trị TRUE nếu là phim màu, FALSE nếu là phim đen trắng.
Chỳng ta hóy viết một hàm để lấy năm y và một xưởng phim s, và trả về một giỏ trị boolean là TRUE khi và chỉ khi xưởng phim s sản xuất ớt nhất một bộ phim đen trắng trong năm y hoặc khụng sản xuất bất cứ bộ phim nào ở tất cả mọi thời điểm trong năm đú. Chương trỡnh được trỡnh bày ở hỡnh 3.10
1) CREATE FUNCTION Vớdụ(y INT, s CHAR[15]) RETURNS BOOLEAN
2) IF NOT EXISTS(
3) SELECT * FROM PHIM WHERE Nămsảnxuất = y AND Tờnxuởngphim = s)
4) THEN RETURN TRUE; 5) ELSEIF 1<=
6) (SELECT COUNT(*) FROM PHIM WHERE Nămsảnxuất = y
AND Tờnxưởngphim = s AND NOT Màu)
7) THEN RETURN TRUE; 8) ELSE RETURN FALSE; 9) END IF;
Hỡnh 3.10: Vớ dụ về cõu lệnh IF
Dũng (1) giới thiệu hàm bao gồm cỏc tham số của nú. Chỳng ta khụng cần xỏc định một chế độ cho cỏc tham số, vỡ nú chỉ cú thể là IN cho một hàm. Dũng (2) và (3) kiểm tra trường hợp khi khụng cú bất cứ bộ phim nào của xưởng phim s trong năm y, trong trường hợp đú chỳng ta thiết lập giỏ trị trả về TRUE ở dũng (4). Ghi nhớ rằng dũng (4) khụng là nguyờn nhõn để hàm
trả về. Về kỹ thuật, một dũng điều khiển tuõn theo cỏc cõu lệnh if sinh ra điều khiển nhảy từ dũng (4) tới dũng (9), ở đú hàm hoàn thành và trả về. Nếu xưởng phim s cú làm phim trong năm y, thỡ dũng (5) và (6) kiểm tra xem cú phải ớt nhất một trong số chỳng khụng phải phim mầu. Nếu như vậy, giỏ trị trả về lại được đặt là TRUE, lần này ở dũng (7). Trong trường hợp ngược lại, xưởng phim s cú làm cỏc bộ phim nhưng chỉ toàn là phim mầu, do vậy chỳng ta thiết lập giỏ trị trả về là FALSE ở dũng (8).
3.2.4 Cỏc truy vấn trong PSM
Cú nhiều cỏch sử dụng cỏc truy vấn select-from-where trong PSM.
Cỏc truy vấn con cú thể được sử dụng trong cỏc điều kiện, hoặc tổng quỏt, bất cứ vị trớ nào một truy vấn con được phộp trong SQL. Để minh họa, chỳng ta xem hai vớ dụ về những truy vấn con trong dũng (3) và (6) của hỡnh 3.10.
1. Cỏc truy vấn trả về một giỏ trị đơn cú thể được sử dụng ở bờn phải của cỏc cõu lệnh gỏn.
2. Một cõu lệnh select đơn hàng là một cõu lệnh hợp lệ trong PSM. Nhắc lại là cõu lệnh này cú một mệnh đề INTO chỉ định những biến vào nơi đặt những thành phần của bản ghi được trả về đơn. Những biến này cú thể là những biến địa phương hoặc cỏc tham số của một thủ tục PSM. Dạng tổng quỏt được thảo luận trong ngữ cảnh của SQL nhỳng trong Phần 3.1.5.
3. Chỳng ta cú thể khai bỏo và sử dụng một con trỏ, về cơ bản nú được mụ tả trong Phần 8.1.6 của SQL nhỳng. Việc khai bỏo con trỏ, tất cỏc cõu lệnh OPEN, FETCH, và CLOSE như được mụ tả ở đú, với cỏc ngoại lệ sau:
(a) Khụng cú EXEC SQL xuất hiện trong cỏc cõu lệnh, và (b) Cỏc biến (là cục bộ) khụng sử dụng tiền tố hai chấm CREATE PROCEDURE SomeProc(IN Tendonvi CHAR[15]) DECLARE LuongNQL INTEGER;
SELECT Luong INTO LuongNQL
FROM NHÂNVIấN,ĐƠNVỊ
AND TờnĐV = Tendonvi; …
Hỡnh 3.11: Một select đơn hàng trong PSM
Vớ dụ 3.12: Trong Hỡnh 3.11 là một select đơn hàng của Hỡnh 3.3, làm lại bằng PSM và đặt trong ngữ cảnh một định nghĩa thủ tục giả thuyết. Ghi nhớ rằng, bởi vỡ select đơn hàng trả về một bản ghi cú một thành phần, chỳng ta cũng cú thể nhận ảnh hưởng từ một cõu lệnh chỉ định giống như:
SET LuongNQL = (SELECT Luong FROM NHÂNVIấN,ĐƠNVỊ
WHERE NHÂNVIấN.MósốNV = ĐƠNVỊ.Mó sốNQL
AND TờnĐV = Tendonvi;
Chỳng ta sẽ hoón những vớ dụ của con trỏ cho đến khi chỳng ta học cỏc cõu lệnh lặp PSM trong phần tiếp theo.
3.2.5 Vũng lặp trong PSM
Cấu trỳc vũng lặp cơ bản trong PSM là: LOOP
<danh sỏch tham số> END LOOP;
Người ta thường gắn nhón cho cõu lệnh LOOP, vỡ vậy nú cú thể phỏ vỡ vũng lặp, bằng việc sử dụng cõu lệnh:
LEAVE <nhón vũng lặp>;
Trong trường hợp phổ biến loop tham gia lấy về những bản ghi bằng một con trỏ, chỳng ta thường mong muốn rời bỏ vũng lặp khi khụng cũn bản ghi. Sẽ hữu ớch nếu khai bỏo một tờn trạng thỏi của giỏ trị SQLSTATE, nú chỉ ra rằng khụng tỡm thấy bản ghi nào (tức là khi SQLSTATE = ‘02000’); chỳng ta làm vậy với:
DECLARE Not_Found CONDITION FOR SQLSTATE ‘02000’;
Tổng quỏt hơn, chỳng ta cú thể khai bỏo một trạng thỏi với bất kỳ một tờn mong muốn tương ứng với giỏ trị SQLSTATE bằng
Bõy giờ chỳng ta sẵn sàng dẫn ra một vớ dụ trúi buộc những thao tỏc con trỏ và vũng lặp trong PSM.
Vớ dụ 3.13: Hỡnh 3.12 thể hiện một thủ tục PSM nú nhận một tờn xưởng quay s như một tham số đầu vào và đưa ra tham số đầu ra mean và variance giỏ trị trung bỡnh và sự biến thiờn về độ dài của tất cả những bộ phim của xưởng s. Dũng (1) đến dũng (4) khai bỏo thủ tục và cỏc tham số của nú. Dũng (5) đến dũng (8) là cỏc khai bỏo cục bộ. Chỳng ta định nghĩa Not_Found là tờn của trạng thỏi cú nghĩa là một FETCH thất bại để trả về một bản ghi ở dũng (5). Sau đú, ở dũng (6), con trỏ MovieCursor được định nghĩa để trả về tập hợp những độ dài của những bộ phim của xưởng quay s. Dũng (7) và (8) khai bỏo hai biến cục bộ mà chỳng ta sẽ cần. Số nguyờn newLength lưu giữ kết quả của một FETCH, trong khi movieCount đếm số lượng những bộ phim của xưởng quay s. Chỳng ta cần movieCount bởi vỡ, cuối cựng, chỳng ta cú thể chuyển một tổng cỏc độ dài vào trong một giỏ trị trung bỡnh của cỏc độ dài và một tổng của cỏc bỡnh phương cỏc độ dài vào trong một sự biến thiờn.
Phần cũn lại của cỏc dũng là thõn của thủ tục. Chỳng ta sẽ sử dụng mean và variance là cỏc biến tạm thời, cũng như khi để “trả về” những kết quả cuối cựng. Trong vũng lặp chớnh, mean thực sự nắm giữ tổng của cỏc độ dài, và variance thực sự nắm giữ tổng cỏc bỡnh phương cỏc độ dài. Do vậy, cỏc dũng (9) đến (11) khởi tạo cỏc biến này và tổng số cỏc bộ phim là 0. Dũng (12) mở con trỏ, và dũng (13) đến dũng (19) thiết lập vũng lặp được gỏn nhón movieLoop.
Dũng (14) biểu diễn một fetch, và ở dũng (15) chỳng ta kiểm tra xem những bản ghi khỏc cú đựoc tỡm thấy khụng. Nếu khụng, chỳng ta rời khỏi vũng lặp. Dũng (15) đến (18) tớch lũy cỏc giỏ trị; chỳng ta thờm 1 vào movieCount, thờm độ dài tới mean (nhắc lại, nú tớnh toỏn tổng cỏc độ dài), và chỳng ta thờm bỡnh phương của độ dài tới variance.
Khi tất những bộ phim của xưởng quay s được tỡm thấy, chỳng ta rời khỏi vũng lặp, và điều khiển chuyển đến dũng (20). Ở dũng này, chỳng ta trả chuyển mean thành giỏ trị chớnh xỏc của nú bằng cỏch chia tổng của cỏc độ dài cho tổng số cỏc bộ phim. Ở dũng (21), chỳng ta tạo variance thực sự lưu
giữ sự biến thiờn bằng cỏch chia tổng bỡnh phương của độ dài cho tổng số cỏc bộ phim và trừ cho bỡnh phương của trung bỡnh. Xem Hỡnh 8.2.4 để thảo luận tại sao tớnh toỏn này chớnh xỏc. Dũng (22) đúng con trỏ, và chỳng ta hoàn thành.
1) CREATE PROCEDURE MeanVar(
2) IN s CHAR[[15]],
3) OUT mean REAL,
4) OUT variance REAL )
5) DECLARE Not_Found CONDITION FOR SQLSTATE ‘02000’; 6) DECLARE MovieCursor CURSOR FOR
SELECT Độdài FROM PHIM WHERE Tờnxưởngphim = s; 7) DECLARE newLength INTEGER;
8) DECLARE movieCount INTEGER; BEGIN 9) SET mean = 0.0; 10) SET variance = 0.0; 11) SET movieCount = 0; 12) OPEN MovieCursor; 13) MovieLoop: LOOP
14) FETCH MovieCursor INTO newLength;
15) IF Not_Found THEN LEAVE MovieLoop END IF;
16) SET movieCount = movieCount + 1;
17) SET mean = mean + newLength;
18) SET variance = variance + newLength * newLength;
19) END LOOP;
20) SET mean = mean/movieCount;
21) SET variance = variance/movieCount – mean * mean;
22) CLOSE MovieCursor;
END;
Hỡnh 3.12: Tớnh giỏ trị trung bỡnh và biến thiờn của độ dài cỏc cuốn phim do một xưởng phim sản xuất
3.2.6 Vũng lặp for
Trong PSM cũng cú một cấu trỳc for, nhưng nú cho một mục đớch quan trọng duy nhất: để lặp lại thụng qua một con trỏ. Dạng của cõu lệnh là:
FOR <tờn vũng lặp> AS <tờn con trỏ> CURSOR FOR <truy vấn>
DO
<danh sỏch cõu lệnh> END FOR;
Cõu lệnh này khụng chỉ khai bỏo một con trỏ mà nú cũn vận hành cho chỳng ta một số lượng “cỏc chi tiết khú chịu”: việc mở và đúng con trỏ, việc lấy về và kiểm tra xem cú phải khụng cú bản ghi nào được lấy khụng. Tuy nhiờn, vỡ chỳng ta khụng tự lấy cỏc bản ghi, chỳng ta khụng thể chỉ ra cỏc biến được đặt cho những thành phần nào của bản ghi. Do vậy, cỏc tờn được sử dụng cho cỏc thuộc tớnh trong kết quả của truy vấn cũng được PSM coi như cỏc biến cục bộ cú cựng kiểu.
1) CREATE PROCEDURE MeanVar(
2) IN s CHAR[[15]],
3) OUT mean REAL,
4) OUT variance REAL )
5) DECLARE movieCount INTEGER; BEGIN
6) SET mean = 0.0; 7) SET variance = 0.0;
8) SET movieCount = 0;
9) FOR movieLoop AS MovieCursor CURSOR FOR
SELECT Độdài FROM PHIM WHERE studioName = s;
10) DO
11) SET movieCount = movieCount + 1;
12) SET mean = mean + length ;
13) SET variance = variance + length * length;
14) END FOR;
16) SET variance = variance/movieCount – mean * mean; END;
Hỡnh 3.13: Tớnh giỏ trị trung bỡnh và biến thiờn của độ dài cỏc cuốn phim sử dụng vũng lặp for
3.2.7 Những cõu lệnh lặp khỏc
PSM cũng cho phộp cỏc vũng lặp while và repeat, chỳng cú ý nghĩa như trong C. Như vậy chỳng ta cú thể viết một vũng lặp dưới dạng:
WHILE <Điều kiện> DO <Danh sỏch cỏc lệnh> END WHILE;
Hoặc một vũng lặp dưới dạng REPEAT
<danh sỏch cỏc lệnh> UNTIL < Điều kiện > END REPEAT;
Tiện đõy, nếu chỳng ta gỏn nhón cho cỏc vũng lặp này, hoặc vũng lặp được một lệnh lặp hoặc một lệnh for tạo ra, thỡ chỳng ta cú thể đặt nhón sau END LOOP hoặc sau kết thỳc khỏc cũng được. Ưu điểm của việc làm như vậy là ở chỗ nú làm rừ kết thỳc của mỗi vũng lặp ở đõu và nú cho phộp bộ thụng dịch PSM bắt được một số lỗi ngữ phỏp bao hàm việc bỏ qua một END. Vớ dụ 3.14: Chỳng ta hóy làm lại thủ tục của Hỡnh 3.12 bằng việc sử dụng một vũng lặp for. Mó lệnh được thể hiện trong Hỡnh 3.13. Nhiều thứ khụng thay đổi. Phần khai bỏo của thủ tục từ dũng (1) đến dũng (4) của Hỡnh 3.13 thỡ tương tự, cũng như việc khai bỏo biến cục bộ movieCount ở dũng (5). Tuy nhiờn, chỳng ta khụng cần khai bỏo một con trỏ trong phần khai bỏo của thủ tục nữa, và chỳng ta khụng cần định nghĩa điều kiện Not_Found. Dũng (6) đến dũng (8) khởi tạo cỏc biến, như trước đõy. Sau đú, ở dũng (9) chỳng ta xem vũng lặp for, nú cũng định nghĩa con trỏ MovieCursor. Cỏc dũng (11) đến (13) là thõn của vũng lặp. Ghi nhớ rằng trong cỏc dũng (12)
và (13), chỳng ta tham khảo độ dài lấy về bởi con trỏ bằng thuộc tớnh tờn là length, thay vỡ bằng biến cục bộ newLength, biến này khụng tồn tại trong phiờn bản này của thủ tục. Cỏc dũng (15) và (16) tớnh toỏn cỏc giỏ trị chớnh xỏc cho cỏc biến đầu ra, đỳng như trong phiờn bản trước đõy của thủ tục này. 3.2.8 Những loại trừ trong PSM
Một hệ thống PSM chỉ ra cỏc điều kiện lỗi bằng cỏch thiết lập một chuỗi khỏc khụng cỏc con số trong một xõu năm ký tự SQLSTATE. Chỳng ta đó xem một vớ dụ về những mó này: ‘02000’ của “khụng bản ghi nào được tỡm thấy”. Vớ dụ khỏc, ‘21000’ chỉ ra rằng một select đơn hàng đó trả về nhiều hơn một hàng.
PSM cho phộp chỳng ta khai bỏo một phần mó lệnh, được gọi là bộ điều khiển loại trừ, nú được gọi mỗi khi một lỗi trong danh sỏch những mó lỗi này xuất hiện trong SQLSTATE trong khi thực thi một cõu lệnh hoặc một danh sỏch cỏc cõu lệnh. Mỗi bộ điều khiển loại trừ được liờn kết với một khối mó lệnh, được mụ tả bởi BEGIN…END. Bộ điều khiển xuất hiện trong khối này, và nú chỉ ỏp dụng cho những cõu lệnh trong khối.
Cỏc thành phần của bộ điều khiển là:
Một danh sỏch cỏc điều kiện loại trừ gọi đến bộ điều khiển khi được kớch hoạt.
Mó lệnh được thi hành khi một trong những biểu thức liờn kết được kớch hoạt.
Một chỉ thị vị trớ đến sau khi bộ điều khiển đó kết thỳc cụng việc của nú. Cỏch thức khai bỏo của một bộ điều khiển là:
DECLARE <vị trớ đến> HANDLER FOR <danh sỏch điều kiện> <cõu lệnh>
Cỏc lựa chọn của “vị trớ đến” là:
CONTINUE, nú cú nghĩa là sau khi thực hiện cõu lệnh trong phần khai bỏo điều khiển, chỳng ta thực hiện cõu lệnh sau khi sau cõu lệnh phỏt sinh loại trừ.
EXIT, cú nghĩa rằng sau sự thực thi cõu lệnh của bộ điều khiển, điều khiển rời khỏi khối BEGIN…END ở chỗ bộ điều khiển được khai bỏo. Cõu lệnh sau khối này sẽ được thực hiện tiếp.
UNDO, nú giống như là EXIT, ngoại trừ rằng bất cứ thay đổi nào tới cơ sở dữ liệu hoặc cỏc biến cục bộ được làm bởi cỏc cõu lệnh của khối cho đến bõy giờ bị “thỏo bỏ”. Tức là, những ảnh hưởng của nú bị xúa bỏ, và cũng như là những cõu lệnh này chưa hề được thực hiện.
“Danh sỏch điều kiện” là một danh sỏch những điều kiện được phõn cỏch bởi dấu phảy, chỳng hoặc là những điều kiện được khai bỏo, giống như Not_Found trong dũng (5) của Hỡnh 8.12, hoặc những biểu thức của dạng SQLSTATE và một xõu năm ký tự.
Vớ dụ 3.15: Chỳng ta hóy viết một hàm PSM, hàm này lấy một tiờu đề bộ phim làm tham số và trả về năm của bộ phim. Nếu khụng cú bộ phim nào cú tiờu đề đú hoặc cú nhiều hơn một bộ phim cú tiờu đề đú, thỡ NULL phải được trả về. Mó lệnh được thể hiện trong Hỡnh 3.14.
CREATE FUNCTION GetYear (t VARCHAR[255]) RETURN INTEGER DECLARE Not_Found CONDITION FOR SQLSTATE ‘02000’ ;
DECLARE Too_Many CONDITION FOR SQLSTATE ‘21000’ ; BEGIN
DECLARE EXIT HANDLER FOR Not_Found, Too_Many RETURN NULL ;
RETURN (SELECT Năm FROM PHIM WHERE Tờnphim = t); END;
Hỡnh 3.14 Điều khiển ngoại trừ trong đú một SELECT đơn hàng trả về những cỏi khỏc với một bộ
Dũng (2) và (3) khai bỏo cỏc điều kiện tiờu biểu; chỳng ta khụng phải tạo những định nghĩa này, và cũng cú thể sử dụng cỏc trạng thỏi SQL với việc chỳng đặt trong dũng (4). Dũng (4), (5) và (6) là một khối, ở đú đầu tiờn chỳng ta khai bỏo một bộ điều khiển cho hai điều kiện ở đú hoặc là khụng cú
bản ghi nào được trả về, hoặc cú nhiều hơn một bản ghi được trả về. Hành động của bộ điều khiển, trờn dũng (5), đơn giản là thiết lập giỏ trị trả về là NULL.
Dũng (6) là cõu lệnh làm cụng việc của hàm GetYear. Nú là một cõu lệnh SELECT mong muốn trả về chớnh xỏc một số nguyờn, vỡ đú là hàm giỏ trị hàm GetYear trả về. Nếu chớnh xỏc cú một bộ phim cú tiờu đề t (tham số đầu vào của hàm), thỡ giỏ trị này sẽ được trả về. Tuy nhiờn, nếu một loại trừ phỏt sinh ở dũng (6), hoặc là bởi vỡ khụng cú bộ phim nào cú tiờu đề t hoặc vài bộ phim cú tiờu đề đú, thỡ bộ điều khiển được gọi, một NULL thay thế, bởi trở thành giỏ trị trả về. Hơn nữa, vỡ bộ điều khiển là một bộ điều khiển EXIT,