基于PostgreSQL按天存储的property_calendars表计算入住率
没问题,我来帮你搞定PostgreSQL里计算物业入住率的需求!结合你给出的property_calendars表结构(按天存储单条记录),我会分几种常见场景给出SQL方案,你可以根据实际需求调整。
核心逻辑说明
入住率的常规定义是:
入住率 = (已预订天数 / 统计周期内的有效天数) × 100%
这里的「有效天数」可以是周期内的总天数,也可以是物业可售天数(排除维护、不可用等状态),下面的示例会分别覆盖这两种情况。
场景1:单个物业指定时间段的入住率(按表中记录的天数计算)
如果你的表中已经完整存储了目标周期内的所有日期记录(每天一行),可以直接用这个查询:
SELECT property_id, COUNT(*) FILTER (WHERE status = 'booked') AS booked_days, COUNT(*) AS total_days_in_period, ROUND( (COUNT(*) FILTER (WHERE status = 'booked')::NUMERIC / COUNT(*)) * 100, 2 ) AS occupancy_rate_percent FROM property_calendars WHERE property_id = 56 -- 替换为你要查询的物业ID AND date BETWEEN '2017-10-01' AND '2017-10-31' -- 替换为目标统计周期 GROUP BY property_id;
COUNT(*) FILTER (WHERE status = 'booked'):精准统计该物业在周期内的已预订天数- 转换为
NUMERIC是为了避免PostgreSQL的整数除法(如果用整数计算会直接取整,丢失精度) ROUND(..., 2)用来把百分比保留两位小数,看起来更直观
场景2:单个物业指定时间段的入住率(按实际日历天数计算)
如果你的表中可能存在日期缺失(比如物业刚上线,之前的日期没有记录),这时候用实际日历天数作为基数更准确:
WITH date_range AS ( -- 生成目标周期内的所有日期 SELECT generate_series( '2017-10-01'::DATE, '2017-10-31'::DATE, '1 day'::INTERVAL )::DATE AS date ), property_full_days AS ( -- 左连接日历表,补全缺失的日期记录 SELECT dr.date, pc.status FROM date_range dr LEFT JOIN property_calendars pc ON dr.date = pc.date AND pc.property_id = 56 ) SELECT 56 AS property_id, COUNT(*) FILTER (WHERE status = 'booked') AS booked_days, COUNT(*) AS total_days_in_period, -- 这里就是周期的实际总天数 ROUND( (COUNT(*) FILTER (WHERE status = 'booked')::NUMERIC / COUNT(*)) * 100, 2 ) AS occupancy_rate_percent FROM property_full_days;
这个方案用CTE生成了完整的日期序列,确保即使某天没有记录,也会被纳入统计,结果更贴合真实的日历周期。
场景3:按物业+月份分组统计入住率
如果需要批量统计多个物业在不同月份的入住率,可以用DATE_TRUNC来按月份分组:
SELECT property_id, DATE_TRUNC('month', date)::DATE AS month_start, -- 显示每个月的第一天 COUNT(*) FILTER (WHERE status = 'booked') AS booked_days, COUNT(*) AS total_days_in_month, ROUND( (COUNT(*) FILTER (WHERE status = 'booked')::NUMERIC / COUNT(*)) * 100, 2 ) AS occupancy_rate_percent FROM property_calendars WHERE date >= '2017-01-01' AND date < '2018-01-01' -- 统计2017年全年 GROUP BY property_id, DATE_TRUNC('month', date) ORDER BY property_id, month_start;
场景4:基于「可售天数」计算入住率
如果你的业务中存在不可售状态(比如维护、暂停预订),需要排除这些天数来计算入住率,可以调整查询:
SELECT property_id, COUNT(*) FILTER (WHERE status = 'booked') AS booked_days, COUNT(*) FILTER (WHERE status IN ('booked', 'available')) AS available_days, -- 可售天数:已预订+可预订 ROUND( (COUNT(*) FILTER (WHERE status = 'booked')::NUMERIC / COUNT(*) FILTER (WHERE status IN ('booked', 'available'))) * 100, 2 ) AS occupancy_rate_percent FROM property_calendars WHERE property_id = 56 AND date BETWEEN '2017-10-01' AND '2017-10-31' GROUP BY property_id;
这里把「可售天数」定义为status是booked或available的天数,你可以根据实际的状态值修改这个条件。
内容的提问来源于stack exchange,提问作者larpo
相关产品推荐
相关产品推荐

