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】:
我认为您可以在这里使用FILTER
和PARTITION BY
关键字。这不是复制和粘贴解决方案,但我认为这将为您指明正确的方向。我使用10
作为行限制,因为我不想提供虚假数据,但可以在此处应用250
。
此示例中的表test
将是您在两个表之间初始连接的结果。选择所有数据(或所需字段)并添加ROW_NUMBER
想法:
-
最内层查询:选择所需数据并应用
ROW_NUMBER
中间查询:将行限制应用于初始结果(其中行号为<= x
)。选择行限制x
下所有内容的最大值以及包括行限制x
在内的整个集合的最大值
最外层查询:确保行号1
等于最大值(最高close
where rno < 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 第一个和最后一个位置的主要内容,如果未能解决你的问题,请参考以下文章