TSQL Pivot senza funzione aggregata


139

Ho un tavolo come questo ...

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

E voglio questo ...

È possibile usare PIVOT?

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

Risposte:


102

È possibile utilizzare l'aggregato MAX, funzionerebbe comunque. MAX di un valore = quel valore ..

In questo caso, puoi anche unirti a te stesso 5 volte su customerid, filtrando per dbColumnName per riferimento della tabella. Potrebbe funzionare meglio.


1
che in realtà non funzionerà se hai 2 clienti con lo stesso nome
Leonardo

1
Funzionerà Ricorda che DBColumnName è metadata: filtra letteralmente per "CustomerID = 1 AND DBColumnName = 'FirstName'". Naturalmente, questo si rompe se si dispone di più righe FirstName per un determinato CustomerID, ma se si sta creando le tabelle correttamente sia CustomerID e DBColumnName fanno parte della vostra chiave primaria ...
04:00

7
Un po 'di codice / derisione come esempio sarebbe stato grandioso e avrebbe reso questa risposta perfettamente completa.
DavidScherer,

167

si ma perché !!??

   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

2
^^ Questo ha funzionato per me. PIVOT non è efficiente per valori non numerici.
Dienekes,

6
Questa è un'ottima alternativa. Stavo usando Pivotnella mia query, poi sono passato a questo e ho esaminato il piano di esecuzione per l'esecuzione di entrambi insieme. Questo approccio è costato l'8% e l'approccio Pivot ha preso il 92%!
mafue,

2
@CharlesBretana, sei eccezionale! Mi hai salvato l'anima! ) Questa è la soluzione migliore. Grazie!
Chaki_ Black

3
Adoro davvero questa soluzione, inoltre si assicura che le colonne contengano i dati corretti invece di quello Pivot, grazie!
Tenerezza,

2
Questo lavoro è fantastico! Ma come posso prevenireWarning: Null value is eliminated by an aggregate or other SET operation
GiddyUpHorsey il

24
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;

3
Questa dovrebbe essere la risposta accettata in quanto mostra l'uso corretto del comando TSQL Pivot.
Ubercoder

1
Vale la pena notare che in questa query, "pivot2" è il nome della tabella in cui risiedono i dati originali. Inoltre, l'uso del CTE qui è superfluo: l' SELECTistruzione sotto il CTE avrebbe potuto semplicemente specificare il nome della tabella originale.
STLDev

@STLDev In realtà STLDev non è così che funziona pivot. Non conosciamo tutte le colonne nella tabella "pivot2". Potrebbero infatti esserci altre colonne che OP non ha specificato che sono presenti nella tabella. Pertanto, a meno che non si limitino le colonne, utilizzando una query CTE o una tabella derivata, nel raggruppamento vengono utilizzate TUTTE le colonne della tabella. In altre parole, il PIVOT restituisce qualcosa ma non quello che ci aspettiamo. Questo è un concetto trattato in modo approfondito per l'esame di certificazione 70-761.
Zorkolot,

2
Vale la pena notare che PIVOT raggruppa automaticamente in base a ciò che mai le colonne non sono utilizzate nel PIVOT stesso. Quindi in questo esempio [data] e [dbcolumnname] sono nel PIVOT, quindi tutto sarà raggruppato da [CustomerId]
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' 

Modifica: ho scritto questo senza un editor e non ho eseguito l'SQL. Spero che tu abbia l'idea.


9

Ok, scusa per la povera domanda. gbn mi ha portato sulla strada giusta. Questo è quello che stavo cercando in una risposta.

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

Quindi ho dovuto usare un'istruzione while e creare l'istruzione precedente come varchar e usare dynmaic sql.

Usando qualcosa del genere

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)

Avere a per compilare @fulltext usando un ciclo while e selezionare i nomi di colonna distinti dalla tabella. Grazie per le risposte


6

Il PO in realtà non ha avuto bisogno di ruotare senza aggregazione ma per quelli di voi che vengono qui per sapere come vedere:

query cte con parametri sql

La risposta a questa domanda implica una situazione in cui è necessario un perno senza aggregazione, quindi un esempio di farlo è parte della soluzione.


1

Prova questo:

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

1

Questo dovrebbe funzionare:

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

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

1

Ecco un ottimo modo per creare campi dinamici per una query pivot:

- riassumi i valori in una tabella tmp

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

--- vedi i campi generati

print @STr

exec('  .... pivot code ...
pivot (avg(SalesAmt) for DateRange IN (' + @Str +')) AS P
order by Decile')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.