Módulo 2 · SQL Server / Procedures — Capítulo 07

Tabelas Temporárias e Table Variables

Quando uma procedure precisa de um "rascunho" de dados no meio do caminho: tabelas temporárias (#temp) e variáveis de tabela (@tabela) — e quando usar cada uma.

1. Por que "rascunhos" de dados

Procedures complexas frequentemente precisam calcular um resultado intermediário antes de devolver o resultado final — por exemplo, filtrar um conjunto de clientes, depois cruzar esse conjunto com outra tabela. Guardar esse intermediário exige uma estrutura tipo tabela que existe só durante a execução. T-SQL oferece duas:

Tabela Temporária (#temp)Variável de Tabela (@tabela)
Onde vivetempdb, como uma tabela realtempdb, mas tratada como variável
Aceita índices?Sim, inclusive depois de criadaSó os definidos na declaração (PRIMARY KEY, UNIQUE)
Estatísticas para o otimizadorSim — o otimizador conhece o volume de dadosLimitadas — o otimizador costuma assumir poucas linhas
EscopoVisível em procedures aninhadas chamadas depoisSó no bloco/procedure onde foi declarada
TransaçãoRespeita ROLLBACKSobrevive a um ROLLBACK
Melhor paraVolumes médios/grandes, muitas operaçõesVolumes pequenos (dezenas/centenas de linhas)

2. Tabela temporária (#temp)

SQL criando e usando uma #temp
CREATE PROCEDURE dbo.usp_ClienteRelatorioTop
    @Quantidade INT = 10
AS
BEGIN
    SET NOCOUNT ON;

    CREATE TABLE #ClientesComPedidos
    (
        ClienteId    INT PRIMARY KEY,
        Nome         NVARCHAR(100),
        TotalPedidos INT,
        ValorTotal   DECIMAL(12,2)
    );

    INSERT INTO #ClientesComPedidos (ClienteId, Nome, TotalPedidos, ValorTotal)
    SELECT c.Id, c.Nome, COUNT(p.Id), SUM(p.Valor)
    FROM dbo.Cliente c
    INNER JOIN dbo.Pedido p ON p.ClienteId = c.Id
    GROUP BY c.Id, c.Nome;

    SELECT TOP (@Quantidade) *
    FROM #ClientesComPedidos
    ORDER BY ValorTotal DESC;

    -- opcional: o SQL Server já limpa ao fim da procedure,
    -- mas DROP explícito documenta a intenção
    DROP TABLE #ClientesComPedidos;
END;
GO
Nota

Uma tabela temporária criada com # (uma cerquilha) é local — só existe na sessão atual e desaparece quando a procedure termina. Duas cerquilhas (##) criam uma tabela global, visível para qualquer sessão — uso raro e arriscado (uma sessão pode interferir na outra).

3. Variável de tabela (@tabela)

SQL o mesmo relatório com @tabela
CREATE PROCEDURE dbo.usp_ClienteRelatorioTop
    @Quantidade INT = 10
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @ClientesComPedidos TABLE
    (
        ClienteId    INT PRIMARY KEY,
        Nome         NVARCHAR(100),
        TotalPedidos INT,
        ValorTotal   DECIMAL(12,2)
    );

    INSERT INTO @ClientesComPedidos (ClienteId, Nome, TotalPedidos, ValorTotal)
    SELECT c.Id, c.Nome, COUNT(p.Id), SUM(p.Valor)
    FROM dbo.Cliente c
    INNER JOIN dbo.Pedido p ON p.ClienteId = c.Id
    GROUP BY c.Id, c.Nome;

    SELECT TOP (@Quantidade) *
    FROM @ClientesComPedidos
    ORDER BY ValorTotal DESC;
END;
GO

Repare que a sintaxe de uso é quase idêntica — a diferença real está em como o SQL Server trata cada uma por baixo dos panos, o que só importa na prática quando o volume de linhas cresce.

Atenção

Por não ter estatísticas confiáveis, o otimizador de consultas costuma presumir que uma variável de tabela tem apenas 1 linha, independente do volume real. Isso pode gerar planos de execução ruins quando ela guarda milhares de linhas. Regra prática: até ~1000 linhas, @tabela é seguro; acima disso, prefira #temp.

4. Onde isso te leva

Essas duas estruturas resolvem "preciso de uma tabela temporária dentro da procedure". O próximo capítulo resolve o problema complementar: "preciso receber uma lista de valores como parâmetro" — que é para isso que existem os Table-Valued Parameters.

📌 Resumo do capítulo

  • #temp vive na tempdb como tabela real, com estatísticas e suporte a índices — melhor para volumes maiores.
  • @tabela é mais leve e sobrevive a um ROLLBACK, mas o otimizador assume poucas linhas — melhor para volumes pequenos.
  • ##temp (dupla cerquilha) é global entre sessões — evite, exceto em cenários muito específicos.

✏️ Praticando

  1. Implemente usp_ClienteRelatorioTop das duas formas (#temp e @tabela) e compare o plano de execução de cada uma no SSMS (Display Estimated Execution Plan).
  2. Adicione um índice não-clusterizado em #ClientesComPedidos (coluna ValorTotal) e observe se o plano de execução muda.