TSQL Pivot ohne Aggregatfunktion

139

Ich habe einen Tisch wie diesen ...

CustomerID   DBColumnName   Data
--------------------------------------
1            FirstName      Joe
1            MiddleName     S
1            LastName       Smith
1            Date           12/12/2009
2            FirstName      Sam
2            MiddleName     S
2            LastName       Freddrick
2            Date           1/12/2009
3            FirstName      Jaime
3            MiddleName     S
3            LastName       Carol
3            Date           12/1/2009

Und ich will das ...

Ist das mit PIVOT möglich?

CustomerID  FirstName   MiddleName          LastName        Date
----------------------------------------------------------------------
1           Joe             S               Smith           12/12/2009
2           Sam             S               Freddrick       1/12/2009
3           Jaime           S               Carol           12/1/2009
ctrlShiftBryan
quelle

Antworten:

102

Sie können das MAX-Aggregat verwenden, es würde immer noch funktionieren. MAX von einem Wert = dieser Wert ..

In diesem Fall können Sie die Kunden-ID auch fünfmal selbst verbinden und nach dbColumnName pro Tabellenreferenz filtern. Es kann besser funktionieren.

gbn
quelle
1
Das wird eigentlich nicht funktionieren, wenn Sie 2 Kunden mit dem gleichen Vornamen haben
Leonardo
1
Das wird funktionieren. Denken Sie daran, dass DBColumnName Metadaten sind - Sie filtern buchstäblich nach "CustomerID = 1 AND DBColumnName = 'FirstName'". Dies funktioniert natürlich nicht, wenn Sie mehrere FirstName-Zeilen für eine bestimmte CustomerID haben, aber wenn Sie Ihre Tabellen ordnungsgemäß erstellen, sind sowohl CustomerID als auch DBColumnName Teil Ihres Primärschlüssels ...
4AM
7
Einige Codes / Verspottungen als Beispiel wären großartig gewesen und hätten diese Antwort perfekt vervollständigt.
DavidScherer
167

Ja aber warum !!??

   Select CustomerID,
     Min(Case DBColumnName When 'FirstName' Then Data End) FirstName,
     Min(Case DBColumnName When 'MiddleName' Then Data End) MiddleName,
     Min(Case DBColumnName When 'LastName' Then Data End) LastName,
     Min(Case DBColumnName When 'Date' Then Data End) Date
   From table
   Group By CustomerId
Charles Bretana
quelle
2
^^ Das hat bei mir funktioniert. PIVOT ist für nicht numerische Werte nicht effizient.
Dienekes
6
Dies ist eine großartige Alternative. Ich habe Pivotin meiner Abfrage verwendet, dann habe ich zu diesem gewechselt und mir den Ausführungsplan angesehen, um beide zusammen auszuführen. Dieser Ansatz kostete 8% und der Pivot-Ansatz 92%!
Mafue
2
@ CharlesBretana, du bist großartig! Du hast meine Seele gerettet! ) Das ist die beste Lösung. Vielen Dank!
Chaki_Black
3
Ich liebe diese Lösung wirklich, sie stellt auch sicher, dass die Spalten die richtigen Daten anstelle der Pivot-Daten enthalten, danke!
Tenerezza
2
Das funktioniert super! Aber wie kann ich verhindern -Warning: Null value is eliminated by an aggregate or other SET operation
GiddyUpHorsey
22
WITH pivot_data AS
(
SELECT customerid, -- Grouping Column
dbcolumnname, -- Spreading Column
data -- Aggregate Column
FROM pivot2 
)
SELECT customerid, [firstname], [middlename], [lastname]
FROM pivot_data
PIVOT (max(data) FOR dbcolumnname IN ([firstname],[middlename],[lastname])) AS p;
Vishwanath Dalvi
quelle
3
Dies sollte die akzeptierte Antwort sein, da sie die ordnungsgemäße Verwendung des TSQL-Pivot-Befehls zeigt.
Ubercoder
1
Es ist erwähnenswert, dass in dieser Abfrage "pivot2" der Name der Tabelle ist, in der sich die Originaldaten befinden. Auch die Verwendung des CTE ist hier überflüssig - die SELECTAnweisung unter dem CTE hätte nur den Namen der Originaltabelle angeben können.
STLDev
@STLDev Eigentlich funktioniert STLDev nicht so. Wir kennen nicht alle Spalten in der Tabelle "pivot2". Es könnte tatsächlich andere Spalten geben, die OP nicht angegeben hat und die in der Tabelle enthalten sind. Wenn Sie also die Spalten nicht einschränken - mithilfe einer CTE- oder abgeleiteten Tabellenabfrage -, werden ALLE Spalten in der Tabelle in der Gruppierung verwendet. Mit anderen Worten, der PIVOT gibt etwas zurück, aber nicht das, was wir erwarten. Dies ist ein Konzept, das ausführlich für die Zertifizierungsprüfung 70-761 behandelt wird.
Zorkolot
2
Es ist erwähnenswert, dass PIVOT automatisch nach Spalten gruppiert, die im PIVOT selbst nicht verwendet werden. In diesem Beispiel befinden sich [data] und [dbcolumnname] im PIVOT, sodass alles nach [CustomerId] gruppiert wird
Sal
9
SELECT
main.CustomerID,
f.Data AS FirstName,
m.Data AS MiddleName,
l.Data AS LastName,
d.Data AS Date
FROM table main
INNER JOIN table f on f.CustomerID = main.CustomerID
INNER JOIN table m on m.CustomerID = main.CustomerID
INNER JOIN table l on l.CustomerID = main.CustomerID
INNER JOIN table d on d.CustomerID = main.CustomerID
WHERE f.DBColumnName = 'FirstName' 
AND m.DBColumnName = 'MiddleName' 
AND l.DBColumnName = 'LastName' 
AND d.DBColumnName = 'Date' 

Bearbeiten: Ich habe dies ohne Editor geschrieben und die SQL nicht ausgeführt. Ich hoffe, Sie haben die Idee.

shahkalpesh
quelle
9

Ok, entschuldige die arme Frage. gbn hat mich auf den richtigen Weg gebracht. Das habe ich in einer Antwort gesucht.

SELECT [FirstName], [MiddleName], [LastName], [Date] 
FROM #temp 
PIVOT
(   MIN([Data]) 
    FOR [DBColumnName] IN ([FirstName], [MiddleName], [LastName], [Date]) 
)AS p

Dann musste ich eine while-Anweisung verwenden und die obige Anweisung als varchar erstellen und dynmaic sql verwenden.

Mit so etwas

SET @fullsql = @fullsql + 'SELECT ' + REPLACE(REPLACE(@fulltext,'(',''),')','')
SET @fullsql = @fullsql + 'FROM #temp '
SET @fullsql = @fullsql + 'PIVOT'
SET @fullsql = @fullsql + '('
SET @fullsql = @fullsql + ' MIN([Data])'
SET @fullsql = @fullsql + ' FOR [DBColumnName] IN '+@fulltext
SET @fullsql = @fullsql + ')'
SET @fullsql = @fullsql + 'AS p'

EXEC (@fullsql)

Sie müssen @fulltext mithilfe einer while-Schleife erstellen und die verschiedenen Spaltennamen aus der Tabelle auswählen. Danke für die Antworten.

ctrlShiftBryan
quelle
6

Das OP musste sich eigentlich nicht ohne Agregation drehen, aber für diejenigen von Ihnen, die hierher kommen, um zu wissen, wie man sieht:

SQL-parametrisierte CTE-Abfrage

Die Antwort auf diese Frage beinhaltet eine Situation, in der ein Pivot ohne Aggregation erforderlich ist, sodass ein Beispiel dafür Teil der Lösung ist.

bielawski
quelle
1

Versuche dies:

SELECT CUSTOMER_ID, MAX(FIRSTNAME) AS FIRSTNAME, MAX(LASTNAME) AS LASTNAME ...

FROM
(

SELECT CUSTOMER_ID, 
       CASE WHEN DBCOLUMNNAME='FirstName' then DATA ELSE NULL END AS FIRSTNAME,
       CASE WHEN DBCOLUMNNAME='LastName' then DATA ELSE NULL END AS LASTNAME,
        ... and so on ...
GROUP BY CUSTOMER_ID

) TEMP

GROUP BY CUSTOMER_ID
user3538033
quelle
1

Das sollte funktionieren:

select * from (select [CustomerID]  ,[Demographic] ,[Data]
from [dbo].[pivot]
) as Ter

pivot (max(Data) for  Demographic in (FirstName, MiddleName, LastName, [Date]))as bro
Randy Boamah
quelle
1

Hier ist eine großartige Möglichkeit, dynamische Felder für eine Pivot-Abfrage zu erstellen:

- Werte in eine tmp-Tabelle zusammenfassen

declare @STR varchar(1000)
SELECT  @STr =  COALESCE(@STr +', ', '') 
+ QUOTENAME(DateRange) 
from (select distinct DateRange, ID from ##pivot)d order by ID

--- siehe die generierten Felder

print @STr

exec('  .... pivot code ...
pivot (avg(SalesAmt) for DateRange IN (' + @Str +')) AS P
order by Decile')
user7237698
quelle