2010-04-12 29 views
1

Je cherche le moyen le plus performant pour transformer des lignes en colonnes. J'ai une exigence pour sortir le contenu de la base de données (pas le schéma réel ci-dessous, mais le concept est similaire) dans les deux formats de largeur fixe et délimité. La requête FOR XML PATH ci-dessous me donne le résultat que je souhaite, mais en cas d'autre chose que de petites quantités de données, cela peut prendre un certain temps. J'ai regardé pivot, mais la plupart des exemples que j'ai trouvés sont des informations d'agrégation. Je veux juste combiner les rangées d'enfants et les coller sur le parent.t-sql plus efficace ligne à colonne? tableau croisé pour le chemin xml, pivot

Je devrais également souligner que je n'ai pas besoin de traiter les noms de colonnes puisque la sortie des lignes enfant sera soit une chaîne de largeur fixe, soit une chaîne délimitée.

Par exemple, étant donné les tableaux suivants:

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 

pour un ordre que je dois sortie:

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 

pensées ou suggestions? J'utilise SQL Server 2k5.

Exemple de configuration:

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) 

utilisant POUR XML PATH:

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 

qui délivre ce que je veux, mais est très lent pour les grandes quantités de données. Une des tables enfant contient plus de 2 millions de lignes, ce qui fait passer le temps de traitement à ~ 4 heures.

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

Répondre

0

Par définition, un PIVOT va devoir rassembler en quelque sorte, parce que vous pouvez avoir plusieurs lignes avec les mêmes colonnes de clés de pivot. Si vous n'avez pas plusieurs lignes, c'est bien, mais vous devez toujours choisir un opérateur agrégé (MIN, MAX, SUM).

Mais la construction FOR XML PATH est préférable pour l'opération de «pivot» de valeurs de ligne multiple à colonne unique.

Je ne sais pas pourquoi le vôtre ne fonctionne pas bien. Quels index avez-vous sur les tables? À quoi ressemble votre plan d'exécution?

+0

Il existe un index cluster sur la colonne de clé primaire et un index non cluster sur la colonne de clé primaire, avec toutes les autres colonnes du tableau – ajberry

+0

@ajberry - dans la table des détails, vous avez une clé dans OrderId, DetailId Qui comprend ProductId? –

+0

J'ai ajouté les index qui seraient normalement sur la table sous l'exemple de configuration ci-dessus. J'ai besoin de revérifier les index sur les tables réelles, il peut y avoir un réglage là. – ajberry