为列的每个唯一值选择X个最新行

时间:2014-02-10 14:24:09

标签: sql postgresql greatest-n-per-group window-functions

我有一张包含以下内容的表格:

  • eventid - >主键,数字越大意味着更新
  • itemid - >项目表的外键
  • 消息 - >事件消息

每个itemid将有100/1000个事件。我需要的是从表中获取每个独特的itemid值的X最新事件。在这种情况下,X是20,“最新”是最高的偶数。

我以前做的是获取整个表格,并且每个itemid只保留最新的20个。这非常缓慢且效率低下。

编辑:我正在使用opennms和Events表(OpenNMS create.sql):( itemid == nodeID)

create table events (
eventID integer not null,
eventUei    varchar(256) not null,
nodeID  integer,
eventTime   timestamp with time zone not null,
eventHost   varchar(256),
eventSource varchar(128) not null,
ipAddr  varchar(16),
eventDpName varchar(12) not null,
eventSnmphost   varchar(256),
serviceID   integer,
eventSnmp   varchar(256),
eventParms  text,
eventCreateTime timestamp with time zone not null,
eventDescr  varchar(4000),
eventLoggroup   varchar(32),
eventLogmsg varchar(256),
eventSeverity   integer not null,
eventPathOutage varchar(1024),
eventCorrelation    varchar(1024),
eventSuppressedCount    integer,
eventOperInstruct   varchar(1024),
eventAutoAction varchar(256),
eventOperAction varchar(256),
eventOperActionMenuText varchar(64),
eventNotification   varchar(128),
eventTticket    varchar(128),
eventTticketState   integer,
eventForward    varchar(256),
eventMouseOverText  varchar(64),
eventLog    char(1) not null,
eventDisplay    char(1) not null,
eventAckUser    varchar(256),
eventAckTime    timestamp with time zone,
alarmID integer,
constraint pk_eventID primary key (eventID)
); 

我的查询非常简单:

SELECT eventid, nodeid, eventseverity, eventtime, eventlogmsg
FROM events
WHERE nodeid IS NOT NULL;

3 个答案:

答案 0 :(得分:2)

如果您需要固定数量的“最新”条目,则需要使用窗口函数row_number()(不是rank())。但是,如果eventid恰好是唯一的(itemid},那么唯一(轻微)的差异就是性能。 (您的问题更新确认了这一点。)

此外,您需要一个子查询,因为在窗口函数之前应用了WHERE条件:

SELECT itemid, eventid, nodeid, eventseverity, eventtime, eventlogmsg
FROM  (
   SELECT itemid, eventid, nodeid, eventseverity, eventtime, eventlogmsg
         ,row_number() OVER (PARTITION BY itemid
                             ORDER BY eventid DESC NULLS LAST) AS rn
   FROM   events
   WHERE  nodeid IS NOT NULL
   ) sub
WHERE  rn <= 20
ORDER  BY 1, 2 DESC NULLS LAST;

NULLS LAST子句仅在eventid可以为NULL时才相关,在这种情况下,这会将具有NULL值的行排序到末尾。 (你的问题更新规则,因此不需要该条款。)

答案 1 :(得分:1)

我认为这是相当昂贵的,可能有更好的方法,但这样的事情对你有用吗?

select itemid, message 
from events e
where eventid in
  (select eventid from events f
   where e.itemid=f.itemid
   order by eventid desc
   limit 20)
order by itemid

子查询查找特定itemid的最新项目,外部查询为所有项目执行该项目。 sqlfiddle中有一个模型。

答案 2 :(得分:0)

SELECT * FROM
( SELECT 
    eventid, 
    itemid, 
    message, 
    rank() OVER (PARTITION BY itemid ORDER BY eventid DESC) AS rnk
  FROM your_table)
WHERE rnk <= 20