从预订开始一年中的入住天数 table

Number of occupied days in a year from reservation table

我读过这个 question 但它并没有真正帮助我。 我有一个类似的房屋预订系统。因此,每当有人需要租房时,他只需登录 select 一个他想要的房子有空的时间,然后预订。所以在我的例子中,我还有一个 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 ;

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

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

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

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

当然,从 2015-01-01 到 2015-01-02 和从 2015-01-02 到 2015-01-03 预订的房子将导致预订三天,因为一天被预订两次.您可以在之后减去这些双重预订:

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

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

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

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

每年天数:

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 和更明确的语句。