Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
ryan_hunter1200
Starting Member
3 Posts |
Posted - 2013-09-01 : 18:37:52
|
I want to take a bunch of stock trade prices and determine the first, last, high, and low prices.example:SELECT FIRST(Price), LAST(Price), MAX(Price), MIN(Price) FROM my_table_of_stock_trades WHERE Symbol='IBM' and TradeTime > '01/01/2013 12:00:00' AND TradeTime < '01/01/2013 12:15:00'Right now I am having to break this up into multiple queries to get the First, Last, and High/Low (SELECT TOP 1 Price WHERE ... ORDER BY TradeTime) and then flip it the other way for the last. It is not a big deal if I am querying this once or twice, but I want to query this thousands of times a minute and it is just too slow.Ideally, I would like to eventually do a GROUP BY Symbol and get data on every symbol for the time period:SELECT Symbol, FIRST(Price), LAST(Price), MAX(Price), MIN(Price) FROM my_table_of_stock_trades WHERE TradeTime > '01/01/2013 12:00:00' AND TradeTime < '01/01/2013 12:15:00' GROUP BY SymbolCan you please point me in the right direction to do this as quickly and efficiently as possible? There is no concept of FIRST/LAST in SQL Server 2008. I am prepared to install SQL 2012 if there is a better way to do this? If not, what do you think is the fastest way to do this with the GROUP BY? |
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2013-09-01 : 21:57:08
|
[code]; with cte as( select *, rn = row_number() over (partition by Symbol order by TradeTime), cnt = count(*) over (partition by Symbol) from my_table_of_stock_trades WHERE Symbol = 'IBM' and TradeTime > '01/01/2013 12:00:00' AND TradeTime < '01/01/2013 12:15:00')SELECT [FIRST] = max(case when rn = 1 then Price end), [LAST] = max(case when rn = cnt then Price end), [MIN] = min(Price), [MAX] = max(Price)FROM cte [/code] KH[spoiler]Time is always against us[/spoiler] |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2013-09-02 : 09:55:13
|
2012 has FIRST_VALUE, LAST_VALUE etc so you may use this tooSELECT FIRST_VALUE(Price) OVER (partition by Symbol order by TradeTime) AS [FIRST], FIRST_VALUE(Price) OVER (partition by Symbol order by TradeTime ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS [LAST], min(Price) OVER (partition by Symbol) AS [MIN], max(Price) OVER (partition by Symbol) AS [MAX],....FROM my_table_of_stock_trades WHERE Symbol = 'IBM' and TradeTime > '01/01/2013 12:00:00' AND TradeTime < '01/01/2013 12:15:00' ------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/https://www.facebook.com/VmBlogs |
|
|
ryan_hunter1200
Starting Member
3 Posts |
Posted - 2013-09-02 : 12:32:16
|
khtan,thank you for the sql query. this works very well!I am trying to modify this for my GROUP BY exchange (so I group by symbol -- so i do this for every symbol in the table for the time period and not just 'IBM') but I cannot figure it out.SELECT Symbol, FIRST(Price), LAST(Price), MAX(Price), MIN(Price) FROM my_table_of_stock_trades WHERE TradeTime > '01/01/2013 12:00:00' AND TradeTime < '01/01/2013 12:15:00' GROUP BY Symbolhow do I use your approach for the group by?The Row_number() OVER (Partition ..) is something i saw when I googled this issue but i have to admit it is very confusing. with your working example, I find this is very helpful, so thank you very much.Can you kindly help with a GROUP BY solution? the only solution I have right now is to use a CURSOR over every DISTINCT(Symbol) during the time period and run your query. But this is much too expensive. If I can modify your query to return first/last/high/low for each distinct symbol during the time period that would be precise. thank you.quote: Originally posted by khtan
; with cte as( select *, rn = row_number() over (partition by Symbol order by TradeTime), cnt = count(*) over (partition by Symbol) from my_table_of_stock_trades WHERE Symbol = 'IBM' and TradeTime > '01/01/2013 12:00:00' AND TradeTime < '01/01/2013 12:15:00')SELECT [FIRST] = max(case when rn = 1 then Price end), [LAST] = max(case when rn = cnt then Price end), [MIN] = min(Price), [MAX] = max(Price)FROM cte
|
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2013-09-02 : 13:31:23
|
quote: Originally posted by ryan_hunter1200 khtan,thank you for the sql query. this works very well!I am trying to modify this for my GROUP BY exchange (so I group by symbol -- so i do this for every symbol in the table for the time period and not just 'IBM') but I cannot figure it out.SELECT Symbol, FIRST(Price), LAST(Price), MAX(Price), MIN(Price) FROM my_table_of_stock_trades WHERE TradeTime > '01/01/2013 12:00:00' AND TradeTime < '01/01/2013 12:15:00' GROUP BY Symbolhow do I use your approach for the group by?The Row_number() OVER (Partition ..) is something i saw when I googled this issue but i have to admit it is very confusing. with your working example, I find this is very helpful, so thank you very much.Can you kindly help with a GROUP BY solution? the only solution I have right now is to use a CURSOR over every DISTINCT(Symbol) during the time period and run your query. But this is much too expensive. If I can modify your query to return first/last/high/low for each distinct symbol during the time period that would be precise. thank you.quote: Originally posted by khtan
; with cte as( select *, rn = row_number() over (partition by Symbol order by TradeTime), cnt = count(*) over (partition by Symbol) from my_table_of_stock_trades WHERE Symbol = 'IBM' and TradeTime > '01/01/2013 12:00:00' AND TradeTime < '01/01/2013 12:15:00')SELECT [FIRST] = max(case when rn = 1 then Price end), [LAST] = max(case when rn = cnt then Price end), [MIN] = min(Price), [MAX] = max(Price)FROM cte
did you try my suggestion? is it any better?------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/https://www.facebook.com/VmBlogs |
|
|
ryan_hunter1200
Starting Member
3 Posts |
Posted - 2013-09-02 : 16:46:55
|
Hi Visakh16,I did not try your solution because I do not have SQL 2012 installed. I obviously would prefer to stick with sql2008 if I can (assuming 2012 has some performance benefit for this type of query).Do you think the other solution can be tweaked to work with a GROUP BY or do I need to upgrade to 2012 to do what I am looking for? |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2013-09-03 : 09:29:05
|
quote: Originally posted by ryan_hunter1200 Hi Visakh16,I did not try your solution because I do not have SQL 2012 installed. I obviously would prefer to stick with sql2008 if I can (assuming 2012 has some performance benefit for this type of query).Do you think the other solution can be tweaked to work with a GROUP BY or do I need to upgrade to 2012 to do what I am looking for?
I thought you're on sql 2012 as you posted this on SQL 2012 forumI missed the part in your post where you specified you're on SQL 2008.for your case this is enough i guess.; with cte as( select *, rn = row_number() over (partition by Symbol order by TradeTime), cnt = count(*) over (partition by Symbol) from my_table_of_stock_trades WHERE Symbol = 'IBM' and TradeTime > '01/01/2013 12:00:00' AND TradeTime < '01/01/2013 12:15:00')SELECT Symbol, [FIRST] = max(case when rn = 1 then Price end), [LAST] = max(case when rn = cnt then Price end), [MIN] = min(Price), [MAX] = max(Price)FROM cteGROUP BY Symbol ------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/https://www.facebook.com/VmBlogs |
|
|
|
|
|
|
|