两个日期列和一个日期范围,典型的查询?

时间:2012-02-16 09:27:42

标签: mysql date methods

我有一张桌子

tbl_charge

id hotel_id start_date  end_date    charge_per_day ( in $)  
1   6       2012-02-15  2010-02-15      20  
2   6       2012-02-16  2010-02-18      30  
4   6       2012-02-20  2010-02-25      50  
  

注意:如果表格中没有任何日期,我们会为每天设置25$(即默认费用

现在如果有人想从 2012-02-15 预订酒店到 2012-02-22 ,那么我想计算日期的总费用

Date   : 15+16+17+18+19+20+21+22
Charge : 20+30+30+30+25+50+50+50 = 285$

到目前为止我做了什么:

此查询成功返回所有行

SELECT * FROM `tbl_charge` WHERE 
start_date BETWEEN '2012-02-15' AND '2012-02-22' OR
end_date BETWEEN '2012-02-15' AND '2012-02-22' OR
( start_date <'2012-02-15' AND end_date > '2012-02-22')
HAVING property_id=6 

它返回所有必要的行,但如何汇总费用?

  • 以任何方式计算给定日期范围之间的天数,如最后一行是20 -25但我只想要22,然后它返回3天,我们将费用乘以3
  • 为此创建过程或使用简单查询
  • 是否合适

2 个答案:

答案 0 :(得分:4)

我认为这会解决问题:

select sum(DayDifference * charge_per_day) + 
        (RealDayDifference - sum(DayDifference)) * 25 as TotalPerPeriod
from (
  select charge_per_day, datediff(
      least(end_date, '2012-02-22'),
      greatest(start_date, '2012-02-15')) + 1 as DayDifference,
      datediff('2012-02-22', '2012-02-15') + 1 as RealDayDifference
  from t1
  where
    ((start_date between '2012-02-15' and '2012-02-22') or
    (end_date between '2012-02-15' and '2012-02-22') or
    (start_date < '2012-02-15' and end_date > '2012-02-22'))
    and hotel_id=6
) S1

答案 1 :(得分:1)

我以前必须解决同样的问题并且这是一个有趣的问题,但从那以后我学到了一些更好的方法。当时我认为我创建了一个程序或函数来循环所请求的日期并返回价格。

要返回所需的行,您只需使用上限和下限进行选择即可。您可以在选择条件中执行日期更改,以返回要应用的每个迭代次数。

如果您最终寻找的只是单一价格,我建议将此逻辑组合成一个函数

我假设第二个表,tbh_hotel的id(int PK == hotel_id)和default_charge(int)的行(id = 6,default_charge = 20)

进一步的假设是,如果您的日期是“2010”,那么您的意思是“2012”,这是针对在15日登记入住的人,以及22日退房的人(因此需要酒店15日,16日,17日,18日,19日,20日,21日,7晚)。我还假设你有逻辑来防止日期范围重叠,因此tbl_charge中没有2行与2012年2月14日相匹配(例如)

因此,要启动此操作,请选择适用的行

SELECT 
    *
FROM tbl_charge AS c
WHERE 
(
  c.end_date >= '2012-02-15'
  OR
  c.start_date < '2012-02-22'
)

这几乎就是您已经拥有的内容,因此现在将添加更多字段以获取每个规则应用的天数信息。

SET @StartDate = '2012-02-15';
SET @EndDate = SUBDATE('2012-02-22',1);

SELECT 
    c.id,
    c.start_date,
    c.end_date,
    c.charge_per_day,
    DATEDIFF(IF(c.end_date>@EndDate,@EndDate,c.end_date),SUBDATE(IF(c.start_date<@StartDate,@StartDate,c.start_date),1)) AS quantityOfThisRate
FROM tbl_charge AS c
WHERE c.end_date >=@StartDate OR c.start_date < @EndDate

我正在提交结束日期,因为如果您在22日退房,您的最终入住日期是21日。我在每个DATEDIFF上提交开始日期,因为如果你在15日停留 - &gt; 16日,END DATE的子状态使得这个15-15号,所以这个SUBDATE使它得到14th-15th以返回正确的值1.输出现在看起来有点像这样

id  start_date  end_date    price   quantityAtThisRate
1   2012-02-10  2012-02-15  20  1
2   2012-02-16  2012-02-18  30  3
3   2012-02-20  2012-02-29  50  2

所以继续我会把它放到子查询中并组合tbl_hotel以获得默认费用

SET @StartDate = '2012-02-15';
SET @EndDate = SUBDATE('2012-02-22',1);
SET @NumberOfNights = DATEDIFF(ADDDATE(@EndDate,1),@StartDate);
SET @HotelID = 6;


SELECT 
    SUM(specificDates.charge_per_day*specificDates.quantityAtThisRate) AS specificCharges,
    @NumberOfNights-SUM(specificDates.quantityAtThisRate) AS daysAtDefault,
    h.default_charge * (@NumberOfNights-SUM(specificDates.quantityAtThisRate)) AS defaultCharges
FROM tbl_hotel AS h
INNER JOIN
(
    SELECT 
        c.charge_per_day,
        DATEDIFF(IF(c.end_date>@EndDate,@EndDate,c.end_date),SUBDATE(IF(c.start_date<@StartDate,@StartDate,c.start_date),1)) AS quantityAtThisRate
    FROM tbl_charge AS c
    WHERE (c.end_date >=@StartDate OR c.start_date < @EndDate) AND c.hotel_id = @HotelID
) AS specificDates

WHERE h.id = @HotelID

实际上,单个查询会变得相当复杂,所以我会依赖于上面的逻辑来解决存储过程(好像没有特定的规则,上面的查询会因内部连接而返回null)< / p>

希望这有帮助