假设您有一个包含 Preferred、date_from、date_to 列的表,并且您只是想计算夜晚数。
你可以试试这个查询。
SET @checkin = '2016-01-16';
SET @checkout = '2016-02-08';
SELECT T0.preferred,T0.date_from,T0.date_to,IFNULL(NIGHTS.nights,0) as Nights
FROM YourTable T0
LEFT JOIN
(SELECT T1.preferred,T1.date_from,T1.date_to,COUNT(*) AS Nights
FROM YourTable AS T1
INNER JOIN
(SELECT (@checkin + INTERVAL n DAY) as singleday
FROM numbers
WHERE (@checkin + INTERVAL n DAY) <= @checkout)DAYS1
ON DAYS1.singleday BETWEEN T1.date_from AND T1.date_to
WHERE T1.preferred = 1
OR NOT EXISTS
(SELECT 1
FROM YourTable AS T
WHERE T.preferred = 1
AND DAYS1.singleday BETWEEN T.date_from AND T.date_to
)
GROUP BY T1.preferred,T1.date_from,T1.date_to
)NIGHTS
ON T0.preferred = NIGHTS.preferred
AND T0.date_from = NIGHTS.date_from
AND T0.date_to = NIGHTS.date_to
WHERE
T0.date_from <= @checkout
AND T0.date_to >= @checkin
;
http://sqlfiddle.com/#!9/d64344/10
您可以将 @checkout 和 @checkin 替换为您的实际入住和退房时间。
你可以用你的实际表名替换 YourTable 出现
哦,是的,在 sqlfiddle 中,我包含了一个名为 Numbers 的表,其列 n 包含从 0 向上计数到任何最大可能逗留天数的数字。您还需要创建此表。
要创建表格编号,请使用以下内容
CREATE TABLE numbers AS
SELECT a.n+b.n+c.n+d.n+e.n+f.n+g.n+h.n+i.n as n
FROM
(SELECT 0 as n UNION SELECT 1)a,
(SELECT 0 as n UNION SELECT 2)b,
(SELECT 0 as n UNION SELECT 4)c,
(SELECT 0 as n UNION SELECT 8)d,
(SELECT 0 as n UNION SELECT 16)e,
(SELECT 0 as n UNION SELECT 32)f,
(SELECT 0 as n UNION SELECT 64)g,
(SELECT 0 as n UNION SELECT 128)h,
(SELECT 0 as n UNION SELECT 256)i;
1) 子查询 DAYS1 返回所有单个日期
从@checkin 到@checkout 范围
2) T1 与 DAYS1 WHERE 连接
首选是 1 或不存在覆盖的首选行
DAYS1 的日期
3) 然后我们做一个 COUNT(*) GROUP BY
preferred,date_from,date_to 获取单日计数
4) 然后我们将结果称为 NIGHTS
5) 然后将 T0 与 NIGHTS 左连接以获得具有 0 个夜晚的偶数行
6) 并且只返回截取@checkin/@checkout 范围的 T0 行。
更新如果您的表太大,您可以尝试缩小子查询的范围,只包含您感兴趣的行,就像这样
SET @checkin = '2016-01-16';
SET @checkout = '2016-02-08';
SELECT T0.preferred,T0.date_from,T0.date_to,IFNULL(NIGHTS.nights,0) as Nights
FROM (SELECT * FROM YourTable WHERE date_from <= @checkout AND date_to >= @checkin) T0
LEFT JOIN
(SELECT T1.preferred,T1.date_from,T1.date_to,COUNT(*) AS Nights
FROM (SELECT * FROM YourTable WHERE date_from <= @checkout AND date_to >= @checkin) AS T1
INNER JOIN
(SELECT (@checkin + INTERVAL n DAY) as singleday
FROM numbers
WHERE (@checkin + INTERVAL n DAY) <= @checkout)DAYS1
ON DAYS1.singleday BETWEEN T1.date_from AND T1.date_to
WHERE T1.preferred = 1
OR NOT EXISTS
(SELECT 1
FROM (SELECT * FROM YourTable WHERE date_from <= @checkout AND date_to >= @checkin) AS T
WHERE T.preferred = 1
AND DAYS1.singleday BETWEEN T.date_from AND T.date_to
)
GROUP BY T1.preferred,T1.date_from,T1.date_to
)NIGHTS
ON T0.preferred = NIGHTS.preferred
AND T0.date_from = NIGHTS.date_from
AND T0.date_to = NIGHTS.date_to
;