寻找关于从何处开始查询的一些指导,这些问题让我头疼。
我有一张表格显示试用开始时间&每个帐户的结束日期,如下所示:
account_id trial_start trial_end
========== =========== =========
123 1/2/2017 1/9/17
234 1/8/2017 1/21/17
456 1/15/2017 5/10/17
试用开始日期和结束日期各不相同,我想要一个结果表格,向我显示一年中每周的每个帐户ID。通过这种方式,我可以说我在一年中的每个星期都进行了多少次活动试验,并且可以查看在试用期间有多少这些帐户实际登录。也许是这样的事情:
week account_id
=========== =========
1/1/2017 123
1/8/2017 123
1/8/2017 234
1/15/2017 234
1/15/2017 456
1/22/2017 456
...
5/7/2017 456
我有一个参考表,每年的每个星期都有一行,我觉得我需要以某种方式将我的帐户ID加入到该表中的每一行,但我无法弄清楚每周如何映射在每个星期的行的开始和结束日期之间,以便我捕获之间的日期:/
答案 0 :(得分:0)
形成笛卡尔帐户和周数的产品,然后将周盯着日期放在跟踪日期中(这将每周提取一次)。
PostgreSQL 9.6架构设置:
CREATE TABLE TrialDates
(account_id int, trial_start timestamp, trial_end timestamp)
;
INSERT INTO TrialDates
("account_id", "trial_start", "trial_end")
VALUES
(678, '2017-01-04 00:00:00', '2017-01-05 00:00:00'),
(123, '2017-01-02 00:00:00', '2017-01-09 00:00:00'),
(234, '2017-01-08 00:00:00', '2017-01-21 00:00:00'),
(456, '2017-01-15 00:00:00', '2017-05-10 00:00:00')
;
CREATE TABLE Weeks
("week_start" timestamp)
;
INSERT INTO Weeks
("week_start")
VALUES
('2017-01-16 00:00:00'),
('2017-01-09 00:00:00'),
('2017-01-02 00:00:00')
;
查询1 :( 已编辑)
select w.week_start, td.account_id
from (select distinct account_id from TrialDates) a
cross join Weeks w
inner join TrialDates td on a.account_id = td.account_id
and (
w.week_start >= td.trial_start and w.week_start < trial_end
OR
td.trial_start >= w.week_start and td.trial_start < w.week_start + interval '7 days'
)
order by w.week_start, td.account_id
<强> Results 强>:
| week_start | account_id |
|----------------------|------------|
| 2017-01-02T00:00:00Z | 123 |
| 2017-01-02T00:00:00Z | 234 |
| 2017-01-02T00:00:00Z | 678 |
| 2017-01-09T00:00:00Z | 234 |
| 2017-01-09T00:00:00Z | 456 |
| 2017-01-16T00:00:00Z | 234 |
| 2017-01-16T00:00:00Z | 456 |
对于可能没有现有周表的读者,使用PostgreSQL非常出色的generate_series
功能可以获得相同的结果。因此,动态生成周数的交叉连接,系列的下边界和上边界日期也是动态确定的。
select w.week_start, td.account_id
from (select distinct account_id from TrialDates) a
cross join (
select
date_trunc('week', dates.d) as week_start
from generate_series(
(select date_trunc('week',min(trial_start)) from TrialDates)
,
(select date_trunc('week',max(trial_start) + interval '6 days') from TrialDates)
, '1 day'
) as dates(d)
group by 1
) w
inner join TrialDates td on a.account_id = td.account_id
and (
w.week_start >= td.trial_start and w.week_start < trial_end
OR
td.trial_start >= w.week_start and td.trial_start < w.week_start + interval '7 days'
)
order by w.week_start, td.account_id
;