为相关记录组

时间:2016-03-28 15:56:02

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

我有一个表,可以容纳多个属性(例如外键)可逻辑分组的数据。数据在连续时间间隔内是连续的;即它是时间序列数据。我想要实现的是仅为每组组选择最新值。

以下是示例数据:

+-----------------------------------------+
| code | value | date       | relation_id |
+-----------------------------------------+
| A    | 1     | 01.01.2016 | 1           |
| A    | 2     | 02.01.2016 | 1           |
| A    | 3     | 03.01.2016 | 1           |
| A    | 4     | 01.01.2016 | 2           |
| A    | 5     | 02.01.2016 | 2           |
| A    | 6     | 03.01.2016 | 2           |
| B    | 1     | 01.01.2016 | 1           |
| B    | 2     | 02.01.2016 | 1           |
| B    | 3     | 03.01.2016 | 1           |
| B    | 4     | 01.01.2016 | 2           |
| B    | 5     | 02.01.2016 | 2           |
| B    | 6     | 03.01.2016 | 2           |
+-----------------------------------------+

以下是所需输出的示例:

+-----------------------------------------+
| code | value | date       | relation_id |
+-----------------------------------------+
| A    | 3     | 03.01.2016 | 1           |
| A    | 6     | 03.01.2016 | 2           |
| B    | 3     | 03.01.2016 | 1           |
| B    | 6     | 03.01.2016 | 2           |
+-----------------------------------------+

为了正确看待这一点 - 对于每个相关对象,我想选择具有最新日期的每个代码。

这是我带来的选择。我使用了ROW_NUMBER OVER (PARTITION BY...)方法:

SELECT indicators.code, indicators.dimension, indicators.unit, x.value, x.date, x.ticker, x.name
FROM (
  SELECT
  ROW_NUMBER() OVER (PARTITION BY indicator_id ORDER BY date DESC) AS r,
  t.indicator_id, t.value, t.date, t.company_id, companies.sic_id,
  companies.ticker, companies.name
  FROM fundamentals t
  INNER JOIN companies on companies.id = t.company_id
  WHERE companies.sic_id = 89
) x
INNER JOIN indicators on indicators.id = x.indicator_id
WHERE x.r <= (SELECT count(*) FROM companies where sic_id = 89)

它有效,但问题是它很慢;当使用大约5%的生产数据时,相当于大约300万fundamentals个记录,这个选择大约需要10秒才能完成。我的猜测是由于子选择首先选择大量记录而发生的。

有没有什么方法可以加快这个查询速度,还是我正朝着错误的方向努力尝试按照我的方式去做?

4 个答案:

答案 0 :(得分:1)

Postgres为此目的提供方便的distinct on

select distinct on (relation_id, code) t.*
from t
order by relation_id, code, date desc;

答案 1 :(得分:0)

因此,您的查询使用的列名不同于您的示例数据,因此很难说,但看起来您只想按日期除外?假设您没有多个最近的日期,这样的事情应该有效。基本上不要使用窗口功能,使用适当的组,你的引擎应该更好地优化查询。

SELECT mytable.code,
       mytable.value,
       mytable.date,
       mytable.relation_id
  FROM mytable
  JOIN (
        SELECT code, 
               max(date) as date, 
               relation_id
          FROM mytable
      GROUP BY code, relation_id
       ) Q1
    ON Q1.code = mytable.code
   AND Q1.date = mytable.date
   AND Q1.relation_id = mytable.relation_id

答案 2 :(得分:0)

其他选择:

SELECT DISTINCT Code,
Relation_ID,
FIRST_VALUE(Value) OVER (PARTITION BY Code, Relation_ID ORDER BY Date DESC) Value,
FIRST_VALUE(Date) OVER (PARTITION BY Code, Relation_ID ORDER BY Date DESC) Date
FROM mytable

这将返回您分区的最高值,以及您订购的任何内容。

答案 3 :(得分:0)

我相信我们可以尝试这样的事情

   SELECT CODE,Relation_ID,Date,MAX(value)value FROM mytable

    GROUP BY CODE,Relation_ID,Date