1
Bài 12: Kiểu dữ liệu con trỏ - Cursor
1. Ý nghĩa sử dụng: Dữ liệu con trỏ cho phép lưu trữ một
tập hợp các mẫu tin từ bảng.
2. Khai báo biến con trỏ
3. Sử dụng biến con trỏ
4. Kiểm tra trạng thái của con trỏ - @@Fetch_Status
5. Phạm vi họat động của biến con trỏ
6. Phân loại con trỏ
7. Cập nhật dữ liệu trong con trỏ
2
Khai báo biến con trỏ
SQL 92 Syntax
DECLARE cursor_name [ INSENSITIVE ] [ SCROLL ]
CURSOR FOR select_statement
[ FOR { READ ONLY | UPDATE [ OF column_name [ , n ] ] } ]
INSENSITIVE – SQL sẽ tạo ra một bảng dữ liệu tạm thời trong
TempDB vì vậy các sửa đổi dữ liệu trong bảng cũ không có tác
dụng lên con trỏ.
SCROLL - Mặc định chỉ cho phép thực hiện FETCH NEXT, nếu có
thêm tham số SCROLL thì có thể thực hiện: FIRST, LAST,
PRIOR, NEXT, RELATIVE, ABSOLUTE
UPDATE [OF column_name [, n]] – danh sách các trường
có thể update dữ liệu. Nếu chỉ có UPDATE thì tất cả các
trường đều có thể cập nhập dữ liệu.
3
Khai báo biến con trỏ (2)
Transact-SQL Extended Syntax
DECLARE cursor_name CURSOR[ LOCAL | GLOBAL ]
[ FORWARD_ONLY | SCROLL ]
[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]
FOR select_statement[ FOR UPDATE [ OF column_name
[ , n ] ] ]
4
Mở con trỏ
Open <ten_contro>
Lấy mẫu tin từ con trỏ
Sau khi mở con trỏ, bước tiếp theo là chúng ta sẽ lấy giá trị các cột
trong các mẫu tin lưu trong con trỏ.
FETCH [ NEXT | PRIOR | FIRST | LAST] FROM cursor_name
[ INTO @variable_name [ , n ] ]
FETCH – Lấy dữ liệu
Next - Đến mẫu tin tiếp theo
Prior -Về mẫu tin trước đó
First –Về mẫu tin đầu tiên
Last – Đến mẫu tin cuối cùng
INTO @variable_name [ , n ] - Dữ liệu của các cột trong mẫu tin sẽ
được đưa vào các biến tương ứng
Sử dụng con trỏ
5
Ví dụ về sử dụng biến con trỏ
use adventureworks
Declare cProd Cursor for select ProductID, Name from
Production.Product
Declare @masp varchar(10), @TenSP nvarchar(30)
Open cProd
Fetch next From cProd into @masp,@tenSP
Print 'Ma san pham := '+@masp +';Ten san pham := '
+@TenSP
close cProd
deallocate cProd
6
@@Fetch_Status để kiểm tra.
0 - Nếu như lấy mẫu tin thành công;
1 - Lấy mẫu tin thất bại với lý do là con trỏ đã ra quá vùng giới hạn BOF hoặc EOF,
2 - Lấy mẫu tin thất bại với lý do là mẫu tin không tồn tại.
use adventureworks
Declare cProd Cursor for select ProductID, Name from
Production.Product
Declare @masp varchar(10), @TenSP nvarchar(30), @STT int
Open cProd
Fetch next From cProd into @masp,@tenSP; set @STT=1
While @@Fetch_Status=0
Begin
Print 'STT:='+ cast(@STT as varchar(4))+';Ma san pham :=
'+@masp +';Ten san pham := ' +@TenSP
Fetch next From cProd into @masp,@tenSP ; set @STT=@STT+1
End
close cProd; deallocate cProd
Kiểm tra trạng thái của con trỏ
7
Phạm vi họat động của biến con trỏ Local
Local – là phạm vi mặc định - chỉ hoạt động trong một thủ tục
Global – có phạm vi hoạt động trong toàn bộ kết nối
Ví dụ: Khai báo con trỏ với phạm vi là local
Tạo 02 thủ tục:
- spCursorLocal1: có khai báo con trỏ cProdLocal truy cập dữ liệu
trong bảng Product và chỉ hiển thị 02 bản ghi đầu tiên.
- spCursorLocal2: gọi thực hiện spCursorLocal1 và sau đó có gắng
sử dụng cProdLocal đã khai báo trong spCursorLocal1 biển hiện thị
các bản ghi còn lại.
=> Trong trường hợp này phát sinh lỗi do phạm vi họat động của con
trỏ local.
8
Phạm vi họat động của biến con trỏ Local (2)
use adventureworks;
alter PROCEDURE spCursorLocal1 as
Declare cProdLocal Cursor local for select ProductID, Name from
Production.Product
Declare @masp varchar(10), @TenSP nvarchar(30), @STT int
Open cProdLocal ;
Fetch next From cProdLocal into @masp,@tenSP; set @STT=1
While ((@STT<3)) and (@@Fetch_Status=0) Hien 02 b-ghi dau
Begin
Print 'STT:='+ cast(@STT as varchar(4))+';Ma san pham :=
'+@masp +';Ten san pham := ' +@TenSP
Fetch next From cProdLocal into @masp,@tenSP; set
@STT=@STT+1
End
9
Phạm vi họat động của biến con trỏ Local (3)
alter PROCEDURE spCursorLocal2 as
declare @STT int, @MaSP varchar(10), @tenSp nvarchar(30)
exec spCursorLocal1; Set @STT=3
Fetch next From cProdLocal into @masp,@tenSP;
While (@@Fetch_Status=0) Hien 02 b-ghi dau
Begin
Print 'STT:='+ cast(@STT as varchar(4))+';Ma san pham := '+@masp
+';Ten san pham := ' +@TenSP
Fetch next From cProdLocal into @masp,@tenSP; set @STT=@STT+1
End
close cProdLocal
deallocate cProdLocal
exec spCursorLocal2
10
Phạm vi họat động của biến con trỏ Local (4)
STT:=1;Ma san pham := 1;Ten san pham := Adjustable Race
STT:=2;Ma san pham := 2;Ten san pham := Bearing Ball
Msg 16916, Level 16, State 1, Procedure spCursorLocal2, Line 7
A cursor with the name 'cProdLocal' does not exist.
Msg 16916, Level 16, State 1, Procedure spCursorLocal2, Line 15
A cursor with the name 'cProdLocal' does not exist.
Msg 16916, Level 16, State 1, Procedure spCursorLocal2, Line 16
A cursor with the name 'cProdLocal' does not exist.
11
Phạm vi họat động của biến con trỏ Global
Sử đổi phạm vi của con trỏ trong spCursorLocal1 thành global, ta xây
dựng một kịch bản tương ứng với hai thủ tục là
spCursorGlobal1 và spCursorGlobal2
12
Phân loại con trỏ
•
Static - con trỏ tĩnh
•
Keyset – con trỏ keyset
•
Dynamic – con trỏ động
13
Static cursor
•
Khi con trỏ này được tạo ra, những mẫu tin được copy vào
một bảng tạm thời trong CSDL tempdb;
•
Con trỏ làm việc với bảng tạm thời do đó những thay đổi
dữ liệu trong bảng gốc không có tác động đến con trỏ;
•
Con trỏ static không cho phép cập nhật dữ liệu.
•
Xem xét kịch bản (Lecture8-StaticCursor.sql):
–
Tạo con trỏ Static – hiển thị dữ liệu trong con trỏ
–
Cập nhật dữ liệu vào bảng dữ liệu gốc – hiển thị
–
Tiếp tục hiển thị lại dữ liệu trong con trỏ (kiểm tra sự
thay đổi của dữ liệu?)
14
Con trỏ Keyset
•
Tập dữ liệu trong khóa được copy vào bảng tạm trong
TempDB.
•
Tập dữ liệu trong khóa phải duy nhất
•
Cho phép thay đổi các trường dữ liệu không phải là khóa
•
Việc thay đổi các trường nonkey sẽ có tác động ngay đến
con trỏ.
•
Việc xóa bản ghi hoặc thay đổi khóa có thể làm con trỏ bị
lỗi.
•
Việc thêm mới bản ghi vào bảng gốc không tác động đến
con trỏ
15
Con trỏ Keyset (2)
•
Xem xét kịch bản (Lecture8-KeySetCursor.sql):
–
Tạo con trỏ KeySet – hiển thị dữ liệu trong con trỏ
–
Cập nhật dữ liệu vào bảng dữ liệu gốc – hiển thị
–
Tiếp tục hiển thị lại dữ liệu trong con trỏ (kiểm tra sự thay đổi
của dữ liệu?)
•
Kiểm tra thêm trường hợp thêm, xóa dữ liệu
16
Dynamic cursor
•
Con trỏ Dynamic không sử dụng đến bảng tạm trong TempDB
mà thao tác trực tiếp với bảng gốc.
•
Khác với con trỏ keyset, dynamic không yêu cầu unique index
•
Mọi thao tác thêm, sửa, xóa đều có tác động ngay lập tức đến
con trỏ Dynamic.
•
Xem kịch bản trong Lecture8-Dynamic.sql:
–
Tạo con trỏ Dynamic – Hiển thị dữ liệu
–
Sửa, thêm dữ liệu bảng gốc
–
Hiện thị dữ liệu trong con trỏ một lần nữa
17
Thay đổi dữ liệu tại vị trí con trỏ
•
Có thể sử dụng Update hoặc Delete để sửa đổi hoặc xóa
bản ghi tại vị trí hiện thởi của con trỏ với mệnh đề Where
current of TEN_CURSOR
•
Chỉ áp dụng với con trỏ dạng KeySet và Dynamic
•
Xem Lecture8-CurrentOfCursor.sql