TSQL Pivot โดยไม่มีฟังก์ชั่นรวม


139

ฉันมีโต๊ะแบบนี้ ...

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

และฉันต้องการสิ่งนี้ ...

เป็นไปได้โดยใช้ 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

คำตอบ:


102

คุณสามารถใช้การรวม MAX มันจะยังคงทำงาน MAX หนึ่งค่า = ค่านั้น

ในกรณีนี้คุณสามารถรวมตัวเอง 5 ครั้งบน customerid กรองโดย dbColumnName ต่อการอ้างอิงตาราง มันอาจจะทำงานได้ดีขึ้น


1
ที่จริงแล้วจะไม่ทำงานหากคุณมีลูกค้า 2 คนที่มีชื่อเดียวกัน
Leonardo

1
ที่จะได้ผล จำไว้ว่า DBColumnName เป็นข้อมูลเมตา - คุณกรองตามตัวอักษร "CustomerID = 1 AND DBColumnName = 'FirstName'" แน่นอนว่าถ้าคุณมี FirstName หลายแถวสำหรับ CustomerID ที่กำหนด แต่ถ้าคุณสร้างตารางของคุณอย่างถูกต้องทั้ง CustomerID และ DBColumnName เป็นส่วนหนึ่งของคีย์หลักของคุณ ...
4AM

7
โค้ด / การเยาะเย้ยบางอย่างเป็นตัวอย่างที่ยอดเยี่ยม
DavidScherer

167

ใช้ แต่ทำไม !!??

   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
^^ สิ่งนี้ใช้ได้สำหรับฉัน PIVOT ไม่มีประสิทธิภาพสำหรับค่าที่ไม่ใช่ตัวเลข
Dienekes

6
นี่เป็นทางเลือกที่ยอดเยี่ยม ฉันใช้Pivotในการค้นหาของฉันจากนั้นฉันสลับไปที่สิ่งนี้และดูแผนการดำเนินการสำหรับการทำงานทั้งสองร่วมกัน วิธีนี้มีค่าใช้จ่าย 8% และวิธีการ Pivot นั้นได้ 92%!
mafue

2
@CharlesBretana คุณยอดเยี่ยม! คุณช่วยชีวิตฉัน! ) นั่นคือทางออกที่ดีที่สุด ขอบคุณ!
Chaki_Black

3
ชอบวิธีนี้จริง ๆ และทำให้แน่ใจว่าคอลัมน์มีข้อมูลที่ถูกต้องแทนที่จะเป็น Pivot หนึ่งขอบคุณ!
Tenerezza

2
มันใช้งานได้ดีมาก! แต่ฉันจะป้องกันได้อย่างไร -Warning: Null value is eliminated by an aggregate or other SET operation
GiddyUpHorsey

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
นี่ควรเป็นคำตอบที่ยอมรับเนื่องจากแสดงการใช้คำสั่ง TSQL Pivot อย่างเหมาะสม
Ubercoder

1
เป็นที่น่าสังเกตว่าในแบบสอบถามนี้ "pivot2" เป็นชื่อของตารางที่มีข้อมูลต้นฉบับอยู่ นอกจากนี้การใช้ CTE ที่นี่นั้นไม่จำเป็น - SELECTคำสั่งด้านล่าง CTE สามารถระบุชื่อของตารางต้นฉบับได้
STLDev

@STLDev อันที่จริง STLDev นั้นไม่ใช่วิธีการทำงานของเดือย เราไม่ทราบคอลัมน์ทั้งหมดในตาราง "pivot2" ในความเป็นจริงอาจเป็นคอลัมน์อื่น ๆ OP ไม่ได้ระบุที่อยู่ในตาราง ดังนั้นถ้าคุณไม่ จำกัด คอลัมน์ - โดยใช้แบบสอบถามตาราง CTE หรือ Derived - คอลัมน์ทั้งหมดในตารางจะถูกใช้ในการจัดกลุ่ม กล่าวอีกนัยหนึ่ง PIVOT ส่งคืนสิ่งที่ไม่ใช่สิ่งที่เราคาดหวัง นี่คือแนวคิดที่ครอบคลุมในเชิงลึกสำหรับการสอบรับรอง 70-761
Zorkolot

2
เป็นที่น่าสังเกตว่า PIVOT จะจัดกลุ่มโดยอัตโนมัติตามสิ่งที่ไม่เคยใช้ในคอลัมน์ PIVOT ดังนั้นในตัวอย่างนี้ [ข้อมูล] และ [dbcolumnname] อยู่ใน PIVOT เพื่อทุกอย่างจะถูกจัดกลุ่มตาม [รหัสลูกค้า]
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' 

แก้ไข: ฉันได้เขียนสิ่งนี้โดยไม่มีตัวแก้ไข & ไม่ได้เรียกใช้ SQL ฉันหวังว่าคุณจะได้รับความคิด


9

ตกลงขออภัยสำหรับคำถามที่ไม่ดี gbn พาฉันไปในเส้นทางที่ถูกต้อง นี่คือสิ่งที่ฉันกำลังมองหาในคำตอบ

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

จากนั้นฉันต้องใช้คำสั่ง while และสร้างคำสั่งด้านบนเป็น varchar และใช้ dynmaic sql

ใช้สิ่งนี้

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)

มี a เพื่อสร้าง @fulltext โดยใช้ลูป while และเลือกชื่อคอลัมน์ที่แตกต่างจากตาราง ขอบคุณสำหรับคำตอบ


6

OP ไม่จำเป็นต้องหมุนโดยไม่ต้องใช้การปั่นป่วน แต่สำหรับผู้ที่มาที่นี่เพื่อดูว่า:

แบบสอบถาม cte sql parameterised

คำตอบสำหรับคำถามนั้นเกี่ยวข้องกับสถานการณ์ที่จำเป็นต้องมีการหมุนโดยไม่มีการรวมดังนั้นตัวอย่างของการทำมันเป็นส่วนหนึ่งของการแก้ปัญหา


1

ลองสิ่งนี้:

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

นี่เป็นวิธีที่ยอดเยี่ยมในการสร้างเขตข้อมูลแบบไดนามิกสำหรับแบบสอบถาม Pivot:

- สรุปค่าให้กับตาราง tmp

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

--- ดูฟิลด์ที่สร้าง

print @STr

exec('  .... pivot code ...
pivot (avg(SalesAmt) for DateRange IN (' + @Str +')) AS P
order by Decile')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.