2009-06-03 21 views
14

Ich arbeite mit einer Tabelle, wo mehrere Zeilen, die ich in Spalten geschwenkt werden müssen. Der Pivot ist also die perfekte Lösung und funktioniert gut, wenn ich nur ein Feld brauche. Ich muss mehrere Felder basierend auf dem Drehpunkt zurückgeben. Hier wird der Pseudo-Code mit Spezifika gezupft:Mehrere Spalten Pivot in T-SQL

SELECT 
    field1, 
    [1], [2], [3], [4] 
FROM 
    (
    SELECT 
    field1, 
    field2, 
    (ROW_NUMBER() OVER(PARTITION BY field1 ORDER BY field2)) RowID 
    FROM tblname 
) AS SourceTable 
PIVOT 
    (
    MAX(field2) 
    FOR RowID IN ([1], [2], [3], [4]) 
) AS PivotTable; 

Die obige Syntax funktioniert hervorragend, aber was soll ich tun, wenn ich weitere Informationen finden müssen, sich in field3, field4 ....?

+2

Was genau brauchen Sie? –

+0

Ich habe es versucht, funktioniert gut für mich (3. Ansatz im Blog). http://dba.stackexchange.com/questions/65786/query-pivot-multiple-columns-variable-number-of-rows – JayaPrakash

Antwort

11

Rewrite MAX mit (CASE ...) und GROUP BY:

select 
    field1 
, [1] = max(case when RowID = 1 then field2 end) 
, [2] = max(case when RowID = 2 then field2 end) 
, [3] = max(case when RowID = 3 then field2 end) 
, [4] = max(case when RowID = 4 then field2 end) 
from (
    select 
    field1 
    , field2 
    , RowID = row_number() over (partition by field1 order by field2) 
    from tblname 
) SourceTable 
group by 
    field1 

Von dort können Sie in field3, field4 hinzufügen usw.

+0

Was ich getan habe, war, CASe-Anweisungen in einem CTE zu verwenden, um diese abgeleitete Tabelle zu füllen, der ich mit zusätzlichen Kriterien beitrat. Hier ist der CTE: – websch01ar

+0

Mit cteSec als ( \t SELECT \t vSec.ID, \t --Secretary 1 ----------------------- - \t MAX ( \t \t CASE vSec.RowID \t \t WHEN 1 THEN vSec.field1 \t \t ELSE '' \t \t END \t) [SEC_OfficePhone1], \t MAX ( \t \t CASE vSec.RowID \t \t WENN 1 DANN vSec.field2 \t \t ELSE '' \t \t END \t) [SEC_OfficeFax1], \t \t FROM \t ( \t --Dieser WIRD DIE INNERE QUERY (es weist Zeilen Sekretär) \t SELECT TOP 100 PERCENT \t \t feld1, field2, ID \t \t (ROW_NUMBER() OVER (PARTITION BY vs.ID ORDER BY vs.ID2)) rowid \t FROM tblname vs \t ORDER BY vs.ID, ID2 \t) VSEC \t GROUP BY \t vSec.ID ) – websch01ar

+0

So durch diese Methode habe ich die Anzahl der Spalten fest einprogrammiert ich erwarte. Ich würde es im Allgemeinen bevorzugen, dies dynamisch zu tun, da es sich ändern muss. Aber als Unternehmen konzentrieren wir uns auf die Reduzierung von Gemeinkosten, so dass ich nicht mehr als vier Sekretäre pro Chef brauche ... Ich gebe Ihnen den Kredit, weil Ihr Beitrag mich auf den Weg gebracht hat, den Fall 20 zu schreiben Aussagen. Dies wirkt wie ein Zauber mit einer Antwort in weniger als einer Sekunde. – websch01ar

1

Ich bin unsicher, ob Sie MS SQL Server verwenden, aber wenn Sie ... Sie möchten vielleicht einen Blick auf die CROSS APPLY-Funktionalität der Engine werfen. Grundsätzlich können Sie die Ergebnisse einer Tabellenwert-UDF auf eine Ergebnismenge anwenden. Dazu müssten Sie Ihre Pivot-Abfrage in eine tabellenwertige Ergebnismenge einfügen.

http://weblogs.sqlteam.com/jeffs/archive/2007/10/18/sql-server-cross-apply.aspx

+0

-1 Kann keine Beziehung mit Frage – Andomar

+0

Die Frage wird markiert und als T-SQL betitelt . Das ist der MS Dialekt .... – RolandTumble

+0

Es ist auch Sybase Dialekt. –

1

wickeln Sie Ihre SQL-Anweisung mit etwas wie:

select a.segment, sum(field2), sum(field3) 
from (original select with case arguments) a 
group by a.segment 

Es sollte Ihre Ergebnisse in eine Zeile reduzieren, gruppiert auf field1.

1

Der Trick mehrere schwenken über einen row_number zu tun, ist, dass die Zeilennummer Sequenz zu modifizieren sowohl die Sequenz zu speichern und die Feldnummer. Hier ist ein Beispiel, das mit mehreren PIVOT-Anweisungen das macht, was Sie wollen.

-- populate some test data 
if object_id('tempdb..#tmp') is not null drop table #tmp 
create table #tmp (
    ID int identity(1,1) not null, 
    MainField varchar(100), 
    ThatField int, 
    ThatOtherField datetime 
) 

insert into #tmp (MainField, ThatField, ThatOtherField) 
select 'A', 10, '1/1/2000' union all 
select 'A', 20, '2/1/2000' union all 
select 'A', 30, '3/1/2000' union all 
select 'B', 10, '1/1/2001' union all 
select 'B', 20, '2/1/2001' union all 
select 'B', 30, '3/1/2001' union all 
select 'B', 40, '4/1/2001' union all 
select 'C', 10, '1/1/2002' union all 
select 'D', 10, '1/1/2000' union all 
select 'D', 20, '2/1/2000' --union all 

-- pivot over multiple columns using the 1.1, 1.2, 2.1, 2.2 sequence trick 
select 
    MainField, 
    max([1.1]) as ThatField1, 
    max([1.2]) as ThatOtherField1, 
    max([2.1]) as ThatField2, 
    max([2.2]) as ThatOtherField2, 
    max([3.1]) as ThatField3, 
    max([3.2]) as ThatOtherField3, 
    max([4.1]) as ThatField4, 
    max([4.2]) as ThatOtherField4 
from 
    (
     select x.*, 
      cast(row_number() over (partition by MainField order by ThatField) as varchar(2)) + '.1' as ThatFieldSequence, 
      cast(row_number() over (partition by MainField order by ThatField) as varchar(2)) + '.2' as ThatOtherFieldSequence 
     from #tmp x 
    ) a 
    pivot (
     max(ThatField) for ThatFieldSequence in ([1.1], [2.1], [3.1], [4.1]) 
    ) p1 
    pivot (
     max(ThatOtherField) for ThatOtherFieldSequence in ([1.2], [2.2], [3.2], [4.2]) 
    ) p2 
group by 
    MainField 
Verwandte Themen