如何强制查询只返回窗口的第一行?

时间:2019-06-26 11:42:15

标签: postgresql greatest-n-per-group

我有数据:

id | price | date
1  |    25 | 2019-01-01
2  |    35 | 2019-01-01
1  |    27 | 2019-02-01
2  |    37 | 2019-02-01

是否可以编写只返回窗口第一行的查询?类似于LIMIT 1,但对于窗口OVER( date )的查询?

我希望下一个结果:

id | price | date
1  |    25 | 2019-01-01
1  |    27 | 2019-02-01

或者如果第一行的行有NULL,则忽略整个窗口:

id | price | date
1  |  NULL | 2019-01-01
2  |    35 | 2019-01-01
1  |    27 | 2019-02-01
2  |    37 | 2019-02-01

结果:

1  |    27 | 2019-02-01

2 个答案:

答案 0 :(得分:1)

dateid对行进行排序,并且每个date仅占第一行。 然后删除价格为NULL的商品。

SELECT *
FROM (SELECT DISTINCT ON (date)
             id, price, date
      FROM mytable
      ORDER BY date, id
    ) AS q
WHERE price IS NOT NULL;

@Laurenz让我提供更多解释

select distinct on (<fldlist>) * from <table> order by <fldlist+>;

等于更复杂的查询:

select * from (
    select row_number() over (partition by <fldlist> order by <fldlist+>) as rn,*
    from <table>)
where rn = 1;

这里<fldlist>应该是<fldlist+>的开头(或相等)

答案 1 :(得分:0)

正如IRC上的Myon所说:

  

如果要在WHERE中使用窗口功能,则需要先将其放入子选择中

因此目标查询是:

select * from (
  select
    *
    agg_function( my_field ) OVER( PARTITION BY other_field ) as agg_field
  from sometable
) x
WHERE agg_field <condition>

就我而言,我有下一个查询:

SELECT * FROM (
    SELECT *, 
      FIRST_VALUE( p.price ) over( PARTITION BY crate.app_period ORDER BY st.DEPTH ) AS first_price,
      ROW_NUMBER() over( PARTITION BY crate.app_period ORDER BY st.DEPTH ) AS row_number
    FROM st 
    LEFT JOIN price p ON <COND>
    LEFT JOIN currency_rate crate ON <COND>
) p
WHERE p.row_number = 1 AND p.first_price IS NOT null

在这里,我仅从组中选择第一行,其中price IS NOT NULL