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.