我在这个结构中有表:
id accom_id room_type_id date_from date_to price_per_room
3 1 2 2017-09-01 2017-09-10 70.00
5 1 2 2017-09-11 2017-09-20 100.00
让我们说我想留在2017-09-07至2017-09-15。因此,对于DATEDIFF,我需要计算价格为70天的天数以及价格为100天的天数。最后我想显示总数。
任何人都可以帮我构建此查询吗?我希望它清楚什么问题!
答案 0 :(得分:2)
假设没有定义重叠范围,并且假设给定的所有范围都是包容性的,我们可以使用CTE获得数据,然后是简单的聚合问题:
declare @t table (date_from date,date_to date, price_per_room int)
insert into @t (date_from,date_to,price_per_room) values
('20170901','20170910',70.00 ),
('20170911','20170920',100.00)
declare @Start date
declare @End date
select @Start = '20170907',@End = '20170915'
;With IncludedPeriods as (
select
CASE WHEN @Start > date_from THEN @Start ELSE date_from END as fromDT,
CASE WHEN @End < date_to THEN @End ELSE date_to END as ToDT,
price_per_room
from
@t
where
date_from <= @End and
@Start <= date_to
)
select
SUM(price_per_room * (1 + DATEDIFF(day,fromDT,ToDT)))
from
IncludedPeriods
请注意,我们会在DATEDIFF
结果中添加一个,因为它会计算过渡,但我假设来自的句点 &#39; 20170911&#39; to &#39; 20170911&#39;应该算一天和更长的时间。
与其他一些试图列举各种&#34;案例的答案不同。对于重叠,这使用简单规则 - 如果第一个在第二个结束之前开始则两个周期重叠,如果第二个结束在第一个结束之前开始则 - 这是{{1 CTE里面的子句。为了确定重叠的范围,我们采用两个开始日期的后期和两个结束日期中较早的日期 - 这是where
表达式正在做什么。如果我们在日期操作时使用了标量CASE
和MIN
函数,那么我更倾向于使用SQL Server中内置的函数。
答案 1 :(得分:0)
在SQL Server中,您可以执行以下操作:
select dateadd(d, number, '20170801')
from master.dbo.spt_values
where type='P' and (number <= datediff(d, '20170801', '20170810'))
您计算总天数(在where子句中),并选择从0到总天数的数字(master.dbo.spt_values
是SQL Server中的一个有用的表)。否则,您可以创建一个从0到?的递增数字的表。然后你将startdate添加到数字中。所以你得到预订的所有日子:
2017-08-01
2017-08-02
2017-08-03
2017-08-04
2017-08-05
2017-08-06
2017-08-07
2017-08-08
2017-08-09
2017-08-10
然后你可以在date_from和date_to上加入你给定的price_table,你可以计算你的总和。
编辑:只是为了完成它......: - )
SELECT SUM(price_per_room)
FROM master.dbo.spt_values
LEFT OUTER JOIN room_prices AS rp ON (date_from <= DATEADD(d, number, my_start_date) AND DATEADD(d, number, my_start_date) <= date_to)
WHERE type='P' AND (number <= DATEDIFF(d, my_start_date, my_end_date))
答案 2 :(得分:-1)
您可以使用日历或日期表进行此类操作。
如果不采用创建表格的实际步骤,您可以使用日期为common table expression的特殊表格,如下所示:
<form class="container">
<div class="form-group">
<label class="form-control-label" for="inputSuccess1">Input with success</label>
<input type="text" class="form-control is-valid" id="inputSuccess1">
<div class="valid-feedback">Success! You've done it.</div>
</div>
</form>
rextester演示:http://rextester.com/MCF52261
返回:
declare @fromdate date = '20170907';
declare @thrudate date = '20170915';
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (datediff(day, @fromdate, @thrudate)+1)
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date]
)
select total_price = sum(price_per_room)
from dates d
inner join t
on d.date >= t.date_from
and d.date <= t.date_to
有关价格和日期的更详细分类,您可以将以上+-------------+
| total_price |
+-------------+
| 780 |
+-------------+
换成以下内容:
select
rextester演示:http://rextester.com/NKZD1468
返回:
select
fromdate = min(date)
, thrudate = max(date)
, days = count(*)
, price_per_room = avg(price_per_room)
, total = sum(price_per_room)
from dates d
inner join t
on d.date >= t.date_from
and d.date <= t.date_to
group by grouping sets ((price_per_room),())
<小时/> 数字和日历表参考:
答案 3 :(得分:-1)
我建议使用Date表(包含所有日期的表)或派生表来填充这些日期(您可以在线轻松找到它),如下所示:
SELECT p.id,p.room_type_id,sum(p.price_per_room)
FROM(
SELECT t.date,s.price_per_room,s.id,s.room_type_id
FROM (DATES QUERY \ DATE_TABLE) t
LEFT JOIN s.yourTable
ON(t.date between s.date_from and s.date_to)) p
WHERE p.id = YourID and p.room_type_id = YourTypeId
AND p.date between yourStartDate and yourEndDate
GROUP BY p.id,p.room_type_id
在价格的日期范围内为每个日期填充一行,因此它会知道每天的价格是多少,然后只是在您想要的日期之间加上价格。
答案 4 :(得分:-1)
对所有四种可能情况使用UNION ALL
也可以完成这项工作
SELECT SUM(x.p)
FROM
(
SELECT (DATEDIFF(DAY, @from, date_to)+1)* price p
FROM tab
WHERE date_to BETWEEN @from AND @to AND NOT date_from BETWEEN @from AND @to
UNION ALL
SELECT ISNULL(SUM((DATEDIFF(DAY, date_from, date_to)+1)* price), 0) p
FROM tab
WHERE date_to BETWEEN @from AND @to AND date_from BETWEEN @from AND @to
UNION ALL
SELECT (DATEDIFF(DAY, date_from, @to)+1)* price p
FROM tab
WHERE date_from BETWEEN @from AND @to AND NOT date_to BETWEEN @from AND @to
UNION ALL
-- in the case that the (@from, @to) interval is completely in one row interval
SELECT (DATEDIFF(DAY, @from, @to)+1)* price p
FROM tab
WHERE date_from <= @from AND date_to >= @to
)x;