SQL Pivot查询帮助

时间:2014-05-30 00:30:55

标签: sql sql-server-2008 tsql pivot unpivot

我有一张桌子

+----+-------+----------+-------+--------------+
| ID | REQID |  VENDOR  | QUOTE | DELIVERYDATE |
+----+-------+----------+-------+--------------+
|  1 | R1    | Vendor_1 |    99 | 2014-06-15   |
|  2 | R1    | Vendor_2 |    88 | 2014-07-15   |
|  3 | R1    | Vendor_3 |    77 | 2014-08-15   |
|  4 | R2    | Vendor_4 |    66 | 2014-09-15   |
+----+-------+----------+-------+--------------+

SQL Fiddle here

我需要查询返回三列,供应商为Pivot点。所以我的行看起来像这样:

+-----------+-----------+-----------+
| Vendor_1  | Vendor_2  | Vendor_3  |
+-----------+-----------+-----------+
| 99        | 88        | 77        |
| 2014-6-15 | 2014-7-15 | 2014-8-15 |
+-----------+-----------+-----------+

cte返回正确的记录,我只是不知道如何编写Pivot部分,或者甚至可以返回我需要的内容。

2 个答案:

答案 0 :(得分:4)

您没有指定您正在使用的SQL Server版本,但您可以先通过取消标记日期和引用列来获得最终结果,然后转动数据。基本语法类似于:

select Vendor_1, Vendor_2, Vendor_3
from
(
   select vendor, col, value,
     row_number() over(partition by vendor
                       order by vendor) seq
   from vendorquotes
   cross apply
   (
     values
      ('Quote', cast(quote as varchar(10))),
      ('DeliveryDate', convert(varchar(10), deliverydate, 120))
   ) c(col, value)
) d
pivot
( 
  max(value)
  for vendor in (Vendor_1, Vendor_2, Vendor_3)
) pi;

See SQL Fiddle with demo

关键是你需要使用像row_number这样的窗口函数,这样你就可以为每个供应商返回多行。

如果您拥有未知数量的供应商,则需要使用动态SQL来获得此结果:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(Vendor) 
                    from VendorQuotes
                    group by Vendor
                    order by Vendor
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT ' + @cols + ' 
            from 
            (
               select vendor, col, value,
                 row_number() over(partition by vendor
                                   order by vendor) seq
               from vendorquotes
               cross apply
               (
                 values
                  (''Quote'', cast(quote as varchar(10))),
                  (''DeliveryDate'', convert(varchar(10), deliverydate, 120))
               ) c(col, value)
            ) x
            pivot 
            (
                max(value)
                for Vendor in (' + @cols + ')
            ) p '

exec sp_executesql @query;

请参阅SQL Fiddle with Demo

最后,如果要将ReqID作为参数传递,则可以将动态SQL更改为:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @ReqID varchar(20),
    @ParmDefinition NVARCHAR(500)


SET @ParmDefinition = '@ReqID varchar(20)'
SET @ReqID = 'R1'

select @cols = STUFF((SELECT ',' + QUOTENAME(Vendor) 
                    from VendorQuotes
                    where Reqid = @ReqID
                    group by Vendor
                    order by Vendor
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT ' + @cols + ' 
            from 
            (
               select vendor, col, value,
                 row_number() over(partition by vendor
                                   order by vendor) seq
               from vendorquotes
               cross apply
               (
                 values
                  (''Quote'', cast(quote as varchar(10))),
                  (''DeliveryDate'', convert(varchar(10), deliverydate, 120))
               ) c(col, value)
               where ReqID = @ReqID
            ) x
            pivot 
            (
                max(value)
                for Vendor in (' + @cols + ')
            ) p '

exec sp_executesql @query, @ParmDefinition, @ReqID = @ReqID;

请参阅SQL Fiddle with Demo

答案 1 :(得分:-1)

说实话(如果我理解你的问题),我认为你应该再考虑一下。我会这样做:

Vendor_name     Value     Date
Vendor_1        99        2014-6-15
Vendor_2        88        2014-7-15
Vendor_3        77        2014-8-15

这样,您就可以将所有相关数据放在一行中。

如果您将相关数据放在列中,则需要添加更多列,如果添加了更多供应商,您需要确保所有相关数据输入始终处于相同的顺序。