ROW_NUMBER(), PARTITION_BY, TOP 2 MAX If MAX 第一个和最后一个位置

Posted

技术标签:

【中文标题】ROW_NUMBER(), PARTITION_BY, TOP 2 MAX If MAX 第一个和最后一个位置【英文标题】:ROW_NUMBER(), PARTITION_BY, TOP 2 MAX If MAX 1st and Last Position 【发布时间】:2019-04-02 01:07:54 【问题描述】:

我有一个使用 ROW_NUMBER() 和 PARTITION BY 的查询以及基于日期列的订单。我想知道的是,如果第二个最大值位于位置 1 且当前最大值位于位置 250,是否可以限制这一点并仅返回匹配的 col1。

SELECT t1.col1, t1.col_date, t1.col_val, t1.rno FROM (
  SELECT col1, col_date, col_val, count(*), ROW_NUMBER() OVER (PARTITION BY col1 order by col_date ASC) as rno
FROM table_one
INNER JOIN
  table_two
ON
  table_one.id = table_one_id
WHERE col1 in (
  SELECT
    col1
  FROM
    table_one
  INNER JOIN table_two on table_one.id = table_one_id
  GROUP
    by table_one.id
  HAVING
    COUNT(*) >= 250
  ) 
  GROUP BY col1, col_date, col_val
) t1
WHERE t1.rno < 250
GROUP BY t1.col1, t1.col_date, t1.col_val, t1.rno
ORDER BY t1.col1, t1.col_date;

IE-

 col1 |           col_date           | col_val | rno
--------+----------------------------+--------+-----
 ABC   | 2018-07-18 15:27:35.394051  |   999   |   1
...
 ABC   | 2019-03-24 15:27:34.78493   |   1000  | 250

 XYZ   | 2018-07-18 15:27:35.394051  |   900   |   1
...
 XYZ   | 2019-03-24 15:27:34.78493   |   1001  | 250

如果 col_val 是 rno 1 处的第二个最大值并且 col_val 是 rno 250 处的最大值,则两者都会返回。

[更新]

为清楚起见:两个表。 table_one 是股票代码列表。 table_two 是历史价格列表。当前查询从 table_one 中选择交易品种,并连接来自 table_two 的历史价格,每个交易品种有 250 多条记录,rno 截断为 250,因此输出将如下所示。

symbol |     market_close_date      | close  | rno
--------+----------------------------+--------+-----
 FAKE   | 2018-07-18 15:27:35.394051 |  250.0 |   1
 FAKE   | 2018-07-19 15:27:35.391866 |  249.0 |   2
 FAKE   | 2018-07-20 15:27:35.389615 |  248.0 |   3
 FAKE   | 2018-07-21 15:27:35.38741  |  247.0 |   4
 FAKE   | 2018-07-22 15:27:35.3852   |  246.0 |   5
 FAKE   | 2018-07-23 15:27:35.383099 |  245.0 |   6
 FAKE   | 2018-07-24 15:27:35.380934 |  244.0 |   7
 FAKE   | 2018-07-25 15:27:35.378828 |  243.0 |   8
 FAKE   | 2018-07-26 15:27:35.376769 |  242.0 |   9
...
 FAKE   | 2019-03-24 15:27:34.78493  | 1000.0 | 250
 TEST   | 2018-07-18 15:27:35.396232 |  250.0 |   1
 ...
 TEST   | 2018-07-18 15:27:35.64352  |  50.0 | 250

如果 rno 1 > 2...249 并且 rno 1...249

【问题讨论】:

展示一些示例数据对您的问题有很大帮助。 在最外面的WHERE 子句中你能说WHERE t1.rno =1 OR t1.rno = 250 吗?你能稍微澄清一下第二个最大值的定义吗? J Spratt,请允许我澄清一下。我在问我是否可以做以下事情。 rno 1 处的 col_val 大于到 249 的所有值,并且 rno 250 是从 1 到 250 的最大值。因此,在第一个实例(第二个最大值)中,从 2 到 249 的所有值都将小于 999,而 250 处的值(1000) 将是最大值。任何大于 rno1 或 rno250 的 col_val 2...249 都不符合条件。 【参考方案1】:

我认为您可以在这里使用FILTERPARTITION BY 关键字。这不是复制和粘贴解决方案,但我认为这将为您指明正确的方向。我使用10 作为行限制,因为我不想提供虚假数据,但可以在此处应用250

此示例中的表test 将是您在两个表之间初始连接的结果。选择所有数据(或所需字段)并添加ROW_NUMBER

想法:

    最内层查询:选择所需数据并应用ROW_NUMBER 中间查询:将行限制应用于初始结果(其中行号为&lt;= x)。选择行限制x 下所有内容的最大值以及包括行限制x 在内的整个集合的最大值 最外层查询:确保行号1等于最大值(最高close where rno &lt; x)并确保行号x等于集合中的最大值(最高close where @ 987654337@)

SELECT *
FROM
(
    SELECT  *
            , MAX(close) FILTER(WHERE rno < 10) OVER(PARTITION BY symbol) as "max"
            , MAX(close) OVER(PARTITION BY symbol) AS second_max
    FROM 
    (
        SELECT *, ROW_NUMBER() OVER(PARTITION BY symbol ORDER BY close_date) AS rno
        FROM test
    ) t
    WHERE t.rno <= 10
) t2
WHERE (t2.rno = 1 AND t2.close = t2.max)
   OR (t2.rno = 10 AND t2.close = t2.second_max)
;

Here 是一个展示这个想法的 SQLFiddle。

【讨论】:

一行一行地进行制作、中断和调整,以接近我的意图。这对指导我非常有帮助。谢谢。

以上是关于ROW_NUMBER(), PARTITION_BY, TOP 2 MAX If MAX 第一个和最后一个位置的主要内容,如果未能解决你的问题,请参考以下文章

Informix 的 Row_number() 函数

MySQL 中的 ROW_NUMBER()

ROW_NUMBER() OVER函数的基本用法

在 sqlalchemy 中按 row_number 过滤

ROW_NUMBER() 替代

DB2 中的 ROW_NUMBER()