簡體   English   中英

使用MySQL和PHP計算日期期間的占用天數

[英]Calculate Number of Occupied Days within a date period using MySQL and PHP

我有一個公寓預訂系統,需要根據房產的基礎生成一個日期內未開工日數與空房日數的報告。

請注意,在選定的時間段內,某些預訂可能會在開始/結束日期之前和/或之后開始。

我發現這個 - 在一個月內的DateRange里面的MySQL天數(預訂表) - 這是沿着正確的行,但我不希望它在固定的,逐月的基礎上,而是在兩個可變日期之間。

理想情況下,我只想使用MySQL,但如果需要PHP則可以。

我能想到的唯一方法是單獨循環每一天並檢查當天是否有入住,但這看起來效率低得令人難以置信。

編輯:我設法調整其他問題的代碼如下:

CREATE TABLE IF NOT EXISTS `view_bookings` (
`bkg_id` int(11) NOT NULL AUTO_INCREMENT,
`apt_id` int(10) NOT NULL,
`apt_name` varchar(50) NOT NULL,
`start_date` date DEFAULT NULL,
`end_date` date DEFAULT NULL,
PRIMARY KEY (`bkg_id`),
UNIQUE KEY `bkg_id_UNIQUE` (`bkg_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

INSERT INTO `view_bookings` (`apt_id`, `apt_name`, `start_date`, `end_date`) VALUES
(1, 'Apartment One', '2012-09-02', '2013-02-05'),
(1, 'Apartment One', '2013-02-05', '2013-07-05'),
(2, 'Apartment Two', '2012-12-25', '2013-02-28'),
(2, 'Apartment Two', '2013-03-01', '2013-04-10'),
(2, 'Apartment Two', '2013-04-16', '2013-09-19'),
(3, 'Apartment Three', '2013-01-01', '2013-02-04'),
(3, 'Apartment Three', '2013-02-06', '2013-02-12'),
(3, 'Apartment Three', '2013-02-16', '2013-02-27'),
(3, 'Apartment Three', '2013-02-27', '2013-03-14'),
(3, 'Apartment Three', '2013-03-19', '2013-06-12');

SELECT
SUM(
    1 + DATEDIFF(
        LEAST(end_date, '2013-03-30'),
        GREATEST(start_date, '2013-02-01')
        )
    ) AS days,
    apt_name,
    apt_id
FROM
    view_bookings
WHERE
    start_date <= '2013-03-30'
AND '2013-02-01' <= end_date
GROUP BY
    apt_id

這是有效的,但如果有重疊的預訂,那么它會計算兩天。 我怎么能阻止這個?

可能通過生成開始日期和結束日期之間的所有日期來執行此操作,使用distinct來刪除重復日期。 計算一下,以獲得相關范圍內唯一預訂日期的總數。 然后將該數字與日期范圍內的天數一起使用,以獲得可用天數。

為每間公寓完成: -

SELECT apt_id, apt_name, DaysBooked AS DaysOccupied, DayNumber - DaysBooked AS DaysUnoccupied
FROM
(
    SELECT apt_id, apt_name, COUNT(*) AS DaysBooked
    FROM
    (
        SELECT DISTINCT view_bookings.apt_id, view_bookings.apt_name, DATE_ADD(view_bookings.start_date, INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY) AS BookedDate
        FROM view_bookings
        CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
        CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
        CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) hundreds
        WHERE DATE_ADD(view_bookings.start_date, INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY) <= view_bookings.end_date
        AND DATE_ADD(view_bookings.start_date, INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY) BETWEEN '2013-02-01' AND '2013-02-28'
    ) Sub1
    GROUP BY apt_id, apt_name
) Sub3
CROSS JOIN 
(
    SELECT ABS(DATEDIFF('2013-02-01', '2013-02-28')) + 1 AS DayNumber -- Note that DATEDIFF is giving the difference in days but you want the figure to include the start and end dates so add 1.
) Sub2

請注意,這只能處理最多1000天的日期范圍,但很容易擴展到更多。

嘗試這個。 如果您使用PHP,請先刪除兩行並在SQL語句中使用php變量

SET @START = '2013-02-01';
SET @END = '2013-03-30';
SELECT vb.apt_id, SUM(1 + DATEDIFF(LEAST(vb.end_date, @END), GREATEST(vb.start_date, @START))) AS Days 
FROM view_bookings vb
WHERE (vb.start_date BETWEEN @START AND @END AND vb.end_date BETWEEN @START AND @END) 
OR (vb.start_date < @START AND vb.end_date BETWEEN @START AND @END)
OR (vb.start_date BETWEEN @START AND @END AND vb.end_date > @END) 
OR (vb.start_date < @START AND vb.end_date > @END) 
GROUP BY vb.apt_id

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM