如何使此CTE查询打印0值的行?

时间:2012-10-06 13:39:52

标签: sql postgresql join aggregate-functions common-table-expression

我有一个基于CTE的查询,我使用连接向其传递大约2600个4元组纬度/经度值 - 这些纬度经度4元组已被ID标记并保存在称为坐标的第二个表中。这些左上角和右下角的纬度/经度值被传递到CTE,以显示在给定的两个时间戳内在这些坐标内进行的请求量(每小时).-我能够在时间戳内获得每天的总请求数给定,即每个指定日期的用户请求总数。 (例如,用户选择查看每周三或周三和周四等 - 在2012年1月1日至31日之间的小时11:55和22:04之间,我通过的每个纬度/经度4元组。)但我无法获得行如果结果中zcount为0,我只获得zcount>的行0.我的查询如下:( Erwin Brandstetter的注释,如果他看到这个,我检查了聊天室关于我之前问题的讨论,并将coordinates值设置为NOT NULL,因为你说坐标可以是null的设计,但我仍然有某种相同的问题。 - 虽然我可能已经得到了你的意思错误,因为那时发烧的情况很糟糕 -

WITH v AS (
   SELECT '2012-1-1 11:55:11'::timestamp AS _from -- provide times once
         ,'2012-1-31 22:02:21'::timestamp AS _to
   )
, q AS (
   SELECT c.coordinates_id
        , date_trunc('hour', t.calltime) AS stamp
        , count(*) AS zcount
   FROM   v
   JOIN   mytable t ON  t.calltime BETWEEN v._from AND v._to
                   AND (t.calltime::time >= v._from::time AND
                        t.calltime::time <= v._to::time) AND 
(extract(DOW from t.calltime) = 3)
   JOIN   coordinates c ON (t.lat, t.lon) 
                   BETWEEN (c.bottomrightlat, c.topleftlon)
                       AND (c.topleftlat, c.bottomrightlon)
   GROUP BY c.coordinates_id, date_trunc('hour', t.calltime)
   )
, cal AS (
   SELECT generate_series('2012-1-1 11:00:00'::timestamp
                        , '2012-1-31 23:00:00'::timestamp
                        , '1 hour'::interval) AS stamp)
SELECT q.coordinates_id, cal.stamp::date, sum(q.zcount) AS zcount
FROM   v, cal
LEFT   JOIN q USING (stamp)
WHERE  extract(hour from cal.stamp) BETWEEN extract(hour from v._from)
                                        AND extract(hour from v._to)
AND    extract(DOW from cal.stamp) = 3 
AND    cal.stamp >= v._from
AND    cal.stamp <= v._to
GROUP  BY 1,2
ORDER  BY 1,2;

我执行此查询时得到的输出基本上是这样的(通常我有大约10354行返回,排除0 zcount的行,为了相似性只提供两个坐标):

coordinates_id  | stamp      | zcount
1               ;"2012-01-04";      2
1               ;"2012-01-11";      3
1               ;"2012-01-18";      2
2               ;"2012-01-04";      2
2               ;"2012-01-11";      3
2               ;"2012-01-18";      2

但是,它应该是这样的,其中zcount 0的所有行也应该与具有非零zcounts -E.g的行一起打印出来。 1月25日zcount 0代表ID为1和2的两个坐标也应该在这个小部分的例子中打印 - :

coordinates_id  | stamp      | zcount
1               ;"2012-01-04";      2
1               ;"2012-01-11";      3
1               ;"2012-01-18";      2
1               ;"2012-01-25";      0
2               ;"2012-01-04";      2
2               ;"2012-01-11";      3
2               ;"2012-01-18";      2
2               ;"2012-01-25";      0

更新版本,zcount值大于实际值。 - 还有0 zcount的行仍未显示 -

WITH v AS (
   SELECT '2012-1-1 11:55:11'::timestamp AS _from -- provide times once
         ,'2012-1-31 22:02:21'::timestamp AS _to
   )
, q AS (
   SELECT c.coordinates_id
        , date_trunc('hour', t.calltime) AS stamp
        , count(*) AS zcount
   FROM   v
   JOIN   mytable t ON  t.calltime BETWEEN v._from AND v._to
                   AND (t.calltime::time >= v._from::time AND
                        t.calltime::time <= v._to::time) AND 
(extract(DOW from t.calltime) = 3)
   JOIN   coordinates c ON (t.lat, t.lon) 
                   BETWEEN (c.bottomrightlat, c.topleftlon)
                       AND (c.topleftlat, c.bottomrightlon)
   GROUP BY c.coordinates_id, date_trunc('hour', t.calltime)
   )
, cal AS (
   SELECT generate_series('2012-1-1 11:00:00'::timestamp
                        , '2012-1-31 23:00:00'::timestamp
                        , '1 hour'::interval) AS stamp)
, coordst AS ( 
   SELECT coordinates_id FROM coordinates)
SELECT q.coordinates_id, cal.stamp::date, COALESCE(sum(q.zcount),0) AS zcount
FROM   v, coordst, cal
LEFT   JOIN q USING (stamp)
WHERE  extract(hour from cal.stamp) BETWEEN extract(hour from v._from)
                                        AND extract(hour from v._to)
AND    extract(DOW from cal.stamp) = 3 
AND    cal.stamp >= v._from
AND    cal.stamp <= v._to
GROUP  BY 1,2
ORDER  BY 1,2;

1 个答案:

答案 0 :(得分:1)

您需要一个不同的coordinates_id列表才能执行正确的CROSS JOIN。 1.在WITH中添加另一个条目。 2.将其添加到您的JOIN(FROM v,cal,coords)。 3.你的zcount将显示NULL,因此COALESCE。

WITH v AS (
   SELECT '2012-1-1 11:55:11'::timestamp AS _from -- provide times once
         ,'2012-1-31 22:02:21'::timestamp AS _to
   )
, q AS (
   SELECT c.coordinates_id
        , date_trunc('hour', t.calltime) AS stamp
        , count(*) AS zcount
   FROM   v
   JOIN   mytable t ON  t.calltime BETWEEN v._from AND v._to
                   AND (t.calltime::time >= v._from::time AND
                        t.calltime::time <= v._to::time) AND 
(extract(DOW from t.calltime) = 3)
   JOIN   coordinates c ON (t.lat, t.lon) 
                   BETWEEN (c.bottomrightlat, c.topleftlon)
                       AND (c.topleftlat, c.bottomrightlon)
   GROUP BY c.coordinates_id, date_trunc('hour', t.calltime)
   )
, cal AS (
   SELECT generate_series('2012-1-1 11:00:00'::timestamp
                        , '2012-1-31 23:00:00'::timestamp
                        , '1 hour'::interval) AS stamp)
, coordst AS ( 
   SELECT DISTINCT coordinates_id FROM coordinates)
SELECT coordst.coordinates_id, cal.stamp::date, COALESCE(sum(q.zcount),0) AS zcount
FROM   v CROSS JOIN coordst CROSS JOIN cal
LEFT   JOIN q USING q.stamp = cal.stamp AND coordst.coordinates_id = q.coordinates_id
WHERE  extract(hour from cal.stamp) BETWEEN extract(hour from v._from)
                                        AND extract(hour from v._to)
AND    extract(DOW from cal.stamp) = 3 
AND    cal.stamp >= v._from
AND    cal.stamp <= v._to
GROUP  BY 1,2
ORDER  BY 1,2;