Eu tenho alguns customer_comments
divididos em várias linhas devido ao design do banco de dados e, para um relatório, preciso combinar o comments
de cada exclusivo id
em uma linha. Eu tentei anteriormente algo trabalhando com esta lista delimitada da cláusula SELECT e do truque COALESCE, mas não consigo recuperá-lo e não devo tê-lo salvo. Também não consigo fazê-lo funcionar neste caso, parece funcionar apenas em uma única linha.
Os dados ficam assim:
id row_num customer_code comments
-----------------------------------
1 1 Dilbert Hard
1 2 Dilbert Worker
2 1 Wally Lazy
Meus resultados precisam ficar assim:
id customer_code comments
------------------------------
1 Dilbert Hard Worker
2 Wally Lazy
Então, para cada um row_num
há realmente apenas uma linha de resultados; os comentários devem ser combinados na ordem de row_num
. O truque vinculado acima SELECT
funciona para obter todos os valores de uma consulta específica como uma linha, mas não consigo descobrir como fazê-lo funcionar como parte de uma SELECT
instrução que exibe todas essas linhas.
Minha consulta precisa percorrer toda a tabela por conta própria e gerar essas linhas. Não estou combinando-os em várias colunas, uma para cada linha, portanto PIVOT
, não parece aplicável.
Isso é relativamente trivial para fazer com uma subconsulta correlacionada. Você não pode usar o método COALESCE destacado na postagem do blog que você mencionou, a menos que você extraia isso para uma função definida pelo usuário (ou a menos que você queira retornar apenas uma linha por vez). Aqui está como eu normalmente faço isso:
Se você tiver um caso em que os dados nos comentários possam conter caracteres não seguros para XML (
>
,<
,&
), altere isso:Para esta abordagem mais elaborada:
(Certifique-se de usar o tipo de dados de destino correto,
varchar
ounvarchar
, e o comprimento correto, e prefixe todos os literais de stringN
se estiver usandonvarchar
.)Se você tiver permissão para usar o CLR em seu ambiente, esse é um caso sob medida para um agregado definido pelo usuário.
Em particular, este é provavelmente o caminho a seguir se os dados de origem não forem muito grandes e/ou você precisar fazer muito esse tipo de coisa em seu aplicativo. Suspeito fortemente que o plano de consulta para a solução de Aaron não será dimensionado bem à medida que o tamanho da entrada aumentar. (Tentei adicionar um índice à tabela temporária, mas isso não ajudou.)
Esta solução, como muitas outras coisas, é uma troca:
EDIT: Bem, eu fui tentar ver se isso realmente era melhor, e acontece que o requisito de que os comentários estejam em uma ordem específica atualmente não é possível satisfazer usando uma função agregada. :(
Consulte SqlUserDefinedAggregateAttribute.IsInvariantToOrder . Basicamente, o que você precisa fazer é,
OVER(PARTITION BY customer_code ORDER BY row_num)
masORDER BY
não é suportado naOVER
cláusula ao agregar. Estou assumindo que adicionar essa funcionalidade ao SQL Server abre uma lata de worms, porque o que precisaria ser alterado no plano de execução é trivial. O link mencionado acima diz que isso está reservado para uso futuro, então isso pode ser implementado no futuro (em 2005 você provavelmente está sem sorte).Isso ainda pode ser feito empacotando e analisando o
row_num
valor na string agregada e, em seguida, fazendo a classificação dentro do objeto CLR ... o que parece bastante hackish.De qualquer forma, abaixo está o código que usei no caso de alguém achar isso útil mesmo com a limitação. Vou deixar a parte de hacking como exercício para o leitor. Observe que usei o AdventureWorks (2005) para dados de teste.
Montagem agregada:
T-SQL para teste (
CREATE ASSEMBLY
, esp_configure
para habilitar o CLR omitido):Aqui está uma solução baseada em cursor que garante a ordem dos comentários por
row_num
. (Veja minha outra resposta para saber como a[dbo].[Comments]
tabela foi preenchida.)