T-SQL effizienteste Zeile Spalte? Kreuztabellen- für XML-Pfad, Pivot
-
26-09-2019 - |
Frage
Ich bin für die performante Art und Weise Zeilen in Spalten zu drehen. Ich habe eine Verpflichtung zur Ausgabe der Inhalte des db (nicht unbedingt Schemas unten, sondern Konzept ist ähnlich) sowohl in fester Breite und begrenzt Formate. Die unter FOR XML PATH-Abfrage gibt mir das Ergebnis, das ich will, aber wenn sie mit etwas anderes als kleine Datenmengen zu tun, kann eine Weile dauern.
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
Ich habe an einem Dreh aussah, aber die meisten Beispiele habe ich kumulieren Informationen gefunden. Ich will nur die untergeordneten Zeilen kombinieren und sie auf die Eltern heften.
Ich sollte auch ich mit den Spaltennamen, da der Ausgang entweder zu befassen brauchen nicht darauf aus den untergeordneten Zeilen entweder eine Breite Zeichenfolge oder eine Zeichenfolge mit Trennzeichen festgelegt werden.
Zum Beispiel der folgenden Tabellen angegeben:
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
für einen Auftrag muss ich Ausgabe:
orderid Products
----------- -----------------------
1 100 158 234
2 125
3 101 105 212 250
oder
orderid Products
----------- -----------------------
1 100|158|234
2 125
3 101|105|212|250
Die Gedanken oder Anregungen? Ich bin mit SQL Server 2k5.
Beispiel Setup:
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)
mit FOR 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
das gibt, was ich will, ist jedoch sehr langsam für große Datenmengen. Einer der untergeordneten Tabellen ist über 2 Millionen Zeilen, um ca. 4 Stunden, um die Bearbeitungszeit drücken.
orderid Products
----------- -----------------------
1 100 158 234
2 125
3 101 105 212 250
Lösung
Durch die Definition einer PIVOT ist zu haben, in irgendeiner Weise zu aggregieren, da Sie mehrere Zeilen mit den gleichen Drehschlüsselspalten haben. Wenn Sie nicht über mehrere Zeilen, ist das in Ordnung -. Aber immer noch ein Aggregat Operator (MIN, MAX, SUM)
wählen müssen Aber das FOR XML PATH
Konstrukt ist besser für die mehrreihigen-Werte zu Single-String-Spalte "Pivot" -Betrieb.
Ich bin nicht sicher, warum sind Sie nicht gut ab. Welche Indizes haben Sie auf den Tischen? Wie sieht Ihre Ausführungsplan aus?