如何查询MySQL数据库以获取某个日期范围内每晚的价格?

问题描述 投票:0回答:2

我有这三张桌子:

酒店
酒店_id
酒店名称
房间
房间_id
酒店_id
房间价格
房间_id
开始日期
价格

其中“start_date”存储价格更改为“price”的日期。

我知道如何查询数据库来获取给定 room_id 和给定酒店住宿日期的价格。所以我可以做到这一点,但是,当涉及到在很长的日期范围内执行此操作时,这变得不切实际。

因此,我如何查询数据库才能得到类似的输出

房间_id 日期 价格
1 签到 x1
x2
1 签出 xm
2 签到 y1
y2
2 签出 ym
n 签到 z1
z2
n 签出 zm

这里的“check_in”是客户选择的第一晚,“check_out”是客户选择的最后一晚

这将使计算给定房间的总价格变得更加容易,而不必每天单独计算。

注意:我使用的是 MySQL 5.7

sql mysql mysql-5.7
2个回答
1
投票

您可以动态创建日期系列,如 Bagus Tesa 建议的 答案 所示,或者维护日历表。鉴于日期在预订/预订应用程序中发挥着重要作用,我建议创建一个简单的日历表。

在本例中,我使用的日历表只有一个 dt (

DATE
) 列,您可以轻松地使用存储过程(或您选择的任何其他方法)填充该列:

CREATE TABLE calendar (dt DATE NOT NULL PRIMARY KEY);

DELIMITER $$
CREATE PROCEDURE `filldates`(dateStart DATE, dateEnd DATE)
BEGIN
  WHILE dateStart <= dateEnd DO
    INSERT INTO calendar (dt) VALUES (dateStart);
    SET dateStart = dateStart + INTERVAL 1 DAY;
  END WHILE;
END$$
DELIMITER ;

CALL filldates('2023-01-01', '2039-12-31');

然后是预订日期和房间日期之间的

CROSS JOIN
的简单情况,以及用于检索每天每间房间的价格的相关子查询:

SET @checkin = '2023-11-26', @checkout = '2023-12-15';

SELECT r.room_id, COUNT(*) AS nights, (
    SELECT price
    FROM room_price
    WHERE room_id = r.room_id
    AND start_date <= c.dt
    ORDER BY start_date DESC
    LIMIT 1
) AS price
FROM calendar c
CROSS JOIN room r
WHERE c.dt >= @checkin AND c.dt < @checkout
GROUP BY room_id, price;

注意:虽然关键字

CROSS
在MySQL中没有任何意义(它只是一个没有ON子句的INNER连接),但我认为它清楚地表达了意图。

这是一个db<>小提琴


0
投票

以下查询依赖于

join
group by
而不是子查询。它的灵感来自于生成日期系列作为日期参考。您可以将日期生成替换为具体的日期表,如 user1191247 答案建议

select rp.room_id as room_id,
       date_series.date as date,
       any_value(rp.price) as price
  from
  (select *
     from room_price
     order by start_date desc
  ) as rp
  join
  (select * from 
    (select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) date from
     (select 0 t0 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) t0,
     (select 0 t1 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) t1,
     (select 0 t2 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) t2,
     (select 0 t3 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) t3,
     (select 0 t4 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) t4) v
    where date between '2023-01-01' and '2023-05-31'
  ) as date_series
  on rp.start_date <= date_series.date
  group by rp.room_id, date_series.date
  order by rp.room_id, date_series.date;

参见小提琴:https://www.db-fiddle.com/f/umGDya94iodhMcJbTdvkt6/0

规避

SELECT list is not in GROUP BY clause and contains non-aggregated column
错误的基石是使用
Any_Value()
。您可以通过在会话中或永久禁用ONLY_FULL_GROUP_BY
来达到类似的效果。

但是,请注意

Any_Value()

 在 Mysql 5.7 和 Mysql 8.0 之间的行为不同 - 这有点令人惊讶。

© www.soinside.com 2019 - 2024. All rights reserved.