(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como concatenar linhas com STRING_AGG no SQL Server

João Barros 10 de July de 2026 4 min de leitura

Juntar vários valores de linhas diferentes numa única string separada por vírgulas é um pedido muito comum em relatórios, listagens e exportações de dados. Durante anos, isto obrigava a truques pouco legíveis com FOR XML PATH. Desde o SQL Server 2017, a função STRING_AGG resolve o mesmo problema numa única expressão, com código mais simples, mais rápido de escrever e fácil de manter.

Pré-requisitos

  • SQL Server 2017 ou superior, ou Azure SQL Database (a função STRING_AGG está disponível a partir dessa versão).
  • Uma ferramenta de consulta como o SQL Server Management Studio (SSMS) ou o Azure Data Studio.
  • Conhecimentos básicos de SELECT e GROUP BY.

Passo 1: Preparar uma tabela de exemplo

Para acompanhar o exemplo, vamos criar uma pequena tabela com vendas por vendedor. Cada linha representa um produto vendido por uma pessoa, com um identificador numérico associado. Execute o seguinte script numa base de dados de testes — nunca em produção:

CREATE TABLE Vendas (
    ProdutoId INT,
    Vendedor  NVARCHAR(50),
    Produto   NVARCHAR(50)
);

INSERT INTO Vendas (ProdutoId, Vendedor, Produto) VALUES
(101, 'Ana',   'Teclado'),
(102, 'Ana',   'Rato'),
(103, 'Ana',   'Webcam'),
(201, 'Bruno', 'Monitor'),
(202, 'Bruno', 'Cabo HDMI');

Repare que a Ana tem três produtos e o Bruno tem dois. O nosso objetivo é obter apenas uma linha por vendedor, com todos os produtos reunidos numa só coluna de texto.

Passo 2: Concatenar valores com STRING_AGG

A função STRING_AGG recebe dois argumentos: a expressão a concatenar e o separador a colocar entre os valores. Quando a combinamos com GROUP BY, cada grupo de linhas é reduzido a um único valor de texto:

SELECT
    Vendedor,
    STRING_AGG(Produto, ', ') AS Produtos
FROM Vendas
GROUP BY Vendedor;

O GROUP BY Vendedor define os grupos e o STRING_AGG junta todos os produtos de cada vendedor, separados por vírgula e espaço. Com apenas quatro linhas de SQL temos o resultado pretendido, sem subconsultas nem funções XML.

Passo 3: Ordenar os valores com WITHIN GROUP

Há um pormenor importante: por omissão, a ordem dos valores concatenados não é garantida pelo motor. Se precisa de um resultado previsível — por exemplo, por ordem alfabética — acrescente a cláusula WITHIN GROUP com um ORDER BY:

SELECT
    Vendedor,
    STRING_AGG(Produto, ', ') WITHIN GROUP (ORDER BY Produto) AS Produtos
FROM Vendas
GROUP BY Vendedor;

Agora os produtos aparecem sempre pela mesma ordem dentro de cada grupo. Isto é essencial quando o resultado é comparado entre execuções ou usado em testes automáticos.

Passo 4: Concatenar números e ignorar valores nulos

O STRING_AGG só opera sobre texto, por isso colunas numéricas ou de data têm de ser convertidas primeiro com CAST ou CONVERT. Um detalhe muito útil: a função ignora automaticamente os valores NULL, sem deixar separadores a mais. Veja como concatenar os identificadores numéricos:

SELECT
    Vendedor,
    STRING_AGG(CAST(ProdutoId AS VARCHAR(10)), ';') AS Ids
FROM Vendas
GROUP BY Vendedor;

Se algum ProdutoId fosse NULL, seria simplesmente ignorado, sem criar separadores duplicados nem exigir tratamento manual.

Dica: para gerar uma lista repartida por linhas em vez de valores lado a lado, use CHAR(10) como separador. Muitas ferramentas mostram então cada item na sua própria linha.

Verificar o resultado

Execute a consulta do Passo 3. Deve obter exatamente duas linhas, uma por cada vendedor:

Vendedor  Produtos
--------  ---------------------------
Ana       Rato, Teclado, Webcam
Bruno     Cabo HDMI, Monitor

Se aparecer uma linha por cada produto em vez de uma por vendedor, então falta o GROUP BY na consulta. Se a ordem dos produtos não for a esperada, reveja a cláusula WITHIN GROUP (ORDER BY ...).

Conclusão

Com uma só função, o STRING_AGG substitui soluções complicadas e torna a concatenação de linhas legível e fácil de manter. A partir daqui, experimente combiná-lo com filtros WHERE para concatenar apenas parte dos dados, usá-lo dentro de vistas para relatórios, ou trocar o separador por uma quebra de linha para criar listas verticais. Qual vai ser a primeira consulta do seu projeto onde substitui um FOR XML PATH antigo por STRING_AGG?