You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL中三张表连接实现事件每日预订数时间线的问题

解决方法:生成事件每日预订数时间线(无预订显示0)

嘿,我来帮你搞定这个问题!你需要的其实是先构建出所有事件 × 指定日期范围的完整组合,再关联预订数据补全数量——这是这类时间线统计的经典套路,我给你拆解清楚:

核心思路

要实现“每个日期对应所有事件及当日预订数(无则为0)”,关键是先确保不会漏掉任何「事件-日期」组合,再用左连接把预订数据挂上去,最后把空值转成0。

假设表结构(你可以替换成自己的表名/字段)

先明确三张表的核心字段(如果你的表结构不同,对应调整即可):

  • events(事件表):event_id(事件唯一ID)、event_name(事件名称)等
  • date_range(日期范围表):date(统计日期,比如2017-01-01)
  • event_daily_bookings(事件每日预订统计表):event_id、booking_date(预订日期)、booking_count(当日预订数)

完整SQL示例

SELECT
  e.event_id,
  e.event_name,
  dr.date AS report_date,
  -- 用COALESCE把无预订的NULL值转为0
  COALESCE(edb.booking_count, 0) AS daily_bookings
FROM
  -- 第一步:交叉连接事件表和日期表,生成所有可能的事件-日期组合
  events e
CROSS JOIN date_range dr
  -- 第二步:左连接预订统计表,匹配事件ID和日期
LEFT JOIN event_daily_bookings edb
  ON e.event_id = edb.event_id
  AND dr.date = edb.booking_date
-- 可选:如果日期范围表包含更多日期,在这里筛选近X天
-- WHERE dr.date >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY
  dr.date, e.event_id;

常见场景补充

1. 没有现成的日期范围表?动态生成!

如果你的数据库里没有提前准备好date_range表,可以用数据库自带的函数动态生成近X天的日期:

  • PostgreSQL 用generate_series:
    WITH date_range AS (
      SELECT CURRENT_DATE - INTERVAL 'n days'::DATE AS date
      FROM generate_series(0, 29) AS n -- 生成近30天(含今天)
    )
    SELECT
      e.event_id,
      e.event_name,
      dr.date AS report_date,
      COALESCE(edb.booking_count, 0) AS daily_bookings
    FROM events e
    CROSS JOIN date_range dr
    LEFT JOIN event_daily_bookings edb
      ON e.event_id = edb.event_id
      AND dr.date = edb.booking_date
    ORDER BY dr.date, e.event_id;
    
  • MySQL 用递归CTE:
    WITH RECURSIVE date_range AS (
      SELECT CURRENT_DATE AS date
      UNION ALL
      SELECT date - INTERVAL 1 DAY FROM date_range WHERE date > CURRENT_DATE - INTERVAL 29 DAY
    )
    -- 后面的查询和上面一致
    

2. 预订表是原始记录而非统计好的?先聚合!

如果event_daily_bookings不是按日期统计好的表,而是每条预订记录的明细,那要先按事件和日期聚合计算数量:

WITH aggregated_bookings AS (
  SELECT
    event_id,
    booking_date,
    COUNT(*) AS booking_count -- 如果有预订数量字段,用SUM(quantity)更准确
  FROM event_booking_details -- 你的原始预订明细表
  GROUP BY event_id, booking_date
)
SELECT
  e.event_id,
  e.event_name,
  dr.date AS report_date,
  COALESCE(ab.booking_count, 0) AS daily_bookings
FROM events e
CROSS JOIN date_range dr
LEFT JOIN aggregated_bookings ab
  ON e.event_id = ab.event_id
  AND dr.date = ab.booking_date
ORDER BY dr.date, e.event_id;

这样执行后,就能得到你需要的结果:每个日期下所有事件的当日预订数,没有预订的会显示0,完美适配生成时间线图表的需求!

内容的提问来源于stack exchange,提问作者Fabian Tuender

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:12:04