A tabela é:
+----+------+
| Id | Name |
+----+------+
| 1 | aaa |
| 1 | bbb |
| 1 | ccc |
| 1 | ddd |
| 1 | eee |
+----+------+
Saída necessária:
+----+---------------------+
| Id | abc |
+----+---------------------+
| 1 | aaa,bbb,ccc,ddd,eee |
+----+---------------------+
Inquerir:
SELECT ID,
abc = STUFF(
(SELECT ',' + name FROM temp1 FOR XML PATH ('')), 1, 1, ''
)
FROM temp1 GROUP BY id
Esta consulta está funcionando corretamente. Mas eu só preciso da explicação de como isso funciona ou se existe alguma outra maneira, ou curta, de fazer isso.
Estou ficando muito confuso para entender isso.
sql
sql-server
database
Puneet Chawla
fonte
fonte
ID
seja único em uma tabela diferente de entidades diferentes, e esta tabela esteja armazenando coisas que pertencem a elas.Respostas:
Aqui está como funciona:
1. Obtenha a string do elemento XML com FOR XML
A adição de FOR XML PATH ao final de uma consulta permite gerar os resultados da consulta como elementos XML, com o nome do elemento contido no argumento PATH. Por exemplo, se formos executar a seguinte instrução:
Ao passar uma string em branco (FOR XML PATH ('')), obtemos o seguinte:
2. Remova a vírgula inicial com STUFF
A instrução STUFF literalmente "enche" uma string em outra, substituindo caracteres na primeira string. No entanto, estamos usando-a simplesmente para remover o primeiro caractere da lista de valores resultante.
Os parâmetros de
STUFF
são:Então, acabamos com:
3. Inscreva-se no id para obter a lista completa
Em seguida, juntamos isso à lista de IDs na tabela temporária, para obter uma lista de IDs com o nome:
E nós temos o nosso resultado:
Espero que isto ajude!
fonte
LISTAGG
função no Oracle 11gR2. Sinto falta dessa funcionalidade nos dias em que tenho que usá-la. techonthenet.com/oracle/functions/listagg.phplist
função há décadas. Infelizmente, a Microsoft baseou o SQLServer no ASE da Sybase e nunca se incomodou com uma função de lista até o ano passado. Eu concordo - é incompreensível. E então eles chamamstring_agg
. Eu teria pensado quelist
era bastante óbvio.Este artigo aborda várias maneiras de concatenar seqüências de caracteres no SQL, incluindo uma versão aprimorada do seu código que não codifica XML os valores concatenados.
Para entender o que está acontecendo, comece com a consulta interna:
Como você está especificando
FOR XML
, você obterá uma única linha contendo um fragmento XML que representa todas as linhas.Como você não especificou um alias de coluna para a primeira coluna, cada linha seria quebrada em um elemento XML com o nome especificado entre colchetes após o
FOR XML PATH
. Por exemplo, se você tivesseFOR XML PATH ('X')
, obteria um documento XML parecido com:Mas, como você não especificou o nome de um elemento, basta obter uma lista de valores:
Ele
.value('.', 'varchar(max)')
simplesmente recupera o valor do fragmento XML resultante, sem codificar em XML nenhum caractere "especial". Agora você tem uma sequência que se parece com:A
STUFF
função remove a vírgula inicial, fornecendo um resultado final parecido com:Parece bastante confuso à primeira vista, mas tende a funcionar muito bem em comparação com algumas das outras opções.
fonte
TYPE
diretiva diz ao SQL para retornar os dados usando oxml
tipo Sem ele, os dados são retornados como umnvarchar(max)
. É usado aqui para evitar problemas de codificação XML se houver caracteres especiais naname
coluna.TYPE
e.value('.', 'varchar(max)')
, poderá acabar com entidades codificadas em XML no resultado.O modo PATH é usado na geração de XML a partir de uma consulta SELECT
A Saída é um XML centrado no elemento em que cada valor da coluna no conjunto de linhas resultante é agrupado em um elemento de linha. Como a cláusula SELECT não especifica nenhum alias para os nomes das colunas, os nomes dos elementos filhos gerados são iguais aos nomes das colunas correspondentes na cláusula SELECT.
Para cada linha do conjunto de linhas, uma tag é adicionada.
Para a Etapa 2: se você especificar uma cadeia de comprimento zero, o elemento de quebra automática não será produzido.
Na etapa 4, estamos concatenando os valores.
Na Etapa 6, estamos agrupando a data por ID.
STUFF (source_string, start, length, add_string) Parâmetros ou argumentos source_string A cadeia de origem a ser modificada. start A posição no source_string para excluir caracteres de comprimento e, em seguida, insira add_string. length O número de caracteres a serem excluídos do source_string. add_string A sequência de caracteres a serem inseridos no source_string na posição inicial.
fonte
','
especificado como coluna, combinado com o('')
após caminho xml, faz com que a concatenação de ocorrerSELECT 'a' FROM some_table FOR XML PATH('')
vai produzir:'aaaaaaa'
. Mas se o nome da coluna for especificado:SELECT 'a' AS Col FROM some_table FOR XML PATH('')
você obtém resultado:<Col>a</Col><Col>a</Col><Col>a</Col>
Há uma funcionalidade muito nova no Banco de Dados SQL do Azure e no SQL Server (a partir de 2017) para lidar com esse cenário exato. Acredito que isso serviria como um método oficial nativo para o que você está tentando realizar com o método XML / STUFF. Exemplo:
STRING_AGG - https://msdn.microsoft.com/en-us/library/mt790580.aspx
EDIT: Quando publiquei isso originalmente, mencionei o SQL Server 2016, pois achei que vi isso em um recurso em potencial que deveria ser incluído. Lembrei-me que incorretamente ou algo mudou, obrigado pela edição sugerida que corrige a versão. Além disso, fiquei bastante impressionado e não estava totalmente ciente do processo de revisão em várias etapas que me levou a uma opção final.
fonte
Em
for xml path
, se definirmos qualquer valor como[ for xml path('ENVLOPE') ]
, essas tags serão adicionadas a cada linha:fonte
Aqui, na função STUFF da consulta acima, é usada apenas para remover a primeira vírgula
(,)
da string xml gerada,(,aaa,bbb,ccc,ddd,eee)
e ela se tornará(aaa,bbb,ccc,ddd,eee)
.E
FOR XML PATH('')
simplesmente converte os dados da coluna em(,aaa,bbb,ccc,ddd,eee)
string, mas em PATH estamos passando '', para que não crie uma tag XML.E no final, agrupamos os registros usando a coluna ID .
fonte
Eu fiz a depuração e, finalmente, retornei minha consulta 'recheada' para ela da maneira normal.
Simplesmente
fornece o conteúdo da tabela para gravar em uma tabela de log a partir de um gatilho que depuro.
fonte
fonte
STUFF ((SELECT distinto ',' + CAST (T.ID) DA Tabela T, em que T.ID = 1 FOR XML PATH ('')), 1,1, '') AS Name
fonte
Estou frequentemente usando com cláusula where
fonte