Oracle sql subselect 查找聚合值

Posted

技术标签:

【中文标题】Oracle sql subselect 查找聚合值【英文标题】:Oracle sql subselect to find aggregated values 【发布时间】:2012-11-12 20:15:47 【问题描述】:

我有一张包含产品、日期/时间和价格的表格。我将日期/时间拆分到另一列,我刚刚拆分了小时部分。我需要按小时查找价格值的高点/低点/开盘价/收盘价。我可以通过在 max()/min() 的选择部分中进行子选择并按产品和小时加入数据来轻松获得高/低。我现在需要打开/关闭,这将是每小时的第一条记录和每小时的最后一条记录。每小时的每条记录的高/低/开/关都应该相同。

示例结果。请注意所有 7 小时记录的最高价是 55,这就是所有 7 小时记录中的最高价,最低价是 30,因为它是所有 7 小时记录中的最低价,50 是开盘价,因为第一个价格(按日期/时间排序at 7:15) 是 50。收盘价是按日期/时间排序的一小时内的最后一个价格,即 30。

Product, Date,            Hour, Price, High, Low, Open, Close
A,       11/12/2012 7:15, 7,    50,    55,   30,  50,   30
A,       11/12/2012 7:28, 7,    55,    55,   30,  50,   30
A,       11/12/2012 7:30, 7,    40,    55,   30,  50,   30
A,       11/12/2012 7:35, 7,    45,    55,   30,  50,   30
A,       11/12/2012 7:55, 7,    30,    55,   30,  50,   30

所以再次回顾一下,高/低很容易,因为我在选择部分中对同一个表进行最大/最小查询的子选择,但不知道如何为打开/关闭做同样的事情以获得第一个和基于日期/时间字段的最后记录。

【问题讨论】:

为定价表设置每小时更新 ;) 无论如何,请发布您目前拥有的任何代码。如果您传入表的记录按时间顺序排列。例如下午 1 点的第一条记录是开放的。然后在 60 分钟后,您可以检查哪条记录(即您的收盘价)。一般来说,每个价格变动都附有一个时间。那是怎么回事? :) 所以这是历史数据,不是实时的,所以我有所有的时间。我通过 sql 询问如何获得给定小时内所有记录的第一个和最后一个。例如我有: select price, (select max(price) from price_tbl j where i.product = j.product and i.hr = j.hr) high from price_tbl i 我对 min 做同样的事情,但是第一个如何和最后一个记录。如果 oracle 有一个 first() 和 last() 这会很容易:) 【参考方案1】:

将此添加为子查询以获取 Open,并适当地替换产品密钥和小时:

SELECT * FROM (
  Select Open
  FROM <table name>
  WHERE product = '<product key>' 
    AND hour='<the hour>'
  ORDER BY Date
) WHERE rownum = 1

将此添加为子查询以获取关闭,适当地替换产品密钥和小时:

SELECT * FROM (
  Select Close
  FROM <table name>
  WHERE product = '<product key>' 
    AND hour='<the hour>' 
  ORDER BY Date desc
) WHERE rownum = 1

这里的技巧是正确设置结果排序并使用rownum = 1 仅获取第一个结果。


另一种选择:

SELECT Open
FROM <table name>
WHERE product = '<product key>' 
  AND hour='<the hour>' 
  AND Date = (
    SELECT min(Date) 
    FROM <table name> 
    WHERE product = '<product key>' 
    AND hour='<the hour>'
    ) 

SELECT Close
FROM <table name>
WHERE product = '<product key>' 
  AND hour='<the hour>' 
  AND Date = (
    SELECT max(Date) 
    FROM <table name> 
    WHERE product = '<product key>' 
    AND hour='<the hour>'
    ) 

这种方法的一个缺点是这些语句不能保证返回单行。这意味着如果对于给定的产品,在同一小时有两个条目,具有相同的日期值,即最小值/最大值,它将返回 2 行,在用作子查询时导致异常。

虽然这可能是一件好事,但与其随意选择一行,您会知道存在特定问题,并且可能会更新查询以做出更明智的决定。

【讨论】:

请参阅我认为 rownum 是在 order by 子句之前计算的,如果它在同一个查询中并且此时不能保证它是任何特定的顺序。所以这意味着我必须对它进行子查询,这不起作用,因为在 select 语句中你不能有 2 个嵌套并使用最外面的表的连接。这就是问题所在。 我很确定订单将首先完成。寻找参考。与此同时,您是否尝试过运行它? 你是对的,它的顺序是在rownum之后完成的,你必须把它包装起来。 ORACLE SQL ROWNUM execution order。唯一的其他选项我仍然仍然有 2 个订阅,基本上在日期列上使用 min 和 max。如果你愿意,我可以发布它,但我认为它比上面的更糟糕。【参考方案2】:

我会为此使用排名函数:

select product, datestr, hour,
       max(case when seqnum_open = 1 then price end) as Open,
       max(case when seqnum_close = 1 then price end) as Close,
       max(price) as High,
       min(price) as Low
from (select t.*,
             row_number() over (partition by product, datestr, hour order by date) as seqnum_open,
             row_number() over (partition by product, datestr, hour order by date desc) as seqnum_close
      from (select t.*,
                   to_char(date, 'YYYY-MM-DD') as datestr
            from t
           ) t
     ) t
group by product, datestr, hour

【讨论】:

以上是关于Oracle sql subselect 查找聚合值的主要内容,如果未能解决你的问题,请参考以下文章

为啥 subselect 会使 SQL 请求变慢?

Oracle SQL:如何从组中查找记录

查找 SQL 聚合函数调用中的百分比可能没有嵌套聚合或窗口函数

Oracle_SQL 分组与聚合函数

如果之前在组中没有看到值,则聚合值 - SQL / ORACLE

查询分组中的 Oracle SQL 条件聚合函数