2017-08-29 105 views
2

我的表在这个结构中:重叠获取客房价格日期

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年9月7日至2017年9月15日。因此,对于DATEDIFF,我需要计算价格为70天和价格为100天的天数。最后,我要显示总价。

任何人都可以帮我建立这个查询吗?我希望它明确地问什么!

+0

请不要使用不适用于您的问题的标签。我删除了数据库标记,因为它不清楚你实际使用了哪一个。请添加仅*的标签*您实际使用的数据库 –

+4

在[所以]您应该尝试**自己编写代码**。后** [做更多的研究](//meta.stackoverflow.com/questions/261592)**如果你有问题,你可以**发布你已经尝试**与清楚的解释是什么是'工作**并提供[** Minimal,Complete和Verifiable示例**](// stackoverflow.com/help/mcve)。我建议阅读[问]一个好问题和[完美问题](http://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/)。另外,一定要参加[游览]并阅读[this](// meta.stackoverflow.com/questions/347937/)**。 –

+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结果,因为它计算过渡,但我假设一段“20170911” “20170911”应该算作一天,同样更长的时间。

不像其中一些试图枚举各种“箱子”为重叠其他的答案的,这里采用的简单的规则 - 两个周期重叠,如果第二前的第一次启动结束如果第一端部之前的第二开始 - 这是CTE内where条款中应用的逻辑。为了确定重叠的范围,我们选取​​两个开始日期中较晚的一个和两个结束日期中较早的一个 - 这就是CASE表达式正在做的事情。如果我们在日期上使用了标量MINMAX函数,我宁愿使用这些函数,但没有内置到SQL Server中的函数。

-1

您可以使用日历或日期表来处理这类事情。

如果不考虑创建一个表的实际步骤中,您可以使用日期的即席表,并common table expression像这样:

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 

rextester演示:http://rextester.com/MCF52261

回报:

+-------------+ 
| total_price | 
+-------------+ 
|   780 | 
+-------------+ 

有关价格和价格的更详细的细分日期,您可以交换上述select这一个:

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),()) 

rextester演示:http://rextester.com/NKZD1468

回报:

+------------+------------+------+----------------+-------+ 
| fromdate | thrudate | days | price_per_room | total | 
+------------+------------+------+----------------+-------+ 
| 2017-09-07 | 2017-09-10 | 4 | 70    | 280 | 
| 2017-09-11 | 2017-09-15 | 5 | 100   | 500 | 
| 2017-09-07 | 2017-09-15 | 9 | 86    | 780 | 
+------------+------------+------+----------------+-------+ 


号码和日历表参考:

-1

我会建议使用日期表或派生表来填充这些日期(含所有日期表)(你可以在网上很容易找到它)是这样的:

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 

用于填充行对于每一日期在价格的日期范围内,所以它会知道每天的价格是多少,然后在所需的日期之间对价格进行总结。

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一个有用的表服务器)。否则,您可以创建一个从0到?的升序数字的表格)。然后你添加到开始日期的数字。所以,你得到了预订的所有天:

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 

然后你就可以加入你给price_table上date_from和DATE_TO,你可以计算出你的总和。

编辑:只是为了完成它... :-)

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)) 
+0

我认为在这个答案的介绍中缺少一些东西 - “在SQL Server中(如果有的话)......” - 我认为这是一个标签为[tag:sql-server]的问题。不清楚你要说什么,所以无法修复自己。 –

+0

对不起,我没有看到标签。我编辑了我的答案。谢谢。 – user8527410

-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; 

sqlfiddle demo

+0

如果'@ from'和'@ to'完全包含在一行的周期内(所以'date_from' <'@ from'和'date_to'>'@ to')呢?这就是为什么我不想试图通过分析单独案例来定义重叠。 –

+0

@Damien_The_Unbeliever是真的,我已经更新了解决方案。我承认你的解决方案比较干净,这是我提高它的原因;) –