2014-02-12 34 views
1

我正在Postgres 9.3中的用户活动日志表上撰写分析查询。它有一个注册日期,一个数据字段(可以合计)和一个用户类型。我已经为这个问题构建了一些示例数据/ sql,我希望得到一些帮助来搞清楚最后一部分。测试所需的SQL如下 - 它将删除/创建一个名为facts的表 - 所以一定要在沙箱中工作。如何按查询顺序获取组的所有日期?

我按星期和用户类型汇总数据 - 因此您每周都会得到每个用户类型的数据字段的计数。我遇到的问题是我得到的结果缺少用户类型='x'的一周时间。由于用户类型“x”在9-9-13周没有用户数据,因此不会显示任何行(请参阅下面的示例结果)。我希望那里有一排用户类型和周。我想完成这个任务,如果可能的话,用一个select语句,没有temp或dimension表(这是因为我将这个sql传递给一个业务经理,并且一个自包含的SQL select语句有希望更加傻瓜式的证明( !这种方法的批评是值得欢迎的,但不是一个答案),谢谢大家的任何援助

这里的结果我得到:

 
Sum  test_week  user_type 
4 "2013-09-02" "x" 
5 "2013-09-02" "y" 
10 "2013-09-09" "y" 
2 "2013-09-16" "x" 
1 "2013-09-16" "y" 

这里的结果我想:

 
Sum  test_week  user_type 
4 "2013-09-02" "x" 
5 "2013-09-02" "y" 
0 "2013-09-09" "x" 
10 "2013-09-09" "y" 
2 "2013-09-16" "x" 
1 "2013-09-16" "y" 

这里是测试数据和SQL select语句:

drop table if exists facts; 
create temp table facts (signup_date date, data integer, record_type varchar, alt varchar); 
insert into facts (signup_date, data, record_type) values 
('9/3/2013',1,'x'), 
('9/4/2013',1,'y'), 
('9/5/2013',2,'x'), 
('9/6/2013',3,'y'), 
('9/7/2013',1,'x'), 
('9/8/2013',1,'y'), 
-- note the week of 9/9 to 9/16 has no 'x' records 
('9/9/2013',2,'y'), 
('9/10/2013', 3, 'y'), 
('9/11/2013', 4, 'y'), 
('9/12/2013', 1, 'y'), 
('9/17/2013', 2, 'x'), 
('9/18/2013', 1, 'y'); 

select coalesce(data, 0), test_week, record_type 
    from 
    (select sum(data) as data, record_type, to_timestamp(EXTRACT(YEAR FROM signup_date) || ' ' || EXTRACT(WEEK FROM signup_date),'IYYY IW')::date as test_week 
    from facts 
    group by record_type, test_week 
    ) as facts 
    order by test_week, record_type 

回答

1
select 
    coalesce(sum(data), 0) as "Sum", 
    to_char(date_trunc('week', c.signup_date), 'YYYY-MM-DD') as test_week, 
    c.record_type as user_type 
from 
    facts f 
    right join 
    (
     (
      select distinct record_type 
      from facts 
     ) f1 
     cross join 
     (
      select distinct signup_date 
      from facts 
     ) f2 
    ) c on f.record_type = c.record_type and f.signup_date = c.signup_date 
group by 2, 3 
order by 2, 3 
; 
Sum | test_week | user_type 
-----+------------+----------- 
    4 | 2013-09-02 | x 
    5 | 2013-09-02 | y 
    0 | 2013-09-09 | x 
    10 | 2013-09-09 | y 
    2 | 2013-09-16 | x 
    1 | 2013-09-16 | y 
+0

谢谢!您的答案通过使用具有内部交叉连接的正确外部连接作为“虚拟”维度表来强制执行所有日期* record_type行组合,而不管源数据如何。我接受你的答案作为正确的答案b/c Gordon Linoff的SQL稍微难以使用左外连接读取,其中维表是主表,事实表是连接表。我认为你的系统具有正确的外连接更容易理解。我认为这两个答案都是相当的。 –

+0

@Steve是的,它们是相同的。在我的答案中还有一个细节是使用'date_trunc',它比连接'extract's更容易使用。它也仅适用于最终设置。 –

+0

是的,我注意到这些改进。他们是你的解决方案比我开发的解决方案更好的一个很好的理由。通过将总和放在最外面的查询上,可以避免我的内部交叉连接的丑陋(下面的答案)。好的SQL,再次感谢你! –

1

要解决此问题,请创建所有record_type的所有组合和所有测试周的列表。这些组合的左侧连接到实际的事实表。这将给所有的记录,所以你应该能够得到在没有数据的行:

select coalesce(sum(f.data), 0) as data, rt.record_type, w.test_week 
from (select distinct record_type from facts) rt cross join 
    (select distinct to_timestamp(EXTRACT(YEAR FROM signup_date) || ' ' || EXTRACT(WEEK FROM signup_date),'IYYY IW')::date as test_week 
     from facts 
    ) w left outer join 
    facts f 
    on f.record_type = rt.record_type and 
     w.test_week = to_timestamp(EXTRACT(YEAR FROM f.signup_date) || ' ' || EXTRACT(WEEK FROM f.signup_date),'IYYY IW')::date 
group by rt.record_type, w.test_week 
order by w.test_week, rt.record_type; 
0

一些SQL自己玩耍后,我有另一种解决方案也可以工作。我敢肯定,这个查询不如Clodoaldo Neto或Gordon Linoff的性能,但我想我会分享另一种解决此问题的SQL形式:

select coalesce(data, 0), rt as record_type, weeks 
    from 
     (select sum(data) as data, record_type, to_timestamp(EXTRACT(YEAR FROM signup_date) || ' ' || EXTRACT(WEEK FROM signup_date),'IYYY IW')::date as test_week 
     from facts 
     group by record_type, test_week 
     order by record_type, test_week) as facts 
    right join 
     (select distinct to_timestamp(EXTRACT(YEAR FROM signup_date) || ' ' || EXTRACT(WEEK FROM signup_date),'IYYY IW')::date as weeks, rts.rt as rt 
     from facts 
     cross join (select distinct record_type from facts) as rts (rt) 
     cross join (select distinct alt from facts) as alts (at)) as dates 
    on dates.weeks = facts.test_week 
    and dates.rt = facts.record_type 
相关问题