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

Creare una funzione con valori di tabella a più istruzioni (MSTVF) in SQL Server

È possibile creare una funzione con valori di tabella a più istruzioni (MSTVF) in SQL Server utilizzando T-SQL CREATE FUNCTION sintassi.

Sintassi

Ecco la sintassi ufficiale per i TVF con più dichiarazioni.

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

Esempio 1 – MSTVF di base

Ecco un esempio di una funzione con valori di tabella a più istruzioni.

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

La struttura della tabella di ritorno è definita all'inizio quando specifico il @pets variabile. I risultati della query vengono inseriti nel @pets variabile.

In questo caso, la funzione richiede che venga passato un pet name come argomento. Quindi utilizza questo argomento nelle query per restituire i dati rilevanti. Essere un multi -istruzione con valori di tabella, posso includere più istruzioni nella definizione della funzione.

Esempio 2:aggiunta di associazione allo schema

Di solito è una buona idea associare allo schema le tue funzioni usando SCHEMABINDING discussione.

In questo modo ti assicurerai che le tabelle sottostanti non possano essere modificate in un modo che potrebbe influire sulla tua funzione.

Senza l'associazione dello schema, le tabelle sottostanti potrebbero essere modificate o addirittura eliminate. Ciò potrebbe interrompere la funzione.

Ecco la stessa funzione, ma questa volta con il binding dello schema:

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

Nota che ho usato nomi in due parti quando ho fatto riferimento alle tabelle nella mia query (ho usato dbo.Cats e dbo.Dogs quando si fa riferimento alla tabella, anziché solo a Cats o Dogs ). Questa operazione è un requisito per lo schema vincolante di un oggetto. Se provi a associare allo schema un oggetto senza utilizzare nomi in due parti, riceverai un errore.

Ora che ho associato allo schema la mia funzione, se provo a eliminare la tabella a cui si fa riferimento nella sua definizione, ottengo un errore:

DROP TABLE Dogs;

Risultato:

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

A proposito, ecco cosa succede se provo a creare la funzione senza usare la denominazione in due parti:

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

Risultato:

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.

Esempio 3:aggiunta della crittografia

Puoi anche crittografare le tue funzioni usando ENCRYPTION discussione.

Ecco un esempio di crittografia della funzione:

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

Ora non riesco a visualizzare la definizione della funzione.

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

Risultato:

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

Viene visualizzato anche un messaggio di errore quando si tenta di eseguire lo script della definizione della funzione tramite Azure Data Studio:

No script was returned when scripting as Create on object UserDefinedFunction

Si noti che il testo di una funzione crittografata è ancora disponibile per gli utenti privilegiati che possono accedere alle tabelle di sistema tramite la porta DAC o accedere direttamente ai file del database. Inoltre, gli utenti che possono collegare un debugger al processo del server possono recuperare la procedura originale dalla memoria in fase di esecuzione.