我有一个包含两列的简单表:emp_id
和date
。每当员工为当天打拳时,日期都会附加到此表格中。
在某些时间间隔内,我必须检查哪些员工在过去8周内每2周工作3天或更少。我的查询如下:
select x.emp_id
from
(
select
emp_id
, sum(case when tt.date >= dateadd('week', -8, '2016-08-15') and tt.date < dateadd('week', -6, '2016-08-15') then 1 else 0 end) as four_biweeks_ago
, sum(case when tt.date >= dateadd('week', -6, '2016-08-15') and tt.date < dateadd('week', -4, '2016-08-15') then 1 else 0 end) as three_biweeks_ago
, sum(case when tt.date >= dateadd('week', -4, '2016-08-15') and tt.date < dateadd('week', -2, '2016-08-15') then 1 else 0 end) as two_biweeks_ago
, sum(case when tt.date >= dateadd('week', -2, '2016-08-15') and tt.date < '2016-08-15' then 1 else 0 end) as last_biweek
from temps_timetable tt
where tt.date >= dateadd('week', -8, '2016-08-15')
) x
where x.four_biweeks_ago <= 3
and x.three_biweeks_ago <= 3
and x.two_biweeks_ago <= 3
and x.last_biweek <= 3
但是,我希望“升级”此查询并使其动态化,以适应过去几周的任何数量。由于此查询是从内部接口运行的,因此唯一的动态字段是引用日期(在本例中为2016-08-15
)和每个最大日期数(3
)。我可以通过用户界面使过去双周的数量变得灵活,但我不知道如何升级查询以处理超过4 sum
行,因为这应该更改查询本身。例如,将其设置为过去10周意味着我必须添加sum(case when tt.date >= dateadd('week', -10, '2016-08-15') and tt.date < dateadd('week', -8, '2016-08-15') then 1 else 0 end) as five_biweeks_ago
。别名无所谓,顺便说一句。
我试着阅读PIVOT
来处理这个问题,但逻辑目前正在逃避我。
TL; DR:如何更改查询以便我可以动态容纳过去Z周内每Y周的X个日期?
答案 0 :(得分:1)
转动表格的关键是使用floor()
(请参阅Redshift documentation)并将其与datediff()
相结合,这样可以轻松按给定时间间隔进行分区,即每两周一次。
因此,这应该会产生与查询相同的结果:
with _reference as (
select
'2016-08-15'::date as date
, 8::int as weeks_ago -- Z
, 2::float as partition -- Y
, 3::int as max_count -- X
),
_stats as (
select
emp_id
/** If datediff=3 and partition=2, this returns 1: */
, floor(datediff(week, temps_timetable.date, _reference.date) / _reference.partition) as partition_in_past
, count(distinct temps_timetable.date)
from
_reference, temps_timetable
where
datediff(week, temps_timetable.date, _reference.date) <= _reference.weeks_ago
and
temps_timetable.date < _reference.date
group by
emp_id
, partition_in_past
)
select emp_id
from _stats, _reference
group by emp_id
having sum(case when _stats.count > _reference.max_count then 1 else 0 end) = 0
;