Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Criar uma função com valor de tabela de várias instruções (MSTVF) no SQL Server


Você pode criar uma função com valor de tabela de várias instruções (MSTVF) no SQL Server usando o T-SQL CREATE FUNCTION sintaxe.


Sintaxe


Aqui está a sintaxe oficial para TVFs de várias instruções.
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  
[ ; ]

Exemplo 1 – MSTVF básico


Aqui está um exemplo de uma função com valor de tabela de várias instruções.
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

A estrutura da tabela de retorno é definida no início quando especifico o @pets variável. Os resultados da consulta são inseridos no @pets variável.

Nesse caso, a função requer que um nome de animal de estimação seja passado como argumento. Em seguida, ele usa esse argumento nas consultas para retornar os dados relevantes. Ser um multi -instrução com valor de tabela, posso incluir várias instruções na definição da função.

Exemplo 2 – Adicionar vinculação de esquema


Geralmente é uma boa ideia vincular suas funções usando o método SCHEMABINDING argumento.

Fazer isso garantirá que as tabelas subjacentes não possam ser alteradas de uma maneira que afete sua função.

Sem a associação de esquema, as tabelas subjacentes podem ser modificadas ou até mesmo excluídas. Fazer isso pode quebrar a função.

Aqui está a mesma função, mas desta vez com vinculação de esquema:
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

Observe que usei nomes de duas partes ao fazer referência às tabelas em minha consulta (usei dbo.Cats e dbo.Dogs ao fazer referência à tabela, em vez de apenas Cats ou Dogs ). Fazer isso é um requisito para o esquema vincular um objeto. Se você tentar vincular um objeto ao esquema sem usar nomes de duas partes, receberá um erro.

Agora que vinculei minha função ao esquema, se eu tentar descartar a tabela referenciada em sua definição, recebo um erro:
DROP TABLE Dogs;

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

A propósito, aqui está o que acontece se eu tentar criar a função sem usar nomenclatura de duas partes:
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

Resultado:
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.

Exemplo 3 – Adicionar criptografia


Você também pode criptografar suas funções usando a ENCRYPTION argumento.

Aqui está um exemplo de criptografia da função:
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

Agora não consigo visualizar a definição da função.
SELECT definition 
FROM sys.sql_modules
WHERE object_id = OBJECT_ID('udf_PetsByName_MSTVF');

Resultado:
+--------------+
| definition   |
|--------------|
| NULL         |
+--------------+

Também recebo uma mensagem de erro ao tentar fazer o script da definição da função por meio do Azure Data Studio:
No script was returned when scripting as Create on object UserDefinedFunction

Observe que o texto de uma função criptografada ainda está disponível para usuários privilegiados que podem acessar as tabelas do sistema pela porta DAC ou acessar diretamente os arquivos do banco de dados. Além disso, os usuários que podem anexar um depurador ao processo do servidor podem recuperar o procedimento original da memória em tempo de execução.