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. 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.
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:
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
.
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.
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.