Phạm vi họat động của biến con trỏ LocalLocal – 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
Trang 1Bà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ỏ
Trang 2Khai 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.
Trang 3Khai 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 ] ] ]
Trang 4Mở 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ỏ
Trang 5Ví 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
Trang 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ỏ
Trang 7Phạ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
Trang 8Phạ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
Trang 9Phạ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
Trang 10Phạ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
Trang 11Phạ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
Trang 12Phân loại con trỏ
• Static - con trỏ tĩnh
• Keyset – con trỏ keyset
• Dynamic – con trỏ động
Trang 13Static 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?)
Trang 14Con 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ỏ
Trang 15Con 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
Trang 16Dynamic 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
Trang 17Thay đổ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