我需要一些PIVOT表格的帮助,或者以我需要的方式得到结果。
我有一张这样的桌子。
+---------------+--------------+----------+-----------+---------------+-----------------------------------------+-----------------+---------------+------------------+----------+-------+------------+--------------+------------+-------------------+----------------+----------+-------------------+
| 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(如果有的话)进行分组
我需要这个是动态的,因为日期可以改变。
我尝试使用简单的数据透视表而没有运气。
任何帮助都会很棒。
答案 0 :(得分: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 |
答案 1 :(得分:2)
编辑:关于此“解决方案”的进一步讨论表明,进一步详细说明为什么这不应该被用作可靠性是明智的码。在SELECT *
之类的明显的永恒之类之外,沿着这条路走下去只会超过编译时间限制。假设我们使用以下(以及更好的方式)CTE填充@t_Date
表变量:
-- 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;
不可避免地,我们会在某些时候遇到如下消息:
Msg 8632,Level 17,State 2,Line 2
内部错误:已达到表达式服务限制。请在查询中查找可能复杂的表达式,并尝试简化它们。
请注意,即使是错误消息也可以汇总,因为@bluefeet和@Lamak或多或少都说过,“不要在数据层中这样做。”
所以,帖子是:
@bluefeet和@Lamak是StackOverflow上两个最高级别的数据库人员,所以你会想要留意他们的话。如果确实需要使用@ 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