sql >> Database >  >> RDS >> Sqlserver

Maak een Multi-Statement Table-Valued Function (MSTVF) in SQL Server

U kunt een multi-statement table-valued function (MSTVF) in SQL Server maken met behulp van de T-SQL CREATE FUNCTION syntaxis.

Syntaxis

Dit is de officiële syntaxis voor TVF's met meerdere instructies.

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

Voorbeeld 1 – Basis MSTVF

Hier is een voorbeeld van een functie met tabelwaarde met meerdere instructies.

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

De structuur van de retourtabel wordt aan het begin gedefinieerd wanneer ik de @pets . specificeer variabel. De zoekopdrachtresultaten worden ingevoegd in de @pets variabel.

In dit geval vereist de functie dat een koosnaam wordt doorgegeven als argument. Vervolgens gebruikt het dit argument in de query's om de relevante gegevens te retourneren. Een multi zijn -statement met tabelwaardefunctie, ik kan meerdere uitspraken opnemen in de functiedefinitie.

Voorbeeld 2 – Schemabinding toevoegen

Het is meestal een goed idee om uw functies schema te binden met behulp van de SCHEMABINDING argument.

Als u dit doet, zorgt u ervoor dat de onderliggende tabellen niet kunnen worden gewijzigd op een manier die uw functie zou beïnvloeden.

Zonder schemabinding kunnen de onderliggende tabellen worden gewijzigd of zelfs verwijderd. Als u dit doet, kan de functie worden verbroken.

Hier is dezelfde functie, maar deze keer met schemabinding:

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

Merk op dat ik tweedelige namen gebruikte bij het verwijzen naar de tabellen in mijn zoekopdracht (ik gebruikte dbo.Cats en dbo.Dogs bij het verwijzen naar de tabel, in plaats van alleen Cats of Dogs ). Dit is een vereiste om een ​​object via een schema te binden. Als u een object via een schema probeert te binden zonder tweedelige namen te gebruiken, krijgt u een foutmelding.

Nu ik mijn functie schema gebonden heb, krijg ik een foutmelding als ik probeer de tabel waarnaar in de definitie wordt verwezen te laten vallen:

DROP TABLE Dogs;

Resultaat:

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

Trouwens, dit is wat er gebeurt als ik de functie probeer te creëren zonder tweedelige naamgeving te gebruiken:

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

Resultaat:

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.

Voorbeeld 3 – Codering toevoegen

U kunt uw functies ook versleutelen met de ENCRYPTION argument.

Hier is een voorbeeld van het versleutelen van de functie:

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 ik de definitie van de functie niet bekijken.

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

Resultaat:

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

Ik krijg ook een foutmelding wanneer ik de definitie van de functie probeer te scripten via Azure Data Studio:

No script was returned when scripting as Create on object UserDefinedFunction

Merk op dat de tekst van een gecodeerde functie nog steeds beschikbaar is voor bevoorrechte gebruikers die ofwel toegang hebben tot systeemtabellen via de DAC-poort of rechtstreeks toegang hebben tot databasebestanden. Ook kunnen gebruikers die een debugger aan het serverproces kunnen koppelen, de originele procedure tijdens runtime uit het geheugen halen.


  1. Voordelen van MySQLi boven MySQL

  2. Java:CLOB invoegen in de Oracle-database

  3. Hoe top 1 en gesorteerd op datum selecteren in Oracle SQL?

  4. Meerdere SQL-query's in één instructie uitvoeren met PHP