我对SQL并不满意,但到目前为止,我在项目上取得了很好的进展。现在我完全卡住了。
我试图计算每种状态的公寓数量。我希望每天都能获得这些信息,这样我就可以随着时间推移。我的数据看起来像这样:
table: y_unit_status
unit | date_occurred | start_date | end_date | status
1 | 2017-01-01 | 2017-01-01 | 2017-01-05 | Occupied No Notice
1 | 2017-01-06 | 2017-01-06 | 2017-01-31 | Occupied Notice
1 | 2017-02-01 | 2017-02-01 | | Vacant
2 | 2017-01-01 | 2017-01-01 | | Occupied No Notice
我希望获得如下输出:
date | occupied_no_notice | occupied_notice | vacant
2017-01-01 | 2 | 0 | 0
...
2017-01-10 | 1 | 1 | 0
...
2017-02-01 | 1 | 0 | 1
或者,这种方法可行:
date | status | count
2017-01-01 | occupied no notice | 2
2017-01-01 | occupied notice | 0
date_occurred:单位状态发生变化的日期 start_date:与date_occurred相同 end_date:状态停止为x并更改为y的日期。
我正在拉入卧室的数量和属性ID,因此第二种方法一次选择一种状态的计数会产生相对大量的行而不是选项1(如果这很重要)。
我发现很多参考资料让我接近我正在寻找的东西,但我总是得到一种滚动的累积计数。
这是我的查询,它会生成一列日期和计数,这些日期和计数会随着时间累积而不是反映特定日期的计数快照。您可以看到我对另一个表格的引用,其中我提到了属性ID。表模式是Property - >单位 - >单位状态。
WITH t AS(
SELECT i::date from generate_series('2016-06-29', '2017-08-03', '1 day'::interval) i
)
SELECT t.i as date,
u.hproperty,
count(us.hmy) as count --us.hmy is the id
FROM t
LEFT OUTER JOIN y_unit_status us ON t.i BETWEEN us.dtstart AND
us.dtend
INNER JOIN y_unit u ON u.hmy = us.hunit -- to get property id
WHERE us.sstatus = 'Occupied No Notice'
AND t.i >= us.dtstart
AND t.i <= us.dtend
AND u.hproperty = '1'
GROUP BY t.i, u.hproperty
ORDER BY t.i
limit 1500
我还尝试了一个FOR循环,迭代日期以确定日期在开始和结束之间的情况但我的逻辑不起作用。感谢您的任何见解!
答案 0 :(得分:3)
您走在正确的轨道上,但您需要处理NULL
中的end_date
值。如果这些意味着status
假设在未来的某个地方被改变(但不确定它何时会改变),containment operators (@>
and <@
)的daterange
type对你来说是完美的(因为范围可以是&#34;无界&#34):
with params as (
select date '2017-01-01' date_from,
date '2017-02-02' date_to
)
select date_from + d, status, count(unit)
from params
cross join generate_series(0, date_to - date_from) d
left join y_unit_status on daterange(start_date, end_date, '[]') @> date_from + d
group by 1, 2
要实现第一个变体,您可以使用条件聚合:
with params as (
select date '2017-01-01' date_from,
date '2017-02-02' date_to
)
select date_from + d,
count(unit) filter (where status = 'Occupied No Notice') occupied_no_notice,
count(unit) filter (where status = 'Occupied Notice') occupied_notice,
count(unit) filter (where status = 'Vacant') vacant
from params
cross join generate_series(0, date_to - date_from) d
left join y_unit_status on daterange(start_date, end_date, '[]') @> date_from + d
group by 1
备注:
filter (where <predicate>)
是9.4+的新手。在此之前,您可以使用CASE
(以及大多数聚合函数不包含NULL
值的事实)来模拟它。daterange(start_date, end_date, '[]')
(使用gist
)编入索引以获得更好的效果。