2014-02-05 81 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 
相關問題