Możesz utworzyć wieloinstrukcyjną funkcję z wartościami tabelarycznymi (MSTVF) w SQL Server przy użyciu CREATE FUNCTION języka T-SQL składnia.
Składnia
Oto oficjalna składnia wielowyrazowych plików TVF.
CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
[ = default ] [READONLY] }
[ ,...n ]
]
)
RETURNS @return_variable TABLE <table_type_definition>
[ WITH [ ,...n ] ]
[ AS ]
BEGIN
function_body
RETURN
END
[ ; ]
Przykład 1 – Podstawowy MSTVF
Oto przykład funkcji z wartościami w tabeli zawierającej wiele instrukcji.
CREATE FUNCTION dbo.udf_PetsByName_MSTVF( @PetName varchar(70))
RETURNS @pets TABLE (
PetId varchar(20),
PetName varchar(70)
)
AS
BEGIN
INSERT INTO @pets
SELECT
CONCAT('Cat', ' ', CatId),
CatName
FROM dbo.Cats
WHERE CatName = @PetName;
INSERT INTO @pets
SELECT
CONCAT('Dog', ' ', DogId),
DogName
FROM dbo.Dogs
WHERE DogName = @PetName;
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO @pets
VALUES (
'',
'There are no pets of that name.'
)
END
RETURN;
END;
GO
Struktura tabeli zwrotów jest zdefiniowana na początku, kiedy określam @pets zmienny. Wyniki zapytania są wstawiane do @pets zmienna.
W takim przypadku funkcja wymaga podania jako argumentu imienia zwierzaka. Następnie używa tego argumentu w zapytaniach w celu zwrócenia odpowiednich danych. Bycie wieloosobowym -statement funkcja z wartościami tabelarycznymi, mogę zawrzeć wiele instrukcji w definicji funkcji.
Przykład 2 – Dodaj powiązanie schematu
Zwykle dobrym pomysłem jest powiązanie schematu funkcji za pomocą SCHEMABINDING argument.
W ten sposób zapewnisz, że tabel bazowych nie będzie można zmienić w sposób, który wpłynąłby na twoją funkcję.
Bez powiązania schematu bazowe tabele mogą być modyfikowane, a nawet usuwane. Może to spowodować uszkodzenie funkcji.
Oto ta sama funkcja, ale tym razem z powiązaniem schematu:
CREATE FUNCTION dbo.udf_PetsByName_MSTVF( @PetName varchar(70))
RETURNS @pets TABLE (
PetId varchar(20),
PetName varchar(70)
)
WITH SCHEMABINDING
AS
BEGIN
INSERT INTO @pets
SELECT
CONCAT('Cat', ' ', CatId),
CatName
FROM dbo.Cats
WHERE CatName = @PetName;
INSERT INTO @pets
SELECT
CONCAT('Dog', ' ', DogId),
DogName
FROM dbo.Dogs
WHERE DogName = @PetName;
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO @pets
VALUES (
'',
'There are no pets of that name.'
)
END
RETURN;
END;
GO
Zauważ, że podczas odwoływania się do tabel w moim zapytaniu użyłem dwuczęściowych nazw (użyłem dbo.Cats i dbo.Dogs podczas odwoływania się do tabeli, zamiast po prostu Cats lub Dogs ). Jest to wymagane do powiązania obiektu ze schematem. Jeśli spróbujesz powiązać obiekt w schemacie bez użycia dwuczęściowych nazw, otrzymasz błąd.
Teraz, gdy powiązałem schemat z moją funkcją, jeśli spróbuję usunąć tabelę, do której odwołuje się jej definicja, otrzymuję błąd:
DROP TABLE Dogs;
Wynik:
Msg 3729, Level 16, State 1, Line 1 Cannot DROP TABLE 'Dogs' because it is being referenced by object 'udf_PetsByName_MSTVF'.
A tak przy okazji, oto co się stanie, jeśli spróbuję utworzyć funkcję bez używania dwuczęściowego nazewnictwa:
CREATE FUNCTION dbo.udf_PetsByName_MSTVF( @PetName varchar(70))
RETURNS @pets TABLE (
PetId varchar(20),
PetName varchar(70)
)
WITH SCHEMABINDING
AS
BEGIN
INSERT INTO @pets
SELECT
CONCAT('Cat', ' ', CatId),
CatName
FROM Cats
WHERE CatName = @PetName;
INSERT INTO @pets
SELECT
CONCAT('Dog', ' ', DogId),
DogName
FROM Dogs
WHERE DogName = @PetName;
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO @pets
VALUES (
'',
'There are no pets of that name.'
)
END
RETURN;
END;
GO
Wynik:
Msg 4512, Level 16, State 3, Procedure udf_PetsByName_MSTVF, Line 10 Cannot schema bind table valued function 'dbo.udf_PetsByName_MSTVF' because name 'Cats' is invalid for schema binding. Names must be in two-part format and an object cannot reference itself.
Przykład 3 – Dodaj szyfrowanie
Możesz także zaszyfrować swoje funkcje za pomocą ENCRYPTION argument.
Oto przykład szyfrowania funkcji:
CREATE FUNCTION dbo.udf_PetsByName_MSTVF( @PetName varchar(70))
RETURNS @pets TABLE (
PetId varchar(20),
PetName varchar(70)
)
WITH SCHEMABINDING, ENCRYPTION
AS
BEGIN
INSERT INTO @pets
SELECT
CONCAT('Cat', ' ', CatId),
CatName
FROM dbo.Cats
WHERE CatName = @PetName;
INSERT INTO @pets
SELECT
CONCAT('Dog', ' ', DogId),
DogName
FROM dbo.Dogs
WHERE DogName = @PetName;
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO @pets
VALUES (
'',
'There are no pets of that name.'
)
END
RETURN;
END;
GO
Teraz nie mogę wyświetlić definicji funkcji.
SELECT definition
FROM sys.sql_modules
WHERE object_id = OBJECT_ID('udf_PetsByName_MSTVF');
Wynik:
+--------------+ | definition | |--------------| | NULL | +--------------+
Otrzymuję również komunikat o błędzie podczas próby skryptowania definicji funkcji za pomocą Azure Data Studio:
No script was returned when scripting as Create on object UserDefinedFunction
Należy zauważyć, że tekst zaszyfrowanej funkcji jest nadal dostępny dla uprzywilejowanych użytkowników, którzy mogą uzyskiwać dostęp do tabel systemowych przez port DAC lub bezpośrednio uzyskiwać dostęp do plików bazy danych. Ponadto użytkownicy, którzy mogą podłączyć debugger do procesu serwera, mogą pobrać oryginalną procedurę z pamięci w czasie wykonywania.