最后一小时计数和最后一次收到

时间:2014-10-02 20:32:24

标签: sql postgresql

有两个表A和B,其中包含以下列和示例数据

A

Id    Code      Name       Active
---------------------------------
1     A1        Apple       t
2     B2        Banana      t
3     C1        Cherry      f
4     D2        Date        t

B

Aid             Received     
-----------------------------------
1        2014-10-02 10:24:55.095714
2        2014-10-02 10:54:53.226128
3        2014-10-02 15:39:59.683531
1        2014-10-02 15:39:59.862021
4        2014-10-02 15:42:19.923144
4        2014-10-02 15:49:29.964731
1        2014-10-02 15:53:27.586373

Aid是表 A

中的外键

我需要显示最后一小时收到的所有姓名,号码和最后收到的时间

样本数据的预期输出如下

Name     Count          LastReceived     
-------------------------------------------
Banana     0     2014-10-02 10:54:53.226128
Apple      2     2014-10-02 15:53:27.586373
Date       1     2014-10-02 15:49:29.964731

到目前为止我写的查询如下

SELECT 
  A.name,
  COUNT(B.Aid) AS Count,
  MAX(B.Received) AS LastReceived
FROM 
  A
FULL OUTER JOIN
  B
ON A.id = B.Aid 
WHERE B.Received > (NOW() - INTERVAL '1 hour') AND A.Active = TRUE --approx. 3pm to 4pm 10/2/2014
GROUP BY A.name
ORDER BY Count, A.name

我没有通过此查询获得预期的输出。我应该如何修改查询以获得预期的输出?

编辑

我需要将结果排序为零,计数首先按字母顺序显示,然后按字母顺序显示。我可以在一个查询中执行此操作吗?我知道添加ORDER BY Count, A.name将无效。

2 个答案:

答案 0 :(得分:3)

您遇到的麻烦是where子句排除了您要为上次收到的日期考虑的行。解决这个问题的一种方法是使用条件聚合:

select
  a.name,
  sum(case when b.Received > (now() - interval '1 hour') then 1 else 0 end) AS Count,
  max(b.Received) as LastReceived
from
  a
    left outer join
  b
    on a.id = b.aid 
where
  a.Active = true
group by
  a.name
order by
  case when sum(case when b.Received > (now() - interval '1 hour') then 1 else 0 end) = 0 then 0 else 1 end,
  a.name

通过拉出公用表表达式,可以更容易理解按工作顺序的方式:

with x as (
  select
    a.name,
    sum(case when b.Received > '2014-10-02 15:00:00' then 1 else 0 end) AS Count,
    max(b.Received) as LastReceived
  from
    a
      left outer join
    b
      on a.id = b.aid 
  where
    a.Active = true
  group by
    a.name
) select
  x.name,
  x.count,
  x.lastreceived
from
  x
order by
  case when x.Count = 0 then 0 else 1 end,
  x.name

Example SQLFiddle

答案 1 :(得分:0)

您的查询几乎正确,但您需要LEFT JOIN,因为表A是您的驾驶关系:

SELECT a.name,
       count(b.aid),
       max(b.received) AS LastReceived
  FROM a
  LEFT JOIN b ON a.id=b.aid AND b.received > now()-INTERVAL '1 hour'
 WHERE a.active
 GROUP BY a.name
 ORDER BY a.name;

此外,重要的是,您是否过滤掉WHERE子句中的结果,在您的情况下,跳过所有可能产生零计数的条目,或者将过滤器置于连接条件中(如上所述。)