预订表中一年的占用天数

时间:2015-07-31 10:31:28

标签: mysql sql date count intervals

我已经读过这个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 ;

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

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

-- 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行,并使用更明确的语句。