我有两个临时表,#date和#availability,以及一个datetime varaible,@ startdate。
变量是:
declare @startdate datetime = '2016-12-20'
#dates的列和数据是:
Date
-------
2016-12-20
2016-12-21
2016-12-22
#availability的列和数据是:
GroupId Date StatusId Price
-----------------------------------------------
111 2016-12-20 1 200
111 2016-12-21 1 100
111 2016-12-22 1 500
111 2016-12-22 1 300
222 2016-12-20 4 100
222 2016-12-21 1 200
222 2016-12-22 1 200
333 2016-12-20 1 100
333 2016-12-22 4 200
表#dates显示客户将留在酒店房间的日期范围,这些日期必须(应该)是连续的
表#availability是我从其他表中获得的可用性数据。
我的目标是显示每个有效群体的平均价格 。
限制是:
对于开始日期,StatusId必须为1;否则,StatusId可以是1或4(但不能是其他数字,如2和3) 这意味着GroupId 2已从我们的结果中删除。
如果该群组没有日期范围的完整价格信息,我们会将其删除。 GroupId 3没有2016-12-21的价格信息,它将被删除。
如果任何一天有多个价格,我们会选择当天的最低价格。 这意味着第1组将使用以下数据计算平均价格:
2016-12-20 - > $ 200
2016-12-21 - > $ 100
2016-12-22 - > $ 300
然后,显示最终平均价格:$(200 + 100 + 300)/ 3天= $ 200
我从这开始,
Select GroupId,Date
From #availability
Group by GroupId, Date
但无法弄清楚如何判断日期编号是否与#dates表匹配,并且每个组的#availability中的startdate状态必须为1。
答案 0 :(得分:1)
有几种方法可以做到这一点。这是一种不需要日期连续的方法,并且不依赖于日期和GroupIds之间的笛卡尔连接,这应该有助于提高性能。
;WITH cteMinPricePerDay AS (
SELECT
d.Date
,GroupId
,StatusId
,MIN(Price) as Price
,COUNT(d.Date) OVER (PARTITION BY GroupId) GroupDateCount
,dc.DateCount
FROM
#date d
CROSS APPLY (SELECT COUNT(*) as DateCount FROM #date) dc
LEFT JOIN #availability a
ON d.Date = a.Date
AND NOT(d.Date = @startdate AND a.StatusId <> 1)
GROUP BY
d.Date
,GroupId
,StatusId
,dc.DateCount
)
SELECT
GroupId
,Date
,StatusId
,Price
,AVG(Price) OVER (PARTITION BY GroupId) as AvgPrice
FROM
cteMinPricePerDay
WHERE
GroupDateCount = DateCount
步骤/描述
这里有一个很好的衡量方法是使用不同组和日期之间的笛卡尔连接。
;WITH cteDistinctGroups AS (
SELECT DISTINCT GroupId
FROM
#availability
)
, cteMinPricePerDay AS (
SELECT
d.Date
,g.GroupId
,MIN(a.Price) as Price
,COUNT(CASE WHEN a.Date IS NULL THEN 1 END) OVER (PARTITION BY g.GroupId) as GroupMissingDateCount
FROM
#date d
CROSS JOIN cteDistinctGroups g
LEFT JOIN #availability a
ON d.Date = a.Date
AND g.GroupId = a.GroupId
AND NOT(d.Date = @startdate AND a.StatusId <> 1)
GROUP BY
d.Date
,a.Date
,g.GroupId
)
SELECT
GroupId
,Date
,Price
,AVG(Price) OVER (PARTITION BY GroupId) as AveragePrice
FROM
cteMinPricePerDay
WHERE
GroupMissingDateCount = 0