如何选择3个最大结果,但排除空值

时间:2016-08-02 21:00:40

标签: sql postgresql null

我有两张桌子(事件和事件)。每个事件在occurences表中有0个或更多条目。我想总结出现次数并获得前5个结果。只要所有事件都在occurrence表中有条目,我就有一些适用于此的SQL。如果事件表中没有条目的事件,则最终位于列表的顶部。

实现这一目标的正确SQL是什么?

表定义

  

事件
    id - 整数
    EventName - varchar(200)

     

出现次数
     id - int
     Event_ID - int
     时间戳 - 日期时间
     TimesOccurred - int

对于ID为1的事件(事件名称 - '上下文切换'),我可能在Occurrences表中有相应的行:

  

ID:1,Event_ID:1,时间戳:' 2016-08-02 05:52:00',TimesOccurred:50
  ID:8,Event_ID:1,时间戳:' 2016-08-02 07:11:00',TimesOccurred:20

我会在Occurrences表中有相应条目的其他事件,以及一些没有相应条目的事件(尚未发生,偶发事件等)

以下SQL将通过对具有相同ID的所有事件的TimesOccurred列求和来向我提供前5个事件。

SELECT Events.Name, t.total as Total FROM Events
LEFT JOIN 
(SELECT Occurrences.Event_ID, sum(Events.TimesOccurred) as total FROM Occurrences 
INNER JOIN Events on Events.id = Occurrents.Event_ID GROUP BY Events.id) t
on Events.id = t.Event_ID ORDER BY t.total DESC limit 5;

这可能会给我

  

Segfault 20
  上下文切换10

但是,如果我有一个名为OOM且ID为3的事件,并且Occurrences表中没有Event_ID为3的条目,那么我将得到以下内容

  

OOM
  Segfault 20
  上下文切换10

我尝试将查询更改为:

SELECT Events.Name, COALESCE(t.total, 0) as Total FROM Events
LEFT JOIN 
(SELECT Occurrences.Event_ID, sum(Events.TimesOccurred) as total FROM Occurrences 
INNER JOIN Events on Events.id = Occurrents.Event_ID GROUP BY Events.id) t
on Events.id = t.Event_ID ORDER BY t.total DESC limit 5;

然后返回

  

OOM 0
  Segfault 20
  上下文切换10

我认为这是因为我在t.total上排序,而COALESC没有将t.total设置为0,结果为null,而是返回0,结果为null。

知道如何排除前5个事件中的空值吗?

谢谢,

2 个答案:

答案 0 :(得分:3)

在Postgres中,您可以通过在排序方向之后添加ORDER BY来定义NULLS [LAST/FIRST]子句中空值的处理。

此外,您只需要访问两个表 - 不需要额外的派生表。

SELECT Events.Name, sum(Occurences.TimesOccurred) as Total 
FROM Events
LEFT JOIN Occurrences ON Events.id = Occurrences.Event_ID
GROUP BY 1
ORDER BY 2 DESC NULLS LAST
LIMIT 5

来自manual大胆强调我的 - 您在前5个查询中获得空值的原因):

  

默认情况下,null值排序为大于任何非null值;   也就是说, NULLS FIRST是DESC订单的默认值和NULLS LAST   否则。

如果在没有出现的情况下你仍然需要返回0(因为你可能总共有5个或更少的事件),那么添加COALESCE()就是你要走的路 - 你顺便做了。

我还在GROUP BYORDER BY子句中的列中添加了整数别名。

您还可以为表名创建别名以缩短代码。

答案 1 :(得分:1)

我建议您简化查询并使用NULLS LAST

  SELECT e.Name, sum(o.TimesOccurred) as total
  FROM Events e LEFT JOIN
       Occurrences o I
       ON Events.id = o.Event_ID
  GROUP BY e.Name
  ORDER BY total DESC NULLS LAST
  LIMIT 5;

请注意,两个表之间只需要一个连接。