TSQL Pivot tanpa fungsi agregat

139

Saya punya meja seperti ini ...

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

Dan saya menginginkan ini ...

Apakah ini mungkin menggunakan 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
ctrlShiftBryan
sumber

Jawaban:

102

Anda dapat menggunakan agregat MAX, itu masih akan berfungsi. MAX satu nilai = nilai itu ..

Dalam hal ini, Anda juga dapat bergabung sendiri 5 kali di customerid, memfilter menurut dbColumnName per referensi tabel. Mungkin berhasil lebih baik.

gbn
sumber
1
yang sebenarnya tidak akan berfungsi jika Anda memiliki 2 pelanggan dengan nama depan yang sama
Leonardo
1
Itu akan bekerja. Ingat bahwa DBColumnName adalah metadata - Anda benar-benar memfilter dengan "CustomerID = 1 DAN DBColumnName = 'FirstName'". Tentu saja, ini rusak jika Anda memiliki beberapa baris FirstName untuk CustomerID yang diberikan, tetapi jika Anda membuat tabel dengan benar, baik CustomerID dan DBColumnName adalah bagian dari kunci utama Anda ...
4AM
7
Beberapa kode / mengejek sebagai contoh akan sangat bagus dan membuat jawaban ini sangat lengkap.
DavidScherer
167

iya tapi kenapa !!??

   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
sumber
2
^^ Ini bekerja untuk saya. PIVOT tidak efisien untuk nilai-nilai non-numerik.
Dienekes
6
Ini adalah alternatif yang bagus. Saya menggunakan Pivotdalam permintaan saya, kemudian saya beralih ke ini dan melihat rencana eksekusi untuk menjalankan keduanya bersama-sama. Pendekatan ini menelan biaya 8% dan pendekatan Pivot mengambil 92%!
mafue
2
@CharlesBretana, Anda hebat! Kamu menyelamatkan jiwaku! ) Itu solusi terbaik. Terima kasih!
Chaki_Black
3
Sangat menyukai solusi ini, juga memastikan kolom berisi data yang benar, bukan Pivot, terima kasih!
Tenerezza
2
Ini sangat bagus! Tetapi bagaimana saya mencegah -Warning: Null value is eliminated by an aggregate or other SET operation
GiddyUpHorsey
23
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
sumber
3
Ini harus menjadi jawaban yang diterima karena menunjukkan penggunaan yang tepat dari perintah TSQL Pivot.
Ubercoder
1
Perlu dicatat bahwa dalam kueri ini, "pivot2" adalah nama tabel tempat data asli berada. Juga, penggunaan CTE di sini berlebihan - SELECTpernyataan di bawah CTE bisa saja menentukan nama tabel aslinya.
STLDev
@ STLDev Sebenarnya STLDev bukan itu cara pivot bekerja. Kami tidak tahu semua kolom di tabel "pivot2". Bahkan, bisa jadi ada kolom lain OP tidak menentukan yang ada di tabel. Jadi, kecuali Anda membatasi kolom - menggunakan kueri CTE atau Derived table - maka SEMUA kolom dalam tabel digunakan dalam pengelompokan. Dengan kata lain, PIVOT mengembalikan sesuatu tetapi tidak seperti yang kita harapkan. Ini adalah konsep yang dibahas secara mendalam untuk ujian sertifikasi 70-761.
Zorkolot
2
Perlu dicatat bahwa PIVOT secara otomatis mengelompokkan berdasarkan kolom apa pun yang tidak digunakan dalam PIVOT itu sendiri. Jadi dalam contoh ini [data] dan [dbcolumnname] ada di PIVOT sehingga semuanya akan dikelompokkan oleh [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' 

Sunting: Saya telah menulis ini tanpa editor & belum menjalankan SQL. Saya harap, Anda mendapatkan idenya.

shahkalpesh
sumber
9

Ok, maaf untuk pertanyaan yang buruk. gbn membuat saya di jalur yang benar. Inilah yang saya cari dalam sebuah jawaban.

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

Kemudian saya harus menggunakan pernyataan sementara dan membangun pernyataan di atas sebagai varchar dan menggunakan sql dinamis.

Menggunakan sesuatu seperti ini

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)

Memiliki a untuk membangun @fulltext menggunakan loop sementara dan pilih nama kolom yang berbeda dari tabel. Terima kasih atas jawabannya.

ctrlShiftBryan
sumber
6

OP sebenarnya tidak perlu berputar tanpa persetujuan tetapi bagi Anda yang datang ke sini untuk mengetahui bagaimana melihatnya:

sql kueri parameterized cl

Jawaban untuk pertanyaan itu melibatkan situasi di mana pivot tanpa agregasi diperlukan sehingga contoh melakukannya adalah bagian dari solusi.

bielawski
sumber
1

Coba ini:

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
pengguna3538033
sumber
1

Ini seharusnya bekerja:

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
sumber
1

Berikut ini cara hebat untuk membangun bidang dinamis untuk kueri pivot:

- merangkum nilai ke tabel tmp

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

--- lihat bidang yang dihasilkan

print @STr

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