我有两张桌子(事件和事件)。每个事件在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个事件中的空值吗?
谢谢,
答案 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 BY
和ORDER 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;
请注意,两个表之间只需要一个连接。