TSQL Pivot không có chức năng tổng hợp


139

Tôi có một cái bàn như thế này ...

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

Và tôi muốn điều này ...

Điều này có thể sử dụng PIVOT không?

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

Câu trả lời:


102

Bạn có thể sử dụng tổng hợp MAX, nó vẫn hoạt động. MAX của một giá trị = giá trị đó ..

Trong trường hợp này, bạn cũng có thể tự tham gia 5 lần trên customerid, lọc theo dbColumnName trên mỗi tham chiếu bảng. Nó có thể làm việc tốt hơn.


1
Điều đó thực sự sẽ không hoạt động nếu bạn có 2 người tiêu dùng có cùng tên
Leonardo

1
Điều đó sẽ làm việc. Hãy nhớ rằng DBColumnName là siêu dữ liệu - bạn thực sự lọc theo "CustomerID = 1 AND DBColumnName = 'FirstName'". Tất nhiên, điều này sẽ phá vỡ nếu bạn có nhiều hàng FirstName cho một ID khách hàng cụ thể, nhưng nếu bạn đang tạo các bảng của mình đúng thì cả ID khách hàng và DBColumnName đều là một phần của khóa chính của bạn ...
4AM

7
Một số mã / chế nhạo như một ví dụ sẽ rất tuyệt và làm cho câu trả lời này hoàn toàn hoàn hảo.
DavidScherer

167

đúng, nhưng tại sao !! ??

   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
^^ Điều này làm việc cho tôi. PIVOT không hiệu quả đối với các giá trị không phải là số.
Điện thoại di động

6
Đây là một sự thay thế tuyệt vời. Tôi đã sử dụng Pivottrong truy vấn của mình, sau đó tôi chuyển sang cái này và xem xét kế hoạch thực hiện để chạy cả hai cùng nhau. Cách tiếp cận này có chi phí 8% và cách tiếp cận Pivot chiếm 92%!
mafue

2
@CharlesBretana, bạn thật tuyệt! Bạn đã cứu linh hồn tôi! ) Đó là giải pháp tốt nhất. Cảm ơn!
Chaki_Black

3
Thực sự yêu thích giải pháp này, nó cũng đảm bảo các cột chứa dữ liệu chính xác thay vì Pivot, cảm ơn!
Tenerezza

2
Công việc này thật tuyệt! Nhưng làm cách nào để ngăn chặn -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;

3
Đây phải là câu trả lời được chấp nhận vì nó cho thấy việc sử dụng đúng lệnh TSQL Pivot.
Ubercoder

1
Điều đáng chú ý là trong truy vấn này, "p Pivot2" là tên của bảng chứa dữ liệu gốc. Ngoài ra, việc sử dụng CTE ở đây là không cần thiết - SELECTcâu lệnh bên dưới CTE có thể chỉ định tên của bảng gốc.
STLDev

@STLDev Trên thực tế STLDev không phải là cách hoạt động của trục. Chúng tôi không biết tất cả các cột trong bảng "p Pivot2". Trên thực tế, có thể có các cột khác OP không chỉ định trong bảng. Vì vậy, trừ khi bạn giới hạn các cột - sử dụng truy vấn bảng CTE hoặc Derogen - thì TẤT CẢ các cột trong bảng được sử dụng trong nhóm. Nói cách khác, PIVOT trả về một cái gì đó nhưng không phải là những gì chúng ta mong đợi. Đây là một khái niệm được trình bày chuyên sâu cho kỳ thi chứng chỉ 70-761.
Zorkolot

2
Điều đáng chú ý là PIVOT tự động nhóm theo những gì từng cột không được sử dụng trong chính PIVOT. Vì vậy, trong ví dụ này [dữ liệu] và [dbcolumnname] nằm trong PIVOT nên mọi thứ sẽ được nhóm theo [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' 

Chỉnh sửa: Tôi đã viết bài này mà không có trình soạn thảo & chưa chạy SQL. Tôi hy vọng bạn có được ý tưởng.


9

Ok, xin lỗi cho câu hỏi nghèo. gbn đã đưa tôi đi đúng hướng. Đây là những gì tôi đang tìm kiếm trong một câu trả lời.

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

Sau đó, tôi đã phải sử dụng một câu lệnh while và xây dựng câu lệnh trên dưới dạng varchar và sử dụng dynmaic sql.

Sử dụng một cái gì đó như thế này

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)

Phải xây dựng @fulltext bằng vòng lặp while và chọn tên cột riêng biệt ra khỏi bảng. Cảm ơn câu trả lời.


6

OP thực sự không cần phải xoay vòng mà không cần liên kết nhưng đối với những người bạn đến đây để biết cách xem:

truy vấn cte tham số sql

Câu trả lời cho câu hỏi đó liên quan đến một tình huống mà trục không có tổng hợp là cần thiết vì vậy một ví dụ về việc thực hiện nó là một phần của giải pháp.


1

Thử cái này:

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

Điều này sẽ làm việc:

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

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

1

Đây là một cách tuyệt vời để xây dựng các trường động cho truy vấn trục:

--summarize giá trị cho một bảng tmp

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

--- xem các trường được tạo

print @STr

exec('  .... pivot code ...
pivot (avg(SalesAmt) for DateRange IN (' + @Str +')) AS P
order by Decile')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.