Trên thực tế bạn có thể chỉ định trả về hai loại table : - Inline table : với loại này, bạn chỉ có thể thực hiện bên trong nó câu lệnh SELECT rõ ràng không quá phức tạp.. Loại này sẽ lu
Trang 1Hệ Quản Trị CSDL SQL Sever
Chương VI : Hàm Do Người Dùng Định Nghĩa
Bài 1: Khái quát về hàm do người dùng định nghĩa
UDFs là một chương trình con đảm trách một xử lý nào đó với đặc tính là sẽ nhận các tham số đầu vào và trả về một giá trị kết quả xử lý tính toán được dựa trên các tham số đầu vào đã nhận.
I/- Giới thiệu
Hàm do người dùng định nghĩa (user defined functions – UDFs) là một đối tượng mới được bổ sung của phiên bản SQL Server 2000 Trước hết bạn cần biết rằng UDFs mang đầy đủ các ý nghĩa và tính chất của một hàm như đa số các ngôn ngữ lập trình khác, có nghĩa là một UDFs là một chương trình con đảm trách một xử lý nào đó với đặc tính là sẽ nhận các tham số đầu vào và trả về một giá trị kết quả xử lý tính toán được dựa trên các tham số đầu vào đã nhận
Không chỉ UDFs mà tất cả các hàm nói chung (các phiên bản SQL Server trước đây cung cấp các hàm được cài đặt sẵn như getdate(), object_name(), …) có thể phân ra thành hai nhóm : hàm xác định (deterministic) và hàm không xác định (non-deterministic)
Các hàm xác định sẽ luôn luôn trả về cùng giá trị nếu giá trị các tham số được cung cấp (truyền vào) là như nhau
Các hàm không xác định có thể tạo ra các kết quả khác biệt tại mỗi thời điểm chúng được gọi thực hiện, ngay cả khi giá trị các tham số được cung cấp vẫn không thay đổi
Trong một số tài liệu, có thuật ngữ "scalar functions – các hàm vô hướng" dùng
để chỉ các hàm trả về một giá trị, tương phản với nó là các hàm trả về một table
Trang 2Hàm getdate() là một ví dụ điển hình cho cả hai : hàm vô hướng (scalar) và hàm không xác định (non-deterministic) Nếu bạn gọi thực hiện nó hai lần với cùng một dòng lệnh gọi, bạn sẽ nhận được hai kết quả khác nhau và chỉ có duy nhất một giá trị cho mỗi lần gọi
UDFs mang đầy đủ tính chất của một hàm, ngoài ra bạn cũng có thể hình dung UDFs là sự kết hợp của hai đối tượng View và Stored Procedure Hơn thế nữa, nó còn có những tính năng sử dụng mà View và Stored Procedure không có được, hay nói cách khác nó khắc phục một số hạn chế của View và Stored Procedure
Ví dụ :
Stored Procedure không thể là một phần của câu lệnh SELECT như UDFs, View không hỗ trợ sự đệ quy trong khi với UDFs thì bạn có thể làm được điều này
I.1/- Làm việc với UDFs :
I.1.1/- Tạo mới UDFs :
Có hai cách để tạo UDFs : sử dụng câu lệnh T-SQL hoặc dùng tiện ích Enterprise Manager.
- Sử dụng câu lệnh T-SQL :
Dùng câu lệnh CREATE FUNCTION để tạo một UDFs bằng cách sử dụng tiện ích SQL Query Analyzer hoặc sử dụng công cụ dạng dấu nhắc lệnh (command-prompt) điển hình như công cụ oslq
Cú pháp :
Trang 3a/- Mệnh đề CREATE FUNCTION
Việc tạo UDFs bắt đầu với mệnh đề CREATE FUNCTION theo sau là tên của UDFs Ngay sau tên của UDFs là phần khai báo các tham số của UDFs Chú ý là các tham số phải tuân thủ quy tắc của một định danh và phải bắt đầu bằng ký tự @
Về nguyên tắc, một UDFs có thể không có tham số
Ví dụ :
UDFs không có tham số :
Ví dụ :
UDFs có tham số :
b/- Mệnh đề RETURNS
Dùng để thiết lập kiểu dữ liệu trả về của UDFs Có hai cách thiết lập chính :
• Trả về giá trị kiểu vô hướng Khi chỉ định kiểu này, UDFs sẽ trả về giá trị kết quả đơn lẻ như là : một chuỗi, một giá trị logic hoặc một giá trị kiểu số
• Trả về một table Trên thực tế bạn có thể chỉ định trả về hai loại table :
- Inline table : với loại này, bạn chỉ có thể thực hiện bên trong nó câu lệnh
SELECT rõ ràng không quá phức tạp UDFs loại này thực chất được dùng để thay thế cho các đối tượng VIEW, bởi vì nó khắc phục được nhược điểm không có tham
số của VIEW Bạn có thể hình dung một UDFs loại inline table giống như là một VIEW có tham số
Trang 4Ví dụ :
Ví dụ :
Việc tạo view ở ví dụ trên thật khó làm cho ta thỏa mãn bởi trong trường hợp ta muốn danh sách gồm các mặt hàng không phải là loại Tivi thì sao ? VIEW không
hỗ trợ tham số Để giải quyết vấn đề này, bạn có thể tạo ra một UDFs với tham số cho phép truyền vào giá trị loại hàng hóa
Chú ý :
Khi sử dụng UDFs loại inline table, bạn cần quan tâm đến các quy tắc :
• Mệnh đề RETURNS chứa duy nhất từ khóa table Bạn không phải định nghĩa kiểu của biến trả về bởi vì nó là tập được định dạng bởi tập kết quả truy vấn của câu lệnh SELECT trong mệnh đề RETURN
• Không có phần thân của hàm với việc bắt đầu bởi BEGIN và kết thúc với END
• Mệnh đề RETURN chứa một câu lệnh SELECT đơn giản nằm trong cặp dấu ngoặc đơn Câu lệnh SELECT được sử dụng trong hàm có các hạn chế giống như câu lệnh SELECT được sử dụng trong đối tượng VIEW
- Multistatement table : khi bạn chỉ định kiểu này, UDFs trở nên rất giống các
Stored Procedure Nó cho phép thực hiện các câu lệnh SELECT phức tạp, hơn nữa
Trang 5nó còn cho phép thực hiện các câu lệnh logic khác như UPDATE, INSERT INTO,
… Đồng thời bạn có thể thiết lập cấu trúc trong cặp dấu ngoặc đơn ngay sau câu lệnh RETURNS Loại này sẽ luôn trả về một biến table (chỉ duy nhất một biến table)
Ví dụ :
Chú ý :
Khi sử dụng UDFs loại Multistatement table bạn cần quan tâm đến các hạn chế sau :
• Không thể gọi một stored procedure từ các câu lệnh bên trong nó
• Không thể sử dụng các hàm loại không xác định được xây dựng sẵn trong SQL Server, ví dụ Getdate, Rand, …
• Việc sử dụng RAISERROR và @@ERROR là hoàn toàn không hợp lệ
Trang 6• UDFs không thể được sử dụng để sửa đổi thông tin trên table cơ sở.
c/- Mệnh đề AS
Mệnh đề AS được khai báo trước các câu lệnh bên trong UDFs
d/- Khối lệnh BEGIN … END
Phần thân của UDFs được bắt đầu sau từ khóa BEGIN và kết thúc bởi từ khóa END Chú ý rằng khối lệnh này không sử dụng cho trường hợp UDFs loại inline table
- Sử dụng tiện ích Enterprise Manager
Tiện ích Enterprise Manager cho phép bạn có thể tạo các UDFs một cách trực quan hơn, bạn có thể thực hiện theo các bước sau :
Bước 1 : Khởi động tiện ích Enterprise Manager Chọn mục User Defined
Functions và chọn tiếp New User Defined Function.
Trang 7Bước 1 : Xuất hiện màn hình chỉ định các thuộc tính liên quan đến UDFs đồng
thời cho phép gõ vào các câu lệnh trong phần thân của UDFs
I.1.1/- Quản lý UDFs
1/- Thay đổi tên của UDFs
Trên thực tế đôi khi bạn cần sửa đổi tên của UDFs, trong trường hợp này bạn có
thể sử dụng một thủ tục do SQL Server cung cấp sẵn có tên là sp_rename.
Cú pháp :
Trang 8Ví dụ :
Chú ý :
Nếu thực hiện thành công sp_rename sẽ trả về giá trị 0, nếu bị lỗi sẽ trả về giá trị khác 0
2/- Thay đổi nội dung các câu lệnh chứa bên trong UDFs
Để sửa đổi các câu lệnh bên trong UDFs, bạn có thể xóa và tạo lại UDFs Thay
vì vậy, bạn có thể bỏ qua bước xóa bằng cách sử dụng câu lệnh ALTER FUNCTION
Cú pháp của câu lệnh ALTER FUNCTION cũng giống như CREATE FUNCTION, nhưng ALTER FUNCTION không gỡ bỏ UDFs ra khỏi các table hệ thống SysComments và SysObjects
Trang 9Ví dụ :
3/- Xem các UDFs
Khi các UDFs được tạo, tên và thông tin nhận dạng khác liên quan UDFs được lưu trữ trong table hệ thống có tên SysObjects
Bạn có thể sử dụng câu lệnh SELECT để hiển thị các UDFs đang có
Ví dụ :
Chú ý :
• Type = ’IF’ tương ứng với UDFs loại multistatement table và inline table;
Trang 10• Type = ’FN’ tương ứng với UDFs loại scalar.
Bạn có thể truy vấn cột TEXT của table hệ thống SysComments để thấy các câu lệnh chứa bên trong một UDFs Điều này thật hữu ích nếu bạn muốn sửa lại nội dung của một UDFs khi phải đang làm việc trên một tiện ích không phải là Enterprise Manager
Ví dụ :
4/- Xóa UDFs
Xóa một UDFs có nghĩa là gỡ bỏ nó ra khỏi các table hệ thống SysComments và SysObjects Bạn có thể sử dụng câu lệnh DROP FUNCTION để xóa UDFs
Ví dụ :
Trang 11Bài 2 : Các Thao Tác trên UDF
Hàm do người dùng định nghĩa (user DefinedFunction)
Đối với người lập trình (lập trình cơ sở dữ liệu cũng không phải là ngoại lệ) thì công việc viết các thủ tục, hàm là rất cần thiết
Các thủ tục nội tại(Stored procedure) và các hàm của người dùng (UDFs) được lưu trong các database trên server Chúng được gọi thực hiện bằng T-SQL hoặc gọi từ ứng dụng
Kể từ phiên bản SQL Server 2000 trở đi, người lập trình với ngôn ngữ T-SQL được phép tạo ra các hàm của chính mình để sử dụng
Có 3 loại UDF :
- Hàm đơn trị (Scalar Function)
- Hàm đọc bảng (inline Table)
- Hàm tạo bảng(Multi Statement Table)
II.1: Gọi thực hiện các UDF thuộc loại hàm đơn trị
Hàm trả về đúng 1 giá trị, giá trị trả về có thể là kiểu chuỗi , số, ngày, giờ,
Sử dụng cú pháp sau để tạo hàm :
CREATE FUNCTION Tên Hàm (Danh sách tham số)
RETURNS kiểu trả về
BEGIN
- Khai báo các biến cục bộ
- Các lệnh xử lý, tính toán
-Trả về giá trị
RETURN Giá trị trả về
END
Ví dụ : Tạo hàm đơn trị fnTong2So nhập vào hai số nguyên và trả ra hàm số tổng
CREATE FUNCTION fnTong2So(@a INT, @b INT)
RETURNS INT BEGIN
- Khai báo các biến cục bộ
DECLARE @s INT
- Các câu lệnh xử lý, tính toán
SET @s = @a+@b
-Trả về giá trị
RETURN @s
Trang 12-Gọi thực hiện
PRINT dbo.fnTong2So(25,18)
Lưu ý:
Hàm tạo mặc định trong schema dbo nên khi gọi phải có dbo.fnTong2So(25,18) -Xóa hàm trong fnTong2So
DROP FUNCTION fnTong2So
Ví Dụ: Tạo hàm đơn vị fnThamNien nhận vào một ngày vào làm và trả ra số năm
làm việc
CREATE FUNCTION fnThamNien (@Ngay_vao_lamDATETIME)
RETURNS INT
BEGIN
-Khai báo các biến cục bộ
DECLARE@so_nam INT
-Các lệnh xử lý, tính toán
SET @So_nam = YEAR(GETDATE()) – YEAR(@ngay_vao_lam)
-Trả về giá trị
RETURN @so_nam
END
Gọi thực hiện
PRINT dbo.fnThamNien(‘1/27/1989’)
-Gọi thực hiện
SELECT EmployeeID, LoginID, dbo.fnThamNien(HireDate)
FROM HumanResources.Employee
Ví dụ: Tạo hàm đơn trị để lấy dữ liệu
Trong hai ví dụ đầu chỉ mang tính cách minh họa cho việc tạo hàm đơn trị
Tiếp theo giả sử chúng ta cần liệt kê các nhân viên trong bảng
HumanResources.Employee, thông tin liệt kê bao gồm EmployeeID,
FirstName,LastName Nhưng các cột FirstName và LastName chỉ có trong bảng Person Contact, có nhiều cách để giải quyết nhưng sau đây là cách giải quyết nhưng sau đây là cách giải quyết bằng hàm đơn trị:
Trang 13SELECT EmployeeID, dbo.fnGetName(ContactID)Name
FROM HumanResources.Employee
Hàm fnGetName nhận vào một Contact ID và trả ra chuỗi FistName,LastName -Hàm đơn trị
CREATE FUNCTION fnGetName(@ContactID INT)
RETURNS VARCHAR(100)
BEGIN
-Khai báo các biến cục bộ
DECLARE @name VARCHAR(100)
-Các lệnh xử lý , tính toán
SELECT @name FistName+’,’+LastName
FROM Person.Contact
WHERE ContactID = @ContactID
-Trả về giá trị
RETURN @name
END
-Gọi thực hiện
SELECT EmplyeeID,dbo.fnGetName(ContactID)Name
FROM HumanResources.Employee
II.2 Sử dụng các UDF thuộc loại hàm đọc bảng
Hàm trả về một bảng (table) là kết quả của câu lệnh SELECT
Do trong hàm chỉ có đúng một câu SELECT nên được gọi là inline table Function Hàm đọc bảng được xem như View có tham số
Sử dụng cú pháp sau để tạo hàm:
CREATE FUNCTION Ten Ham (Danh sách tham số)
RETURN TABLE
AS
RETURN (Câu lệnh SELECT)
Ví dụ:
Tạo hàm đọc bảng fnLietKeNV nhận vào mã người quản lý và trả về bảng chứa các nhân viên của người quản lý đó
-Hàm đọc bảng
Trang 14CREATE FUNCTION fnLietKeNV@ManagerID INT
RETURN TABLE
AS
RETURN (SELECT EmployeeID,LoginID
FROM HumanResources.Employee
WHERE ManagerID=@ManagerID)
GO
-Gọi thực hiện để xem các nhân viên của người quản lý có mã 21
SELECT * FROM dbo.fnLietKe(21)
-Gọi thực hiện để xem các nhân viên của người quản lý có mã 185
SELECT * FROM dbo.fnLietKeNV(185)
Ví dụ: Sửa lại hàm đọc bảng fnLietKeNV
Giả sử thông tin đọc được muốn có them cột FistName và LastName thì chúng ta phải sửa lại câu lệnh SELECT trong hàm
Có thể làm như sau:
Sử dụng lại hàm đơn trị fnGetName trong ví dụ trước Hàm fnGetName nhận vào một ContactID và trả ra chuỗi FistName,LastName
Hàm fnLietKeNV được sửa lại như sau:
-Sửa lại
ALTER FUNCTION fnLietKeNV@ManagerID INT
RETURN TABLE
AS
RETURN (SELECT EmployeeID,LoginID,dbo.fnGetName(ContactID))Name FROM HumanResouces.Employee
WHERE ManagerID=@ManagerID)
GO
-Gọi thực hiện để xem các nhân viên của người quản lý có mã 185
SELECT * FROM dbo.fnLietKeNV(185)
II.3: Sử dụng các UDF thuộc hàm tạo bảng
Hàm trả về một bảng(table),bảng phải định nghĩa cấu trúc trong hàm
Do trong hàm có nhiều câu lệnh nên được gọi là multi statement Function
Trang 15Sử dụng hàm tạo bảng để tự tạo ra cấu trúc cho bảng,tạo dữ liệu cho bảng và trả về bảng đã tạo
Sử dụng cú pháp sau để tạo hàm:
CREATE FUNCTION Tên Hàm(Danh sách tham số)
RETURN@Tên bảng TABLE(Tên cột Kiểu dữ liệu,…)
AS
-Tạo dữ liệu ban đầu cho bảng
-Cập nhật dữ liệu(nếu muốn)
-Kết thúc
RETUN
END
Ví dụ: tạo hàm tạo bảng fnLietkeNV nhận vào 1 hoặc 0 và trả về nhân viên theo
các yêu cầu sau:
Nếu nhận vào 0 thì các nhân viên trả về gồm có EmployeeID,FirstName
Nếu nhận vào 1 thì các nhân viên trả về gồm có EmployeeID,FirestName và
LastName
-Hàm tạo bảng
CREATE FUNCTION fnLienKetNV(@ten_day_du INT)
RETUNS@bang TABLE(manv INT,ten NVARCHAR(100))
AS
BEGIN
-Tao du lieu ban dau cho bang
IF @ten_day_du=1
INSERT INTO @bang(manv,ten)
SELECT EmployeeID,FirstName+’,’+LastName
FROM HumanResources.Employee e INNER JOIN Person.Contact c
ON e.ContactID=c.ContactID
ELSE
INSERT INTO @bang(manv,ten)
SELECT EmployeeID,FirstName
FROM HumanResources.Employee e INNER JOIN Persion.Contact c
ON e.ContactID=c.ContactID
-Ket thuc
Trang 16END
-Gọi thực hiện để liệt kê FirstName và LastName
SELECT *FROM dbo.fnLietKeTenNV(1)
-Gọi thực hiện để liệt chỉ FirstName
SELECT *FROM dbo.fnLietKeTenNV(0)
Ví dụ: sửa lại hàm tạo bảng fnLietKeTenNV để hiển thị tên chữ HOA
-sửa hàm
ALTER FUNCTION fnLietKeTenNV(@ten_day_du_INT)
RETURNS @bang TABLE(manv INT,ten NVARCHAR(100))
AS
BEGIN
-Tạo du lieu ban dau cho bang
IN @ten_day_du=1
INSERT INTO @bang(manv,ten)
SELECT EmployeeID,FirstName+’,’+LastName
FROM HumanResources.Employee e INNER JOIN Person.Contact c
ON e.ContactID=c.ContactID
ELSE
INSERT INTO @bang(manv,ten)
SELECT EmployeeID,FirstName
FROM HumanResources.Employee e INNER JOIN Person.Contact c
ON e.ContactID=c.ContactID
-Cập nhật dữ liệu sang chữ HOA
UPDATE @bang
SET ten=UPPER(ten)
-Kết Thúc
RETURN
END
-Gọi thực hiện để liệt kê FirstName Và LastName
SELECT * FROM dbo.fnLietKeTenNV(1)