2013-08-02 42 views
14

Tôi có bảng nguồn và đích sau trong máy chủ sql 2008R2. Làm thế nào tôi có thể làm (các) trục trong TSQL để đến đích từ nguồn.Máy chủ SQL Xoay nhiều cột dựa trên một cột

SourceTbl

empId empIndex empState empStDate empEndDate 
======================================================== 
10  1   AL   1/1/2012  12/1/2012 
10  2   FL   2/1/2012  2/1/2013 
15  1   FL   3/20/2012 1/1/2099 

DestTbl

empId empState1 empState1StDate empState1EndDt empState2 empState2StDate empState2EndDt 
========================================================================================================= 
10  AL   1/1/2012   12/1/2012   FL   2/1/2012   2/1/2013 
15  FL   3/20/2012   1/1/2099   NULL  NULL    NULL 

Hy vọng rằng bằng cách nào đó empIndex sẽ giúp đỡ trong việc trục.

+0

trục còn được gọi là biến đổi trong msaccess. câu hỏi của bạn là duy nhất ở chỗ nó cũng có văn bản (không phải số nguyên) trong các ô kết quả. chức năng tổng hợp vẫn phải áp dụng, trong trường hợp này MIN() nên làm tốt trên các giá trị Text, ngay cả khi chỉ có 1 giá trị văn bản. – hamish

Trả lời

23

Vì bạn đang sử dụng SQL Server, có nhiều cách khác nhau để bạn có thể chuyển đổi các hàng thành các cột. Bạn có thể sử dụng hàm tổng hợp có biểu thức CASE:

select empid, 
    max(case when empindex = 1 then empstate end) empState1, 
    max(case when empindex = 1 then empStDate end) empStDate1, 
    max(case when empindex = 1 then empEndDate end) empEndDate1, 
    max(case when empindex = 2 then empstate end) empState2, 
    max(case when empindex = 2 then empStDate end) empStDate2, 
    max(case when empindex = 2 then empEndDate end) empEndDate2 
from sourcetbl 
group by empid; 

Xem SQL Fiddle with Demo.

Nếu bạn muốn sử dụng hàm PIVOT để nhận kết quả, sau đó tôi khuyên bạn nên bỏ bớt các cột empState, empStDateempEndDate để trước tiên bạn sẽ có nhiều hàng. Bạn có thể sử dụng hàm UNPIVOT hoặc CROSS APPLY để chuyển đổi dữ liệu mã sẽ là:

select empid, col+cast(empindex as varchar(10)) col, value 
from sourcetbl 
cross apply 
(
    select 'empstate', empstate union all 
    select 'empstdate', convert(varchar(10), empstdate, 120) union all 
    select 'empenddate', convert(varchar(10), empenddate, 120) 
) c (col, value); 

Xem Demo. Khi dữ liệu không được bỏ phiếu, bạn có thể áp dụng chức năng PIVOT để mã cuối cùng là:

select empid, 
    empState1, empStDate1, empEndDate1, 
    empState2, empStDate2, empEndDate2 
from 
(
    select empid, col+cast(empindex as varchar(10)) col, value 
    from sourcetbl 
    cross apply 
    (
    select 'empstate', empstate union all 
    select 'empstdate', convert(varchar(10), empstdate, 120) union all 
    select 'empenddate', convert(varchar(10), empenddate, 120) 
) c (col, value) 
) d 
pivot 
(
    max(value) 
    for col in (empState1, empStDate1, empEndDate1, 
       empState2, empStDate2, empEndDate2) 
) piv; 

Xem SQL Fiddle with Demo.

Th trên các phiên bản sẽ làm việc tuyệt vời nếu bạn có một số hạn chế về empindex, nhưng nếu không thì bạn có thể sử dụng SQL động:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT ',' + QUOTENAME(col+cast(empindex as varchar(10))) 
        from SourceTbl 
        cross apply 
        (
         select 'empstate', 1 union all 
         select 'empstdate', 2 union all 
         select 'empenddate', 3 
        ) c (col, so) 
        group by col, so, empindex 
        order by empindex, so 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT empid,' + @cols + ' 
      from 
      (
       select empid, col+cast(empindex as varchar(10)) col, value 
       from sourcetbl 
       cross apply 
       (
        select ''empstate'', empstate union all 
        select ''empstdate'', convert(varchar(10), empstdate, 120) union all 
        select ''empenddate'', convert(varchar(10), empenddate, 120) 
       ) c (col, value) 
      ) x 
      pivot 
      (
       max(value) 
       for col in (' + @cols + ') 
      ) p ' 

execute sp_executesql @query; 

Xem SQL Fiddle with Demo

Bạn có thể sử dụng các truy vấn này để INSERT INTO của bạn DestTbl, hoặc thay vì lưu trữ dữ liệu ở định dạng này, bây giờ bạn có một truy vấn để có được kết quả mong muốn.

Các truy vấn này đặt các dữ liệu trong các định dạng:

| EMPID | EMPSTATE1 | EMPSTDATE1 | EMPENDDATE1 | EMPSTATE2 | EMPSTDATE2 | EMPENDDATE2 | 
--------------------------------------------------------------------------------------- 
| 10 |  AL | 2012-01-01 | 2012-12-01 |  FL | 2012-02-01 | 2013-02-01 | 
| 15 |  FL | 2012-03-20 | 2099-01-01 | (null) |  (null) |  (null) | 
+0

Tôi đánh giá cao nỗ lực của bạn. Nó cũng giải quyết được vấn đề của tôi. Cảm ơn rất nhiều @bluefeet –

+0

Tôi đã thấy FOR XML được sử dụng rất nhiều trước đây .. nhưng kudo và * thumbsup * để sử dụng tốt nhất: STUFF QUOTENAME và NVARCHAR (MAX) trong PIVOT :) MSACCESS gọi TRANSFORM này (không chắc tại sao lệnh đó không bao giờ thực hiện nó với máy chủ SQL) – hamish

-1

Wow này là phức tạp hơn tôi tưởng tượng, nhưng tôi đã nhận được nó để làm việc tuyệt vời! cảm ơn. Đây là phiên bản cuối cùng của tôi. TextKey chứa dữ liệu bạn muốn chuyển thành các cột và TextValue là giá trị kết thúc trong mỗi ô.

DECLARE @cols AS NVARCHAR(MAX), 
     @query AS NVARCHAR(MAX) 


select @cols = STUFF((SELECT distinct ', ' + QUOTENAME(TextKey) 
        from #SourceTbl 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT FromEntityID, DisplayName, ' + @cols + ' 
       FROM 
       (
        select FromEntityID, DisplayName, TextKey, TextValue 
        from #SourceTbl 
      ) x 
       pivot 
       (
        min(TextValue) 
        for TextKey in (' + @cols + ') 
      ) p 
       ORDER BY FromEntityID 
       ' 

execute(@query)