【问题标题】:Select the X newest rows for each unique value of a column为列的每个唯一值选择 X 个最新行
【发布时间】:2014-02-10 14:24:08
【问题描述】:

我有一张桌子,上面有以下内容:

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

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

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

编辑:我正在使用 opennms 和事件表 (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;

【问题讨论】:

  • 您能否将您的表结构发布为CREATE TABLE ...、数据示例和您现有的查询?
  • @IgorRomanchenko 用这些细节编辑了帖子

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


【解决方案1】:

如果你想要固定数量的“最新”条目,你需要使用窗口函数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 值的行排序到最后。 (您的问题更新排除了这一点,因此不需要该子句。)

【讨论】:

    【解决方案2】:

    我想这很昂贵,可能有更好的方法,但是这样的方法对你有用吗?

    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 中有一个模型。

    【讨论】:

      【解决方案3】:
      SELECT * FROM
      ( SELECT 
          eventid, 
          itemid, 
          message, 
          rank() OVER (PARTITION BY itemid ORDER BY eventid DESC) AS rnk
        FROM your_table)
      WHERE rnk <= 20
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多