我有一个带有id和name字段的简单属性表。我还有一个propertyPrices表,其架构和数据如下所示;
因此,它指定了给定日期范围的价格。价格值表示该期间内一天的费用。
如果给定开始日期和结束日期,我希望能够根据每个日期范围之间的天数选择价格总和。
我尝试了以下内容;
DECLARE @propertyID int = 1;
DECLARE @startDate date = '2014/02/13';
DECLARE @endDate date = '2014/02/18';
/* get number of days between start and end date */
DECLARE @duration int = DATEDIFF(DAY, @startDate, @endDate)
/* select properties with holiday cost */
SELECT
property.name, SUM(dbo.propertyPrices.price) * @duration AS totalCost
FROM
dbo.property INNER JOIN dbo.propertyPrices ON dbo.property.id = dbo.propertyPrices.propertyID
WHERE
property.id = @propertyID
GROUP BY
dbo.property.name
返回2000作为总费用。这是5天,然后乘以400(这是所有价格的总和)。我只想为该范围内的每一天选择合适的价格。所以它应该是;
(100天2天)+(300天3天)= 1100.
我不确定如何汇总个人日值。我的首要任务是表现。
提前感谢您的帮助。
尼克
答案 0 :(得分:2)
我会用CTE来做。首先获得具有实际日期范围的价格,然后将价格乘以该范围内的天数并将其相加。
with cte as
(
select propertyID, price,
case when startDate < @startDate then @startDate else startDate end as startDate,
case when endDate > @endDate then @endDate else endDate end as endDate
from propertyPrices
where endDate >= @startDate
and startDate <= @endDate
)
, cte2 as
(
select propertyID, sum((datediff(day, startDate, endDate)+1) * price) as totalCost
from cte
group by propertyID
)
select name, totalCost
from cte2
inner join property on id = propertyID
where id = @propertyID
您可以在SQLFiddle
上查看整个解决方案答案 1 :(得分:1)
我可以想象编写一个存储过程,或者另一个解决方案是构建一个只包含日期列表的辅助表。
如果您的表calendar(date)
的所有日期都在受影响的范围内,则可以执行
SELECT
property.name, SUM(dbo.propertyPrices.price) AS totalCost
FROM
dbo.property
INNER JOIN dbo.propertyPrices
ON dbo.property.id = dbo.propertyPrices.propertyID
JOIN calendar
ON calendar.date between startDate and endDate
WHERE
property.id = @propertyID
GROUP BY
dbo.property.name
答案 2 :(得分:0)
我相信您需要做的就是在原始查询中添加一个case语句,定义您希望应用于开始日期和结束日期的日期边界和组的条件,这会创建一个表,您可以将其用作子表查询父母按属性名称选择哪些组。
请参阅下面的代码,我已经使用了表varibales,所以我可以轻松地测试它,但你应该可以编辑自己的表名,只需删除@。
DECLARE @property AS Table(
id INT
, name NVARCHAR(50)
)
INSERT INTO @property
SELECT 1, 'Property 1' UNION ALL
SELECT 2, 'Property 2'
DECLARE @propertyPrices AS Table(
id INT
, propertyID INT
, startDate datetime
, endDate datetime
, price float
)
INSERT INTO @propertyPrices
SELECT 1, 1, '2014-02-10', '2014-02-15', 100.00 UNION ALL
SELECT 2, 1, '2014-02-16', '2014-02-20', 300.00
DECLARE @propertyID int = 1;
DECLARE @startDate date = '2014/02/13';
DECLARE @endDate date = '2014/02/18';
/* get number of days between start and end date */
DECLARE @duration int = DATEDIFF(DAY, @startDate, @endDate)
/* select properties with holiday cost */
SELECT p.name, SUM(totalCost) FROM (
SELECT
p.name
, CASE
WHEN @startDate > pp.startDate AND @endDate > pp.endDate THEN
SUM(pp.price) * DATEDIFF(DAY, @startDate, @endDate)
WHEN @endDate < pp.endDate THEN
SUM(pp.price) * DATEDIFF(DAY, pp.startDate, @endDate)
ELSE
SUM(pp.price) * DATEDIFF(DAY, pp.startDate, pp.endDate)
END
AS totalCost
FROM
@property p INNER JOIN @propertyPrices pp ON p.id = pp.propertyID
WHERE
p.id = @propertyID
GROUP BY
p.name, pp.startDate, pp.endDate
) p GROUP BY p.name