在內嵌表值函數中,通過單個 SELECT 語句定義 TABLE 返回值。內嵌函數沒有相關聯的返回變量。
在多語句表值函數中,@return_variable 是 TABLE 變量,用於存儲和累積應作為函數值返回的行。
function_body
指定一系列 Transact-SQL 語句定義函數的值,這些語句合在一起不會產生副作用。function_body 只用於標量函數和多語句表值函數。
在標量函數中,function_body 是一系列合起來求得標量值的 Transact-SQL 語句。
在多語句表值函數中,function_body 是一系列填充表返回變量的 Transact-SQL 語句。
select-stmt
是定義內嵌表值函數返回值的單個 SELECT 語句。
ENCRYPTION
指出 SQL Server 加密包含 CREATE FUNCTION 語句文本的系統表列。使用 ENCRYPTION 可以避免將函數作為 SQL Server 復制的一部分發布。
SCHEMABINDING
指定將函數綁定到它所引用的數據庫對象。如果函數是用 SCHEMABINDING 選項創建的,則不能更改(使用 ALTER 語句)或除去(使用 DROP 語句)該函數引用的數據庫對象。
函數與其所引用對象的綁定關系只有在發生以下兩種情況之一時才被解除:
除去了函數。
在未指定 SCHEMABINDING 選項的情況下更改了函數(使用 ALTER 語句)。
只有在滿足以下條件時,函數才能綁定到架構:
該函數所引用的用戶定義函數和視圖也已綁定到架構。
該函數所引用的對象不是用兩部分名稱引用的。
該函數及其引用的對象屬於同一數據庫。
執行 CREATE FUNCTION 語句的用戶對所有該函數所引用的數據庫對象都具有 REFERENCES 權限。
如果不符合以上條件,則指定了 SCHEMABINDING 選項的 CREATE FUNCTION 語句將失敗。
注釋
用戶定義函數為標量值函數或表值函數。如果 RETURNS 子句指定一種標量數據類型,則函數為標量值函數。可以使用多條 Transact-SQL 語句定義標量值函數。
如果 RETURNS 子句指定 TABLE,則函數為表值函數。根據函數主體的定義方式,表值函數可分為行內函數或多語句函數。
如果 RETURNS 子句指定的 TABLE 不附帶列的列表,則該函數為行內函數。行內函數是使用單個 SELECT 語句定義的表值函數,該語句組成了函數的主體。該函數返回的表的列(包括數據類型)來自定義該函數的 SELECT 語句的 SELECT 列表。
如果 RETURNS 子句指定的 TABLE 類型帶有列及其數據類型,則該函數是多語句表值函數。
多語句函數的主體中允許使用以下語句。未在下面的列表中列出的語句不能用在函數主體中。
賦值語句。
控制流語句。
DECLARE 語句,該語句定義函數局部的數據變量和游標。
SELECT 語句,該語句包含帶有表達式的選擇列表,其中的表達式將值賦予函數的局部變量。
游標操作,該操作引用在函數中聲明、打開、關閉和釋放的局部游標。只允許使用以 INTO 子句向局部變量賦值的 FETCH 語句;不允許使用將數據返回到客戶端的 FETCH 語句。
INSERT、UPDATE 和 DELETE 語句,這些語句修改函數的局部 table 變量。
盡管在用戶定義函數主體中不允許有不確定函數,這些用戶定義函數在調用擴展存儲過程時仍會產生副作用。
由於擴展存儲過程會對數據庫產生副作用,因此調用擴展存儲過程的函數是不確定的。當用戶定義函數調用會對數據庫產生副作用的擴展存儲過程時,不要指望結果集保持一致或執行函數。
從函數中調用擴展存儲過程
從函數內部調用時擴展存儲過程無法向客戶端返回結果集。任何向客戶端返回結果集的 ODS API 都將返回 FAIL。擴展存儲過程可以連接回 Microsoft? SQL Server?;但是,它不應嘗試聯接與喚醒調用擴展存儲過程的函數相同的事務。
與從批處理或存儲過程中喚醒調用相似,擴展存儲過程在運行 SQL Server 的 Windows? 安全帳戶的上下文中執行。存儲過程的所有者在授予用戶 EXECUTE 特權時應考慮這一點。
函數調用
在可使用標量表達式的位置可喚醒調用標量值函數,包括計算列和 CHECK 約束定義。當喚醒調用標量值函數時,至少應使用函數的兩部分名稱。
[database_name.]owner_name.function_name ([argument_expr][,...])
如果用戶定義函數用於定義計算列,則該函數的確定性同樣決定了是否可在該計算列上創建索引。只有當函數具有確定性時,才可以在使用該函數的計算列上創建索引。如果在輸入相同的情況下函數始終返回相同的值,則該函數具有確定性。
可以使用由一部分組成的名稱喚醒調用表值函數。
[database_name.][owner_name.]function_name ([argument_expr][,...])
對於 Microsoft? SQL Server? 2000 中包含的系統表函數,喚醒調用時需在函數名的前面加上前綴"::"。
SELECT *
FROM ::fn_helpcollations()
對於導致語句停止執行然後從存儲過程中的下一語句繼續執行的 Transact-SQL 錯誤,在函數中的處理方式不同。在函數中,這類錯誤會導致函數停止執行。這反過來使喚醒調用該函數的語句停止執行。
權限
用戶應具有執行 CREATE FUNCTION 語句的 CREATE
FUNCTION 權限。
CREATE FUNCTION 的權限默認地授予 sysadmin 固定服務器角色和 db_owner 和 db_ddladmin 固定數據庫角色的成員。sysadmin 和 db_owner 的成員可用 GRANT 語句將 CREATE FUNCTION 權限授予其它登錄。
函數的所有者對其函數具有 EXECUTE 權限。其他用戶不具有 EXECUTE 權限,除非給他們授予了特定函數上的 EXECUTE 權限。
若要創建或更改在 CONSTRAINT、DEFAULT 子句或計算列定義中引用了用戶定義函數的表,用戶還必須對這些函數有 REFERENCES 權限。
示例
A. 計算 ISO 周的標量值用戶定義函數
下例中,用戶定義函數 ISOweek 取日期參數並計算 ISO 周數。為了正確計算該函數,必須在調用該函數前喚醒調用 SET DATEFIRST 1。
CREATE FUNCTION ISOweek (@DATE datetime)
RETURNS int
AS
BEGIN
DECLARE @ISOweek int
SET @ISOweek= DATEPART(wk,@DATE)+1
-DATEPART(wk,CAST(DATEPART(yy,@DATE) as CHAR(4))+'0104')
--Special cases: Jan 1-3 may belong to the previous year
IF (@ISOweek=0)
SET @ISOweek=dbo.ISOweek(CAST(DATEPART(yy,@DATE)-1
AS CHAR(4))+'12'+ CAST(24+DATEPART(DAY,@DATE) AS CHAR(2)))+1
--Special case: Dec 29-31 may belong to the next year
IF ((DATEPART(mm,@DATE)=12) AND
((DATEPART(dd,@DATE)-DATEPART(dw,@DATE))>= 28))
SET @ISOweek=1
RETURN(@ISOweek)
END
下面是函數調用。注意 DATEFIRST 設置為 1。
SET DATEFIRST 1
SELECT master.dbo.ISOweek('12/26/1999') AS 'ISO Week'
下面是結果集。
ISO Week
----------------
52
B. 內嵌表值函數
下例返回內嵌表值函數。
您正在看的SQLserver教程是:sql2k新增加的Function的sqlbook 的幫助。empid, empname, mgrid, title, 0
FROM employees
WHERE empid = @InEmpId
SET @RowsAdded = @@rowcount
-- While new employees were added in the previous iteration
WHILE @RowsAdded > 0
BEGIN
/*Mark all employee records whose direct reports are going to be
found in this iteration with processed=1.*/
UPDATE @reports
SET processed = 1
WHERE processed = 0
-- Insert employees who report to employees marked 1.
INSERT @reports
SELECT e.empid, e.empname, e.mgrid, e.title, 0
FROM employees e, @reports r
WHERE e.mgrid=r.empid and e.mgrid <> e.empid and r.processed = 1
SET @RowsAdded = @@rowcount
/*Mark all employee records whose direct reports have been found
in this iteration.*/
UPDATE @reports
SET processed = 2
WHERE processed = 1
END
-- copy to the result of the function the required columns
INSERT @retFindReports
SELECT empid, empname, mgrid, title
FROM @reports
RETURN
END
GO
-- Example invocation
SELECT *
FROM fn_FindReports('11234')
GO