sql >> Database teknologi >  >> RDS >> Sqlserver

Opret en Multi-Statement Table-Valued Function (MSTVF) i SQL Server

Du kan oprette en multi-statement table-valued function (MSTVF) i SQL Server ved hjælp af T-SQL CREATE FUNCTION syntaks.

Syntaks

Her er den officielle syntaks for multi-statement TVF'er.

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  
[ ; ]

Eksempel 1 – Grundlæggende MSTVF

Her er et eksempel på en funktion med flere sætninger i tabelværdier.

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

Returtabellens struktur er defineret i starten, når jeg angiver @pets variabel. Forespørgselsresultaterne indsættes i @pets variabel.

I dette tilfælde kræver funktionen, at et kæledyrsnavn sendes ind som et argument. Det bruger derefter dette argument i forespørgslerne for at returnere de relevante data. At være en multi -sætning tabel-værdi funktion, kan jeg inkludere flere udsagn i funktionens definition.

Eksempel 2 – Tilføj skemabinding

Det er normalt en god idé at skemabinde dine funktioner ved at bruge SCHEMABINDING argument.

Dette vil sikre, at de underliggende tabeller ikke kan ændres på en måde, der ville påvirke din funktion.

Uden skemabinding kunne de underliggende tabeller ændres eller endda slettes. Dette kan ødelægge funktionen.

Her er den samme funktion, men denne gang med skemabinding:

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

Bemærk, at jeg brugte todelte navne, når jeg refererede til tabellerne i min forespørgsel (jeg brugte dbo.Cats og dbo.Dogs når man refererer til tabellen, i stedet for kun Cats eller Dogs ). At gøre dette er et krav for skemabinding af et objekt. Hvis du forsøger at skemabinde et objekt uden at bruge todelte navne, får du en fejl.

Nu hvor jeg har skemabundet min funktion, får jeg en fejlmeddelelse, hvis jeg forsøger at droppe tabellen, der henvises til i dens definition:

DROP TABLE Dogs;

Resultat:

Msg 3729, Level 16, State 1, Line 1
Cannot DROP TABLE 'Dogs' because it is being referenced by object 'udf_PetsByName_MSTVF'.

Forresten, her er hvad der sker, hvis jeg forsøger at oprette funktionen uden at bruge todelt navngivning:

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

Resultat:

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.

Eksempel 3 – Tilføj kryptering

Du kan også kryptere dine funktioner ved at bruge ENCRYPTION argument.

Her er et eksempel på kryptering af funktionen:

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

Nu kan jeg ikke se funktionens definition.

SELECT definition 
FROM sys.sql_modules
WHERE object_id = OBJECT_ID('udf_PetsByName_MSTVF');

Resultat:

+--------------+
| definition   |
|--------------|
| NULL         |
+--------------+

Jeg får også en fejlmeddelelse, når jeg forsøger at scripte funktionens definition via Azure Data Studio:

No script was returned when scripting as Create on object UserDefinedFunction

Bemærk, at en krypteret funktions tekst stadig er tilgængelig for privilegerede brugere, der enten kan få adgang til systemtabeller over DAC-porten eller direkte få adgang til databasefiler. Brugere, der kan knytte en debugger til serverprocessen, kan også hente den originale procedure fra hukommelsen under kørsel.


  1. Sådan sikkerhedskopieres RAC VM'er

  2. MySQL:Kan ikke oprette tabel (fejlnr:150)

  3. MySQL-brugerrettigheder på delte servere

  4. scope_identity vs ident_current