查找每天日期范围内可用的单位数

时间:2016-01-30 14:45:22

标签: mysql sql

我正在为预订系统制作表格架构。预订可以持续数天或数小时。

例如:100台笔记本电脑可供使用,20人在不同日期租用35台笔记本电脑。有不同的登记和结账时间。

我想从结果中生成一个预订日历,显示每天有多少单位可用。

我正在尝试生成显示日期范围的单位数的结果,例如2016-01-01 10:30到2016-01-04 10:30。

Date       | availableUnits
2016-01-01 | 10
2016-01-02 | 6
2016-01-03 | 0
2016-01-04 | 11

广告表

id  | title             | unit
142 | HP Laptop         | 100
143 | Apple MacBook Air | 25

预订表

id  | ad_id | start_date            | end_date              | units
5   | 143   | 2015-08-17 18:18:00   | 2015-08-24 18:18:00   | 5
8   | 142   | 2015-08-20 05:30:00   | 2015-08-31 05:30:00   | 2
1   | 143   | 2015-08-20 16:59:00   | 2015-08-25 16:58:00   | 1
6   | 142   | 2015-08-25 20:37:00   | 2015-08-29 20:37:00   | 1
10  | 142   | 2015-08-27 05:30:00   | 2015-08-29 04:30:00   | 1
11  | 143   | 2015-09-01 05:30:00   | 2015-09-05 05:30:00   | 3
4   | 142   | 2015-09-01 17:20:00   | 2015-10-12 17:20:00   | 2
3   | 143   | 2015-09-01 21:28:00   | 2015-09-30 21:28:00   | 5
19  | 143   | 2015-09-03 05:30:00   | 2015-09-26 05:30:00   | 1
12  | 142   | 2015-09-05 05:30:00   | 2015-09-10 05:30:00   | 1

如果有人喜欢运行查询,我创建了一个SQL小提琴。 SQL fiddle

我尝试过几种不同的方法但没有取得多大成功。存储每天的可用性是一种选择。但是,当广告数量增加时,这可能是一个大问题。如果我这样做,即使是少量广告也可以生成大量数据。

任何建议都是欢迎

1 个答案:

答案 0 :(得分:0)

诀窍是使用每条记录,好像有2条记录。

在预订开始日期,这会对您的股票产生负面影响

SELECT b1.start_date at_date, -b1.units unitsDiff
FROM ad_bookings b1

在预订结束日期,您的股票再次上涨

SELECT b2.end_date at_date, b2.units unitsDiff
FROM ad_bookings b2

如果您想知道在特定时间有多少单位可用,您可以将这两个查询组合起来并按排序顺序求和:

-- availability at specific moment
SELECT grouped.at_date, 
  @sum := COALESCE(@sum,(SELECT unit FROM ads WHERE id = 142)) + grouped.unitsDiff CurrentTotal, grouped.unitsDiff
FROM (
  SELECT sub.at_date, sum(sub.unitsDiff) unitsDiff
  FROM (
      SELECT b1.start_date at_date, -b1.units unitsDiff
      FROM ad_bookings b1
      WHERE b1.ad_id = 142
         UNION
      SELECT b2.end_date at_date, b2.units unitsDiff
      FROM ad_bookings b2
      WHERE b2.ad_id = 142
  ) sub
  GROUP BY sub.at_date
) grouped
ORDER BY grouped.at_date
  • 如果您想针对特定范围执行此操作,则只需要与该范围有任何重叠的ad_bookings

  • 如果您想消除时间并具有特定日期,则可以投射开始日期和结束日期。 CAST(b1.start_date AS DATE) at_date。 (你可能希望将你的end_date和你的start_date放在一起)

  • 如果明确要求所有日期都在范围内,您可以添加虚拟记录,例如UNION '2015-10-22' at_date, 0 unitsDiff

  • 我建议您查询所需的ad_bookings(可能已分组)并让应用程序逻辑处理它。但这取决于你。