2014-02-05 44 views
0

我需要一些关于PIVOT表的帮助或者以我需要的方式获得结果。将日期转换为列的行 - SQL Server 2008

我有一张这样的桌子。

+---------------+--------------+----------+-----------+---------------+-----------------------------------------+-----------------+---------------+------------------+----------+-------+------------+--------------+------------+-------------------+----------------+----------+-------------------+ 
|  Client_Id | Project_Id | Hotel_Id | Room_Type | Room_Category |    Allotment_Date    | Number_Of_Rooms | Number_Booked | Number_Available | Overbook | Price | Dep_Amount | Full_Payment | Admin_Only | HotelAllotment_Id | Price_Excl_VAT | VAT_Code | Charge_Dep_Amount | 
+---------------+--------------+----------+-----------+---------------+-----------------------------------------+-----------------+---------------+------------------+----------+-------+------------+--------------+------------+-------------------+----------------+----------+-------------------+ 
|  DEFAULT |  TEMPLATE |  2423 |  276 |    |      2010-12-05 00:00:00 |   99999 |    1 |   99998 |  0 | 33000 |   0 |   1 |   0 |   279611 |    0 |   |     0 | 
|  DEFAULT |  TEMPLATE |  2423 |  276 |    |      2010-12-06 00:00:00 |   99999 |    1 |   99998 |  0 | 33000 |   0 |   1 |   0 |   279612 |    0 |   |     0 | 
|  DEFAULT |  TEMPLATE |  2423 |  276 |    |      2010-12-07 00:00:00 |   99999 |    1 |   99998 |  0 | 33000 |   0 |   1 |   0 |   279613 |    0 |   |     0 | 
|  DEFAULT |  TEMPLATE |  2424 |  276 |    |      2010-12-05 00:00:00 |   99999 |    1 |   99998 |  0 | 22000 |  22000 |   0 |   0 |   279590 |    0 |   |     0 | 
|  DEFAULT |  TEMPLATE |  2424 |  276 |    |      2010-12-06 00:00:00 |   99999 |    1 |   99998 |  0 | 22000 |  22000 |   0 |   0 |   279591 |    0 |   |     0 | 
|  DEFAULT |  TEMPLATE |  2424 |  276 |    |      2010-12-07 00:00:00 |   99999 |    1 |   99998 |  0 | 22000 |  22000 |   0 |   0 |   279592 |    0 |   |     0 | 
+---------------+--------------+----------+-----------+---------------+-----------------------------------------+-----------------+---------------+------------------+----------+-------+------------+--------------+------------+-------------------+----------------+----------+-------------------+ 

我需要这样显示数据,以获得列中的日期和每天预订的数量。

+---------------+--------------+----------+-----------+---------------+------------+------------+--------------+ 
|  Client_Id | Project_Id | Hotel_Id | Room_Type | Room_Category | 2010-12-05 | 2010-12-06 | 2010-12-07 | 
+---------------+--------------+----------+-----------+---------------+------------+------------+--------------+ 
|  DEFAULT |  TEMPLATE |  2423 |  276 |    |   1 |   1 |   1 | 
|  DEFAULT |  TEMPLATE |  2424 |  276 |    |   1 |   1 |   1 | 
+---------------+--------------+----------+-----------+---------------+------------+------------+--------------+ 

我需要这个由HOTEL_ID,Room_Type和Room_Category(如果有的话)

我需要这是动态的,因为日期,可以更改进行分组。

我尝试使用简单的透视表,没有运气。

任何帮助将是伟大的。

回答

7

您可以使用PIVOT函数在写动态版本之前得到结果我建议先写一个静态版本。

如果你有值的数量有限,那么你可以硬编码的所有dates的是列标题:

select client_id, project_id, hotel_id, 
    room_type, room_category, 
    [2010-12-05], [2010-12-06], [2010-12-07] 
from 
(
    select client_id, project_id, hotel_id, 
    room_type, room_category, 
    allotment_date, number_booked 
    from yourtable 
) d 
pivot 
(
    sum(number_booked) 
    for allotment_date in ([2010-12-05], [2010-12-06], [2010-12-07]) 
) p; 

SQL Fiddle with Demo。但是,如果你的值将是未知的,那么你将需要创建一个SQL字符串,以使用动态SQL执行。

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

select @cols = STUFF((SELECT ',' + QUOTENAME(convert(varchar(10), allotment_date, 120)) 
        from yourtable 
        group by allotment_date 
        order by allotment_date 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT client_id, project_id, hotel_id, 
       room_type, room_category,' + @cols + ' 
      from 
      (
       select client_id, project_id, hotel_id, 
       room_type, room_category, 
       allotment_date, number_booked 
       from yourtable 
      ) x 
      pivot 
      (
       sum(number_booked) 
       for allotment_date in (' + @cols + ') 
      ) p ' 

execute sp_executesql @query; 

参见SQL Fiddle with Demo。这些给结果:

| CLIENT_ID | PROJECT_ID | HOTEL_ID | ROOM_TYPE | ROOM_CATEGORY | 2010-12-05 | 2010-12-06 | 2010-12-07 | 
|-----------|------------|----------|-----------|---------------|------------|------------|------------| 
| DEFAULT | TEMPLATE |  2423 |  276 |  (null) |   1 |   1 |   1 | 
| DEFAULT | TEMPLATE |  2424 |  276 |  (null) |   1 |   1 |   1 | 
+0

这是好的,但与大项目有很多酒店和日期范围是不一样的每个酒店它给一个错误。 “Msg 1056,Level 15,State 1,Line 1 选择列表中元素的数量超过了允许的最大数量4096个元素。” 我正在测试的项目有4641条记录 –

+2

@FedericoGiust有限制至于什么可以返回,如果你真的需要调整4641个不同的数据值,那么你应该考虑把它分解成更小的部分,或者在应用层中进行这种类型的转换而不是SQL。 – Taryn

+3

@FedericoGiust然后,这是一个迹象表明你正在做的不是应该在数据库层中完成的事情 – Lamak

2

编辑:关于这个“办法”进一步的讨论表明,这将是审慎的进入进一步的细节,以为什么这不应该永远作为可靠的代码。除了像SELECT *这样的显而易见的事情之外,沿着这条路走下去只会超过编译时间的限制。假设我们填入以下的@t_Date表变量(和方式,更好的方式)CTE:

Msg 8632, Level 17, State 2, Line 2

Internal error: An expression services limit has been reached. Please look for potentially complex expressions in your query, and try to simplify them.

注:

-- Thanks @AaronBertrand! 
    WITH cte_Date(DateVal) AS (
     SELECT TOP (10000) DATEADD(DAY, ROW_NUMBER() 
        OVER (ORDER BY s1.object_id), '19991231') 
     FROM sys.all_objects AS s1 
     CROSS JOIN sys.all_objects AS s2 
    ) 
    INSERT INTO @t_Date (DateVal) 
    SELECT DateVal 
    FROM cte_Date; 

不可避免的,我们将传达信息像在一些点以下运行即使是错误信息也可以总结为:@bluefeet和@Lamak或多或少地声明:“不要在数据层中这样做”。

因此,随着职位是:

@bluefeet和@Lamak是两个最优秀的数据库人们在计算器上的,所以你要听从他们的话。如果你真的需要这个测试,使用@ bluefeet的答案,因为你正在收到一个编译时错误,所以你可以在你的查询中加以干涉,并通过下面的例子来解决这个问题。请为了任何可能需要承担工作职责的人的利益,不要将此类代码移到生产环境。我只发布这个hack-fest解决方法,以便您可以测试您正在处理的任何理论,并通过适当的步骤进行后续跟踪,以使您的数据层更适合部署。

IF NOT EXISTS (SELECT 1 
       FROM sys.objects 
       WHERE name = 'yourtable' 
        AND type = 'U') 
BEGIN 
    --DROP TABLE dbo.yourtable; 
    CREATE TABLE dbo.yourtable 
    ( 
     [Client_Id] varchar(7), 
     [Project_Id] varchar(8), 
     [Hotel_Id] int, 
     [Room_Type] int, 
     [Room_Category] int, 
     [Allotment_Date] datetime, 
     [Number_Of_Rooms] int, 
     [Number_Booked] int, 
     [Number_Available] int, 
     [Overbook] int, 
     [Price] int, 
     [Dep_Amount] int, 
     [Full_Payment] int, 
     [Admin_Only] int, 
     [HotelAllotment_Id] int, 
     [Price_Excl_VAT] int, 
     [VAT_Code] int, 
     [Charge_Dep_Amount] INT 
    ); 

    DECLARE @t_Date TABLE 
    (
     DateVal  DATE 
    ); 

    WITH cte_Date AS (
     SELECT DateVal = CAST(GETDATE() AS DATE) 
     UNION ALL 
     SELECT DateVal = DATEADD(DAY, -1, DateVal) 
     FROM cte_Date 
     WHERE DateVal > '2002-01-01' 
    ) 
    INSERT INTO @t_Date (DateVal) 
    SELECT DateVal 
    FROM cte_Date 
    OPTION (MAXRECURSION 5000); 

    INSERT INTO dbo.yourtable([Client_Id], [Project_Id], [Hotel_Id], [Room_Type], [Room_Category], [Allotment_Date], 
     [Number_Of_Rooms], [Number_Booked], [Number_Available], [Overbook], [Price], [Dep_Amount], [Full_Payment], 
     [Admin_Only], [HotelAllotment_Id], [Price_Excl_VAT], [VAT_Code], [Charge_Dep_Amount]) 
    SELECT 'DEFAULT', 'TEMPLATE', 2423, 276, NULL, DateVal, 99999, 1, 99998, 0, 33000, 0, 1, 0, 279611, 0, NULL, 0 
    FROM @t_Date; 
END; 
GO 

SELECT COUNT(DISTINCT Allotment_date) 
FROM dbo.yourtable; 

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

select @cols = STUFF((SELECT ',' + QUOTENAME(convert(varchar(10), allotment_date, 120)) 
        from yourtable 
        group by allotment_date 
        order by allotment_date 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = ' 
      SELECT * 
      FROM ( SELECT client_id, project_id, hotel_id, 
         room_type, room_category,' + @cols + ' 
        from 
        (
         select client_id, project_id, hotel_id, 
         room_type, room_category, 
         allotment_date, number_booked 
         from yourtable 
        ) x 
        pivot 
        (
         sum(number_booked) 
         for allotment_date in (' + @cols + ') 
        ) p) a;' 

execute sp_executesql @query; 
GO 
相关问题