Oracle sql subselect用于查找聚合值

时间:2012-11-12 20:15:48

标签: sql oracle

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

示例结果。注意所有小时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

再次回顾一下,高/低很容易,因为我在选择部分中进行子选择,查询同一个表执行最大/最小值,但不确定如何执行相同的操作来打开/关闭以获取第一个和基于日期/时间字段的最后记录。

2 个答案:

答案 0 :(得分:0)

将其添加为子查询以获取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>'
    ) 

此路由的缺点是不保证这些语句返回单行。意味着对于给定产品,同一小时有两个条目,具有相同的Date值,即min / max,它将返回2行,当用作子查询时会导致异常。

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

答案 1 :(得分:0)

我会使用排名函数:

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