简体   繁体   English

Oracle SQL子选择以查找汇总值

[英]Oracle sql subselect to find aggregated values

I have a table that has product, date/time, and price. 我有一个包含产品,日期/时间和价格的表。 I split out the date/time to another column where I just split out the hour part of it. 我将日期/时间拆分到另一列,在其中我只拆分了小时部分。 I need to find high/low/open/close of the price value by hour. 我需要按小时查找价格值的高/低/开/关。 I can get the high/low easy enough by doing a subselect in the select portion where I max()/min() and join the data by product & hr. 通过在我的max()/ min()的选择部分进行子选择,然后按乘积和小时将数据连接起来,我可以轻松实现高/低。 I now need the open/close which will be the first record for each hour and the last record for each hour. 我现在需要打开/关闭,这将是每小时的第一条记录,以及每小时的最后一条记录。 high/low/open/close should all be the same for each record by hour. 高/低/打开/关闭应该按小时为每个记录都相同。

Example result. 结果示例。 notice how the high for all hour 7 records is 55 so that's what placed in all the hour 7 records, the low is 30 because it's the lowest of all hour 7 records, 50 is the open because the first price (sorted by date/time at 7:15) is 50. Close is the last price in the hour sorted by date/time which is 30. 请注意,所有小时7记录的最高价是55,所以这是所有小时7记录的最低价,最低是30,因为它是所有小时7记录中的最低价,50是开盘价,因为第一个价格(按日期/时间排序)在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

So again to recap, high/low is easy as I do subselects in the select part that query against the same table doing max/min, but not sure how to do the same thing for open/close to get the first and last records based on date/time field. 因此,再次回顾一下,高/低很容易,因为我在选择部分中对子表进行了子选择,以对同一张表进行最大/最小查询,但不确定如何对打开/关闭进行相同操作以获取第一条记录和最后一条记录在日期/时间字段上。

Add this as a subquery to get the Open, replacing the product key and hour appropriately: 将其添加为子查询以获取Open,并相应地替换产品密钥和小时:

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

Add this as a subquery to get the Close, replacing the product key and hour appropriately: 将其添加为子查询以获取关闭,并相应地替换产品密钥和小时:

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

The trick here is setting ordering the result correctly and taking only the first result using rownum = 1 . 这里的技巧是设置结果的正确排序,并使用rownum = 1仅获取第一个结果。


Another option: 另外一个选项:

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>'
    ) 

A drawback of this route is that these statements are not guaranteed to return a single row. 该路由的缺点是不能保证这些语句返回单行。 Meaning if for a given product there two entries for the same hour, with the same Date value that are the min/max it will return 2 rows causing an exception when used as a sub-query. 这意味着如果给定产品在同一小时内有两个条目,且具有相同的日期值(即最小/最大),则它将返回2行,用作子查询时会导致异常。

Although that may be a good thing, instead of it arbitrarily picking a row, you will know there is a particular problem and can possibly update the query to make a more intelligent decision. 尽管那可能是一件好事,但您会知道存在一个特定的问题,并且可以更新查询以做出更明智的决策,而不是随意选择一行。

I would use ranking functions for this: 我将为此使用排名函数:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM