Introdução
Criando o nosso primeiro tipo com estrutura de tabela
CREATE TYPE dbo.tpPessoa AS TABLE (
Nome varchar(100),
Idade INT,
Dt_Nascimento DATE
)
Agora, vamos criar uma Stored Procedure simples, que vai receber uma @variavel do tipo tpPessoa, que acabamos de criar e vai simplesmente mostrar na tela esses dados:
CREATE PROCEDURE dbo.stpExibe_Pessoa (
@Pessoa tpPessoa READONLY
)
AS
BEGIN
SELECT *
FROM @Pessoa
END
GO
Após criar essa Stored Procedure, vamos declarar uma @variável utilizando o tipo tpPessoa, inserir alguns valores e depois, executar a Stored Procedure stpExibe_Pessoa, informando a @variável como parâmetro:
DECLARE @Variavel_Pessoa AS tpPessoa
INSERT INTO @Variavel_Pessoa
(
Nome,
Idade,
Dt_Nascimento
)
VALUES
( 'Dirceu Resende', 31, '1987-05-28'),
( 'Patrícia', 31, '1987-01-15'),
( 'Letícia', 21, '1997-04-15')
EXEC dbo.stpExibe_Pessoa
@Pessoa = @Variavel_Pessoa -- tpPessoa
RESULTADO:
E agora, visualizando o código todo de uma vez:
-- Cria o tipo tpPessoa
CREATE TYPE dbo.tpPessoa AS TABLE (
Nome varchar(100),
Idade INT,
Dt_Nascimento DATE
)
GO
-- Cria uma procedure que você irá receber como parâmetro uma variável do tipo tpPessoa
CREATE PROCEDURE dbo.stpExibe_Pessoa (
@Pessoa tpPessoa READONLY
)
AS
BEGIN
SELECT *
FROM @Pessoa
END
GO
-- Instancia uma variável @Variavel_Pessoa, do tipo tpPessoa, popula os dados e executa a SP stpExibe_Pessoa
DECLARE @Variavel_Pessoa AS tpPessoa
INSERT INTO @Variavel_Pessoa
(
Nome,
Idade,
Dt_Nascimento
)
VALUES
( 'Dirceu Resende', 31, '1987-05-28'),
( 'Patrícia', 31, '1987-01-15'),
( 'Letícia', 21, '1997-04-15')
EXEC dbo.stpExibe_Pessoa
@Pessoa = @Variavel_Pessoa -- tpPessoa
Tipos com estruturas de tabelas mais complexas
IF (OBJECT_ID('dbo.stpExibe_Pessoa') IS NOT NULL) DROP PROCEDURE dbo.stpExibe_Pessoa
IF (EXISTS(SELECT NULL FROM sys.types WHERE [name] = 'tpPessoa')) DROP TYPE dbo.tpPessoa
-- Cria o tipo tpPessoa
CREATE TYPE dbo.tpPessoa AS TABLE (
Id INT IDENTITY(1,1) NOT NULL,
Dt_Registro DATETIME NOT NULL DEFAULT GETDATE(), -- Constraint de Check Default
Nome VARCHAR(100) NOT NULL PRIMARY KEY CLUSTERED, -- PRIMARY KEY e ÍNDICE CLUSTERED :)
Dt_Nascimento DATE NULL,
Nr_Documento VARCHAR(11) NOT NULL UNIQUE, -- índice UNIQUE :)
Idade AS (DATEDIFF(YEAR, Dt_Nascimento, GETDATE())) -- Coluna calculada
)
GO
-- Cria uma procedure que você irá receber como parâmetro uma variável do tipo tpPessoa
CREATE PROCEDURE dbo.stpExibe_Pessoa (
@Pessoa tpPessoa READONLY
)
AS
BEGIN
SELECT *
FROM @Pessoa
END
GO
-- Cria uma tabela com alguns dados de teste
IF (OBJECT_ID('tempdb..#Teste') IS NOT NULL) DROP TABLE #Teste
CREATE TABLE #Teste (
Nome VARCHAR(100),
Dt_Nascimento DATETIME,
Nr_Documento VARCHAR(20)
)
INSERT INTO #Teste
(
Nome,
Dt_Nascimento,
Nr_Documento
)
VALUES
( 'Dirceu Resende', '1987-05-28', '1111111'),
( 'Patrícia', '1987-01-15', '2222222'),
( 'Letícia', '1997-04-15', '33333333'),
( 'Erro no UNIQUE', '2018-09-18', '1111111')
-- Instancia uma variável @Variavel_Pessoa, do tipo tpPessoa e popula os dados com a tabela #Teste
DECLARE @Variavel_Pessoa AS tpPessoa
INSERT INTO @Variavel_Pessoa
(
Nome,
Dt_Nascimento,
Nr_Documento
)
SELECT
Nome,
Dt_Nascimento,
Nr_Documento
FROM
#Teste
-- Executa SP stpExibe_Pessoa passando com parâmetro a variável @Variavel_Pessoa do tipo tpPessoa
EXEC dbo.stpExibe_Pessoa
@Pessoa = @Variavel_Pessoa -- tpPessoa
E se a gente tentar criar um índice depois que o tipo tpPessoa foi criado?
CREATE NONCLUSTERED INDEX SK01_tpPessoa ON dbo.tpPessoa(Nr_Documento)
CREATE TYPE dbo.tpPessoa AS TABLE (
Nome VARCHAR(100) NOT NULL,
Nr_Documento VARCHAR(11) NOT NULL,
Idade AS (DATEDIFF(YEAR, Dt_Nascimento, GETDATE())) -- Coluna calculada
) WITH(MEMORY_OPTIMIZED=ON)
GO
Uso de tipos com estrutura de tabela em funções
IF (OBJECT_ID('dbo.fncRetorna_Mais_Velho') IS NOT NULL) DROP FUNCTION dbo.fncRetorna_Mais_Velho
IF (EXISTS(SELECT NULL FROM sys.types WHERE [name] = 'tpPessoa')) DROP TYPE dbo.tpPessoa
-- Cria o tipo tpPessoa
CREATE TYPE dbo.tpPessoa AS TABLE (
Nome VARCHAR(100) NOT NULL, -- PRIMARY KEY e ÍNDICE CLUSTERED :)
Dt_Nascimento DATETIME NOT NULL,
Idade AS (DATEDIFF(YEAR, Dt_Nascimento, GETDATE())) -- Coluna calculada
)
GO
-- Cria uma procedure que você irá receber como parâmetro uma variável do tipo tpPessoa
CREATE FUNCTION dbo.fncRetorna_Mais_Velho (
@Pessoa tpPessoa READONLY
)
RETURNS VARCHAR(100)
AS
BEGIN
RETURN (SELECT TOP(1) Nome FROM @Pessoa ORDER BY Idade DESC)
END
GO
-- Cria uma tabela com alguns dados de teste
IF (OBJECT_ID('tempdb..#Teste') IS NOT NULL) DROP TABLE #Teste
CREATE TABLE #Teste (
Nome VARCHAR(100),
Dt_Nascimento DATETIME
)
INSERT INTO #Teste
(
Nome,
Dt_Nascimento
)
VALUES
( 'Dirceu Resende', '1987-05-28'),
( 'Patrícia', '1987-01-15'),
( 'Letícia', '1997-04-15'),
( 'Erro no UNIQUE', '2018-09-18')
-- Instancia uma variável @Variavel_Pessoa, do tipo tpPessoa e popula os dados com a tabela #Teste
DECLARE @Variavel_Pessoa AS tpPessoa
INSERT INTO @Variavel_Pessoa
SELECT Nome, Dt_Nascimento
FROM #Teste
-- Executa SP stpExibe_Pessoa passando com parâmetro a variável @Variavel_Pessoa do tipo tpPessoa
SELECT dbo.fncRetorna_Mais_Velho(@Variavel_Pessoa)
E se a gente tentar em funções do tipo table-valued ?
IF (OBJECT_ID('dbo.fncRetorna_Datas_Pessoa') IS NOT NULL) DROP FUNCTION dbo.fncRetorna_Datas_Pessoa
IF (EXISTS(SELECT NULL FROM sys.types WHERE [name] = 'tpPessoa')) DROP TYPE dbo.tpPessoa
-- Cria o tipo tpPessoa
CREATE TYPE dbo.tpPessoa AS TABLE (
Nome VARCHAR(100) NOT NULL, -- PRIMARY KEY e ÍNDICE CLUSTERED :)
Dt_Nascimento DATETIME NOT NULL,
Idade AS (DATEDIFF(YEAR, Dt_Nascimento, GETDATE())) -- Coluna calculada
)
GO
-- Cria uma procedure que você irá receber como parâmetro uma variável do tipo tpPessoa
CREATE FUNCTION dbo.fncRetorna_Datas_Pessoa (
@Pessoa tpPessoa READONLY
)
RETURNS TABLE
AS
RETURN
SELECT Nome, YEAR(Dt_Nascimento) AS Ano_Nascimento, MONTH(Dt_Nascimento) AS Mes_Nascimento, DAY(Dt_Nascimento) AS Dia_Nascimento
FROM @Pessoa
GO
-- Cria uma tabela com alguns dados de teste
IF (OBJECT_ID('tempdb..#Teste') IS NOT NULL) DROP TABLE #Teste
CREATE TABLE #Teste (
Nome VARCHAR(100),
Dt_Nascimento DATETIME
)
INSERT INTO #Teste
(
Nome,
Dt_Nascimento
)
VALUES
( 'Dirceu Resende', '1987-05-28'),
( 'Patrícia', '1987-01-15'),
( 'Letícia', '1997-04-15'),
( 'Erro no UNIQUE', '2018-09-18')
-- Instancia uma variável @Variavel_Pessoa, do tipo tpPessoa e popula os dados com a tabela #Teste
DECLARE @Variavel_Pessoa AS tpPessoa
INSERT INTO @Variavel_Pessoa
SELECT Nome, Dt_Nascimento
FROM #Teste
-- Executa SP stpExibe_Pessoa passando com parâmetro a variável @Variavel_Pessoa do tipo tpPessoa
SELECT * FROM dbo.fncRetorna_Datas_Pessoa(@Variavel_Pessoa)
RESULTADO: (funcionou!)
Artigo original em https://www.dirceuresende.com/blog/sql-server-como-passar-uma-tabela-como-parametro-para-stored-procedures-e-funcoes/