Pergunta

Estou procurando a maneira mais performante de transformar linhas em colunas. Tenho um requisito para produzir o conteúdo do db (não esquema real abaixo, mas o conceito é semelhante) nos formatos de largura fixa e delimitados. O abaixo para a consulta XML Path me dá o resultado que eu quero, mas ao lidar com qualquer outra coisa que não sejam pequenas quantidades de dados, pode levar algum tempo.

 select orderid
   ,REPLACE((  SELECT '  ' + CAST(ProductId as varchar)
       FROM _details d
       WHERE d.OrderId = o.OrderId
       ORDER BY d.OrderId,d.DetailId
       FOR XML PATH('')
   ),' ','') as Products
 from _orders o

Eu olhei para o pivô, mas a maioria dos exemplos que encontrei são informações agregadas. Eu só quero combinar as linhas infantis e colocá -las no pai.

Também devo salientar que não preciso lidar com os nomes das colunas, pois a saída das linhas infantis será uma sequência de largura fixa ou uma string delimitada.

Por exemplo, dadas as seguintes tabelas:

OrderId     CustomerId
----------- -----------
1           1
2           2
3           3

DetailId    OrderId     ProductId
----------- ----------- -----------
1           1           100
2           1           158
3           1           234
4           2           125
5           3           101
6           3           105
7           3           212
8           3           250

Para um pedido, preciso produzir:

orderid     Products
----------- -----------------------
1             100  158  234
2             125
3             101  105  212  250

ou

orderid     Products
----------- -----------------------
1           100|158|234
2           125
3           101|105|212|250

Pensamentos ou sugestões? Estou usando o SQL Server 2K5.

Exemplo de configuração:

   create table _orders (
  OrderId int identity(1,1) primary key nonclustered
  ,CustomerId int
 )

 create table _details (
  DetailId int identity(1,1) primary key nonclustered
  ,OrderId int 
  ,ProductId int
 )

 insert into _orders (CustomerId)
 select 1
 union select 2
 union select 3

 insert into _details (OrderId,ProductId)
 select 1,100
 union select 1,158
 union select 1,234
 union select 2,125
 union select 3,105
 union select 3,101
 union select 3,212
 union select 3,250

 CREATE CLUSTERED INDEX IX_CL__orders on _orders(OrderId)
 CREATE NONCLUSTERED INDEX IX_NCL__orders on _orders(OrderId)
 INCLUDE (CustomerId)

 CREATE CLUSTERED INDEX IX_CL_details on _details(OrderId)
 CREATE NONCLUSTERED INDEX IX_NCL_details on _details(OrderId)
 INCLUDE (DetailId,ProductId)

Usando para o caminho XML:

 select orderid
   ,REPLACE((  SELECT '  ' + CAST(ProductId as varchar)
       FROM _details d
       WHERE d.OrderId = o.OrderId
       ORDER BY d.OrderId,d.DetailId
       FOR XML PATH('')
   ),' ','') as Products
 from _orders o

Qual é produz o que eu quero, no entanto, é muito lento para grandes quantidades de dados. Uma das mesas infantis tem mais de 2 milhões de linhas, elevando o tempo de processamento para ~ 4 horas.

orderid     Products
----------- -----------------------
1             100  158  234
2             125
3             101  105  212  250
Foi útil?

Solução

Por definição, um pivô terá que se agregar de alguma forma, porque você pode ter várias linhas com as mesmas colunas de teclas pivô. Se você não tem várias linhas, tudo bem - mas ainda precisa escolher um operador agregado (min, max, soma).

Mas o FOR XML PATH O construto é melhor para os valores de múltiplas linhas para a operação "pivô" de cordão único.

Não sei por que o seu não está tendo um bom desempenho. Quais índices você tem nas tabelas? Como é o seu plano de execução?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top