【问题标题】:Number of occupied days in a year from reservation table预订表中一年的占用天数
【发布时间】:2015-07-31 10:31:27
【问题描述】:

我已阅读此question,但它并没有真正帮助我。 我有一个类似的房屋预订系统。因此,每当有人需要租房时,他只需登录并选择他想要的房子是免费的时间,然后预订。所以就我而言,我也有一个 start_time 和 end_time。在我的记录中,我为每个日期精确了时间(日期时间格式),因此我可以根据时间精度计算日期差异。这是我的数据库示例:

CREATE TABLE IF NOT EXISTS `bookings` (
  `id_booking` int(11) NOT NULL AUTO_INCREMENT,
  `id_user_staff` int(11) NOT NULL,
  `start_date` datetime NOT NULL,
  `end_date` datetime NOT NULL,
  `details` text,
  `statut` varchar(45) DEFAULT NULL,
  `id_house` int(1) NOT NULL,
  `fees` decimal(6,0) DEFAULT NULL,
  `ip_user` varchar(15) NOT NULL,
  `date_booked` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id_booking`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `users` (
  `id_user` int(5) NOT NULL DEFAULT '0',
  `Last_Name` varchar(23) DEFAULT NULL,
  `First_Name` varchar(23) DEFAULT NULL,
  `Job_Title` varchar(56) DEFAULT NULL,
  `Status` varchar(19) DEFAULT NULL,
  `Company` varchar(38) DEFAULT NULL,
  `Mobile` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id_user`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `house` (
  `id_house` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `details` text,
  PRIMARY KEY (`id_house`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

我现在的需要是确定房屋在一年内的占用情况,该精确度基于该房屋的预订天数。该百分比是基于预订天数与一年中天数的比率。 什么是我的查询来获得天数并试图避免类似问题的问题,有时会计算两次?

【问题讨论】:

  • 听起来您已经有一个返回一些不需要的值的查询?介意与我们分享吗?
  • 人们按小时预订房屋?
  • 分享你当前的查询你做了什么来得到结果?
  • @Olli 我已经使用了我注意到的问题的查询

标签: mysql sql date count intervals


【解决方案1】:

您可以使用DATEDIFF,它为您提供两个日期之间的天数。但由于DATEDIFF('2015-01-01', '2015-01-01') 的结果为 0 天,因此您必须在结果中添加 1 天。

然后,总结每个房子的所有差异:

SELECT id_house, SUM(DATEDIFF(end_date, start_date) + 1) 
FROM bookings 
GROUP BY id_house

当然,在 2015 年 1 月 1 日至 2015 年 1 月 2 日和 2015 年 1 月 2 日至 2015 年 1 月 3 日期间预订的房子将导致三天预订,因为一天被预订两次。之后您可以减去这些重复预订:

SELECT id_house, COUNT(*) 
FROM bookings b1
WHERE (id_house, date(start_date)) IN 
( SELECT id_house, date(end_date) FROM bookings AS b2 WHERE b1.id_booking <> b2.id_booking )
ORDER BY id_house

这会为您提供同时为 start_date 和 end_date 的天数(在两个不同的预订中)。

最后,我会使用如下查询,总结一下:

SELECT bookingdays.id_house, bookingdays.days, COALESCE(doublebookings.doubledays, 0), bookingdays.days - COALESCE(doublebookings.doubledays, 0) AS totaldays
FROM
(SELECT id_house, SUM(DATEDIFF(end_date, start_date) + 1) AS days
FROM bookings 
GROUP BY id_house) bookingdays
LEFT OUTER JOIN
(SELECT id_house, COUNT(*) AS doubledays
FROM bookings b1
WHERE (id_house, date(start_date)) IN 
( SELECT id_house, date(end_date) FROM bookings AS b2 WHERE b1.id_booking <> b2.id_booking )
ORDER BY id_house) doublebookings
ON bookingdays.id_house = doublebookings.id_house

【讨论】:

    【解决方案2】:

    在报告域中处理日期的最佳方式是使用日期维度:

    -- Source:
    -- http://www.joyofdata.de/blog/setting-up-a-time-dimension-table-in-mysql/
    SET @d0 = "2000-01-01";
    SET @d1 = "2020-01-01";
    
    SET @date = date_sub(@d0, interval 1 day);
    
    # set up the time dimension table
    DROP TABLE IF EXISTS date_dimension;
    CREATE TABLE `date_dimension` (
      `date` date DEFAULT NULL,
      `id` int NOT NULL,
      `y` smallint DEFAULT NULL,
      PRIMARY KEY (`id`)
    );
    
    # populate the table with dates
    INSERT INTO date_dimension
    SELECT @date := date_add(@date, interval 1 day) as date,
        # integer ID that allows immediate understanding
        date_format(@date, "%Y%m%d") as id,
        year(@date) as y
    FROM T
    WHERE date_add(@date, interval 1 day) <= @d1
    ORDER BY date
    ;
    

    拥有日期维度表后,您可以将预订加入其中并计算唯一日期。

    每年的天数:

    SELECT year, COUNT(*) FROM date_dimension GROUP BY YEAR; 
    

    每年的预订天数和酒店:

    SELECT year, house_id, COUNT(DISTINCT d.date)
    FROM date_dimension d INNER JOIN bookings b
       ON d.date BETWEEN b.start_date AND b.end_date
    GROUP BY year, house_id
    

    您可以将第一个查询修改为子查询以获取百分比:

    SELECT d.year, b.house_id,
      COUNT(DISTINCT d.date) / 
      (SELECT COUNT(*) 
       FROM date_dimension WHERE year =d.year) AS annual_percent
    FROM date_dimension d INNER JOIN bookings b
       ON d.date BETWEEN b.start_date AND b.end_date
    GROUP BY year, house_id
    

    您会在工作中注意到,如果使用日期维度,与日期相关的计算将使用更少的 SQL 行和更明确的语句。

    【讨论】:

      猜你喜欢
      • 2023-03-10
      • 2017-10-16
      • 2021-12-29
      • 2019-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多