Getting a relative max for each value in a time series - sql

So I have a table called optiontracking with ConID/TimeLog/Ask/Bid table that looks like the following:
ConID
TimeLog
Ask
Bid
1
2020-06-03 10:18:43
0.52
0.55
1
2020-06-03 10:20:41
0.55
0.42
1
2020-06-03 10:23:54
0.60
0.58
1
2020-06-03 10:26:26
0.52
0.51
1
2020-06-03 10:28:57
0.51
0.50
1
2020-06-04 10:25:57
0.65
0.64
1
2020-06-04 10:26:57
0.80
0.79
2
2020-06-03 10:18:43
1.36
1.33
2
2020-06-03 10:20:41
1.38
1.35
2
2020-06-03 10:23:54
1.33
1.32
2
2020-06-03 10:26:26
1.25
1.22
2
2020-06-03 10:28:57
1.20
1.19
What I am trying to get is for each ConID/TimeLog/Ask entry in this table, chronologically next Max(Bid), TimeLog of Max(Bid) while matching the same day and ConID.
I expect to repeat this for Max Ask (but I figure that will need 1 subquery for each group).
So far I have been able to extract the max Bid chronologically after each TimeLog/ask in the dataset using the query below. I want to be able to pull the corresponding timestamp where the MAX(Bid) was retrieved from, but I am hitting a wall without using a second subquery (which I am trying to avoid due to data size).
Here is the query I am using to get the current max Bid per each Ask Chronologically:
SELECT DISTINCT OT.[ConID], OT.[TimeLog], OT.[Ask], MAX(MaxBid.[Bid]) as SellPrice from
(
SELECT * from algotrading.[optiontracking] WHERE YEAR([TimeLog]) <= 2020 and Month([TimeLog]) <= 6
) as OT
LEFT JOIN
(
SELECT [ConID], [Bid], [TimeLog], CONVERT(date, [TimeLog]) as CombDate from algotrading.[optiontracking] WHERE YEAR([TimeLog]) <= 2020 and Month([TimeLog]) <= 6
) as MaxBid
on OT.[ConID] = MaxBid.[ConID] and MaxBid.[CombDate] = CONVERT(date, OT.[TimeLog]) and DATEDIFF(second, OT.[TimeLog], MaxBid.[TimeLog]) > 0
GROUP BY OT.[ConID], OT.[TimeLog], OT.[Ask], CONVERT(date, OT.[TimeLog])
I know there is a way to get the corresponding [TimeLog] for each Max([Bid]), but I can't quite seem to figure it out. The Year/Month filtering on each query is because the dataset is too large and I'm trying to do testing first.
Here is what I would expect as an output from the table above (including the TimeLog for each max bid listed as SellPriceTime below):
ConID
TimeLog
Ask
SellPrice
SellPriceTime
1
2020-06-03 10:18:43
0.52
0.58
2020-06-03 10:23:54
1
2020-06-03 10:20:41
0.55
0.58
2020-06-03 10:23:54
1
2020-06-03 10:23:54
0.60
0.51
2020-06-03 10:26:26
1
2020-06-03 10:26:26
0.52
0.50
2020-06-03 10:23:54
1
2020-06-03 10:28:57
0.51
NULL
NULL
1
2020-06-04 10:25:57
0.65
0.79
2020-06-04 10:26:57
1
2020-06-04 10:26:57
0.80
NULL
NULL
2
2020-06-03 10:18:43
1.36
1.35
2020-06-03 10:20:41
2
2020-06-03 10:20:41
1.38
1.32
2020-06-03 10:23:54
2
2020-06-03 10:23:54
1.33
1.22
2020-06-03 10:26:26
2
2020-06-03 10:26:26
1.25
1.19
2020-06-03 10:28:57
2
2020-06-03 10:28:57
1.20
NULL
NULL

You can use an OUTER APPLY(SELECT TOP 1 ...) to select the max bid row for each ask.
An OUTER APPLY is like a left join to a subselect, where that subselect can apply WHERE conditions, ORDER BY and in this case TOP 1 to get your desired bid. It also allows you to select extract multiple values (Bid and TimeLog in this case), which is an advantage over a simple MAX() function.
I adjusted the "same day" logic to use a condition that checks for TimeLog < start of the next day. The overall date condition in the outer where clause has also been adjusted to be a simple compare. The original logic would have selected the first 6 months in each year 2020 and earlier.
For performance, make sure that you have an index on algotrading.optiontracking(ConID, TimeLog).
SELECT OT.ConID, OT.TimeLog, OT.Ask, MaxBid.SellPrice, MaxBid.SellPriceTime
FROM algotrading.optiontracking as OT
OUTER APPLY (
SELECT TOP 1 OT2.Bid AS SellPrice, OT2.TimeLog AS SellPriceTime
FROM algotrading.optiontracking OT2
WHERE OT2.ConID = OT.ConID
AND OT2.TimeLog > OT.TimeLog -- Later
AND OT2.TimeLog < DATEADD(day, 1, CONVERT(DATE, OT.TimeLog)) -- Before start of next day
ORDER BY OT2.Bid DESC -- Max Bid
) MaxBid
WHERE OT.TimeLog < '2020-07-01' -- Is this what was intended?
Results:
ConID
TimeLog
Ask
SellPrice
SellPriceTime
1
2020-06-03 10:18:43.000
0.52
0.58
2020-06-03 10:23:54.000
1
2020-06-03 10:20:41.000
0.55
0.58
2020-06-03 10:23:54.000
1
2020-06-03 10:23:54.000
0.60
0.51
2020-06-03 10:26:26.000
1
2020-06-03 10:26:26.000
0.52
0.50
2020-06-03 10:28:57.000
1
2020-06-03 10:28:57.000
0.51
null
null
1
2020-06-04 10:25:57.000
0.65
0.79
2020-06-04 10:26:57.000
1
2020-06-04 10:26:57.000
0.80
null
null
2
2020-06-03 10:18:43.000
1.36
1.35
2020-06-03 10:20:41.000
2
2020-06-03 10:20:41.000
1.38
1.32
2020-06-03 10:23:54.000
2
2020-06-03 10:23:54.000
1.33
1.22
2020-06-03 10:26:26.000
2
2020-06-03 10:26:26.000
1.25
1.19
2020-06-03 10:28:57.000
2
2020-06-03 10:28:57.000
1.20
null
null
See this db<>fiddle.

I don't fully understand what you're trying to do but this seems like a case for RANK() and PARTITION BY.
This is not a full answer but with
SELECT ConnId, TimeLog, LastPrice, Ask, Bid,
,Max(LastPrice) OVER (PARTITION BY ConnId) AS MaxLastPrice
,RANK() OVER (PARTITION BY ConnId ORDER BY Bid DESC) AS Rank
from ##Test
you'd get:
ConnId TimeLog LastPrice Ask Bid MaxLastPrice Rank
1 2020-06-04 10:26:57.0000000 10.48 0.80 0.79 10.48 1
1 2020-06-04 10:25:57.0000000 10.48 0.65 0.64 10.48 2
1 2020-06-03 10:23:54.0000000 10.45 0.60 0.58 10.48 3
1 2020-06-03 10:18:43.0000000 10.40 0.52 0.55 10.48 4
1 2020-06-03 10:26:26.0000000 10.42 0.52 0.51 10.48 5
1 2020-06-03 10:28:57.0000000 10.48 0.51 0.50 10.48 6
1 2020-06-03 10:20:41.0000000 10.30 0.55 0.42 10.48 7
2 2020-06-03 10:20:41.0000000 12.05 1.38 1.35 12.15 1
2 2020-06-03 10:18:43.0000000 12.10 1.36 1.33 12.15 2
2 2020-06-03 10:23:54.0000000 12.03 1.33 1.32 12.15 3
2 2020-06-03 10:26:26.0000000 12.13 1.25 1.22 12.15 4
2 2020-06-03 10:28:57.0000000 12.15 1.20 1.19 12.15 5
You can now order by whichever column you wish and pick the records with rank 1, for example.
Here's my test data:
CREATE TABLE ##test (
ConnId INT,
TimeLog DATETIME2,
LastPrice Numeric(5,2),
Ask Numeric(5,2),
Bid Numeric(5,2)
);
Insert into ##test values
(1, '2020-06-03 10:18:43 ', 10.40, 0.52, 0.55),
(1, '2020-06-03 10:20:41 ', 10.30, 0.55, 0.42),
(1, '2020-06-03 10:23:54 ', 10.45, 0.60, 0.58),
(1, '2020-06-03 10:26:26 ', 10.42, 0.52, 0.51),
(1, '2020-06-03 10:28:57 ', 10.48, 0.51, 0.50),
(1, '2020-06-04 10:25:57 ', 10.48, 0.65, 0.64),
(1, '2020-06-04 10:26:57 ', 10.48, 0.80, 0.79),
(2, '2020-06-03 10:18:43 ', 12.10, 1.36, 1.33),
(2, '2020-06-03 10:20:41 ', 12.05, 1.38, 1.35),
(2, '2020-06-03 10:23:54 ', 12.03, 1.33, 1.32),
(2, '2020-06-03 10:26:26 ', 12.13, 1.25, 1.22),
(2, '2020-06-03 10:28:57 ', 12.15, 1.20, 1.19)

I was able to solve this with the way I knew how, and it is faster than the current "better" solution. I would much rather use #T N's answer which is easier to understand and seems way more flexible, but this is query is considerably faster (3.5 mins vs. 8 mins).
For some extra information:
There is roughly 8 million records in this table for data from 6/1/2020 to 7/1/2020
There were no indexes created yet to help with any of these queries.
Any guidance as to why this is a significantly faster query than #T N's answer?
SELECT Prof.[ConID], Prof.[PurchaseTime], Prof.[Ask], Prof.[MaxPriceAfterPurchase], Prof.[MaxPriceAfterPurchase]-Prof.[Ask] as MaxProfit, MIN(SellTimeMax.TimeLog) as SellAtMaxTime
FROM
(
SELECT DISTINCT OT.[ConID], OT.[TimeLog] as [PurchaseTime], OT.[Ask], MAX(MaxBid.[Bid]) as MaxPriceAfterPurchase
from (
SELECT * from algotrading.[optiontracking] WHERE TimeLog < '2020-07-01'
) OT
LEFT JOIN (
SELECT [ConID], [Bid], [TimeLog], CONVERT(date, [TimeLog]) as CombDate from algotrading.[optiontracking] WHERE TimeLog < '2020-07-01'
) MaxBid
on OT.[ConID] = MaxBid.[ConID] and MaxBid.[CombDate] = CONVERT(date, OT.[TimeLog]) and DATEDIFF(second, OT.[TimeLog], MaxBid.[TimeLog]) > 0
GROUP BY OT.[ConID], OT.[TimeLog], OT.[Ask]
) Prof
LEFT JOIN
(
SELECT [ConID], [Bid], [TimeLog], CONVERT(date, [TimeLog]) as CombDate from algotrading.[optiontracking] WHERE TimeLog < '2020-07-01'
) SellTimeMax
ON SellTimeMax.[ConID] = Prof.ConID and SellTimeMax.CombDate = CONVERT(date, Prof.[PurchaseTime]) and SellTimeMax.[Bid] = Prof.[MaxPriceAfterPurchase] and DATEDIFF(second, Prof.[PurchaseTime], SellTimeMax.[TimeLog]) > 0
GROUP BY Prof.[ConID], Prof.[PurchaseTime], Prof.[Ask], Prof.[MaxPriceAfterPurchase], Prof.[MaxPriceAfterPurchase], Prof.[Ask]

Related

How to use NTILE function to create two groups for two columns where one is a nested NTILE of the other?

I have financial data that I want to categorise (using NTILE()) by two columns that contain percentage values (risk, debt_to_assets). My end goal is that I want to aggregate some other column (profit) by the two categories, but that's not related to my issue at hand. The data looks something like this:
profit
risk
debt_to_assets
7000
0.10
0.20
1000
0.40
0.70
3000
0.15
0.50
4000
0.30
0.30
2000
0.20
0.60
The issue I'm trying to solve is that I want the categories to be nested such that, in addition to the population distribution being uniform, the categories of the inner quantile are consistent across the categories of the outer quantile in terms of the range that defines the categories (i.e. I want the min and max value for the inner categories (x0, y0), (x1, y0), (x2, y0), ... to all be the same or as close as possible, where the x's are the outer category and the y's are the inner category).
Ideally if I were to aggregate the columns used for the NTILE() function (using 3 inner categories and 3 outer categories for example) I'd want a table that resembles the following:
risk_cat
dta_cat
min_risk
max_risk
min_dta
max_dta
count
1
1
0.00
0.33
0.00
0.33
100
1
2
0.00
0.33
0.34
0.67
100
1
3
0.00
0.33
0.68
1.00
100
2
1
0.34
0.67
0.00
0.33
100
2
2
0.34
0.67
0.34
0.67
100
2
3
0.34
0.67
0.68
1.00
100
3
1
0.68
1.00
0.00
0.33
100
3
2
0.68
1.00
0.34
0.67
100
3
3
0.68
1.00
0.68
1.00
100
These are the solutions I've tried but they only solve part of the issue, not the whole thing:
SELECT *,
NTILE(3) OVER (
ORDER BY risk
) AS risk_cat,
NTILE(3) OVER (
ORDER BY debt_to_assets
) AS dta_cat
FROM my_table
This would result in an aggregated table like this:
risk_cat
dta_cat
min_risk
max_risk
min_dta
max_dta
count
1
1
0.00
0.33
0.00
0.33
10
1
2
0.00
0.33
0.34
0.67
55
1
3
0.00
0.33
0.68
1.00
180
2
1
0.34
0.67
0.00
0.33
135
2
2
0.34
0.67
0.34
0.67
140
2
3
0.34
0.67
0.68
1.00
100
3
1
0.68
1.00
0.00
0.33
130
3
2
0.68
1.00
0.34
0.67
110
3
3
0.68
1.00
0.68
1.00
40
The problem is that the count across the two categories isn't uniform.
WITH outer_cat AS (
SELECT *,
NTILE(3) OVER (
ORDER BY risk
) AS risk_cat
FROM my_table
)
SELECT *,
NTILE(3) OVER(
PARTITION BY risk_cat
ORDER BY debt_to_assets
) AS dta_cat
FROM outer_cat
The aggregated table for this might resemble the following:
risk_cat
dta_cat
min_risk
max_risk
min_dta
max_dta
count
1
1
0.00
0.33
0.10
0.70
100
1
2
0.00
0.33
0.71
0.90
100
1
3
0.00
0.33
0.91
1.00
100
2
1
0.34
0.67
0.05
0.35
100
2
2
0.34
0.67
0.36
0.60
100
2
3
0.34
0.67
0.61
0.90
100
3
1
0.68
1.00
0.00
0.25
100
3
2
0.68
1.00
0.26
0.50
100
3
3
0.68
1.00
0.51
0.80
100
The problem this time is that the min and max values for the inner category vary to much across the outer category.
SELECT *,
NTILE(9) OVER(
ORDER BY risk, debt_to_assets
) AS dual_cat
FROM my_table
The aggregated table for this looks something like the following:
dual_cat
min_risk
max_risk
min_dta
max_dta
count
1
0.00
0.11
0.55
1.00
100
2
0.12
0.22
0.35
1.00
100
3
0.23
0.33
0.15
1.00
100
4
0.34
0.44
0.40
1.00
100
5
0.45
0.55
0.10
1.00
100
6
0.56
0.66
0.10
0.95
100
7
0.67
0.77
0.05
1.00
100
8
0.78
0.88
0.20
1.00
100
9
0.89
1.00
0.00
1.00
100
This was just a last attempt at a solution after the previous two didn't work. This attempt didn't capture any of the behaviour that I was looking for.
Is there a solution to my problem that I'm not seeing?

Based on CASE Pivot multiple rows into single row and multiple columns

Suppose there is a table
NAME Unit Date Time Type LOAD
A1Cu 2 2020-01-02 10:30 CU 0.1
A1Ta 5 2020-01-02 10:30 TA 0.3
A1Ch 6 2020-01-02 10:30 CH 0.2
B1Ch 4 2020-02-15 11:40 CH 0.52
B1Ta 8 2020-02-15 11:40 TA 0.83
C1Ta 5 2020-06-18 21:00 TA 0.11
Z1Ch 8 2020-08-08 15:30 CH 0.24
D1Ta 8 2020-06-18 01:30 TA 0.3
C1Cu 6 2020-06-18 21:00 CU 0.2
Then for same date and time merge multiple rows into single column by applying following logic
FOR NAME AND UNIT (Stop when one of the condition is met)
IF Type CU Then take NAME & UNIT
ELSE IF Type CH Then take NAME & UNIT
ELSE IF Type TA Then take NAME UNIT
For Load Put in respective column
The final Result should be like
NAME Unit Date Time TypeCULoad TypeCHLoad TypeTALoad
A1Cu 2 2020-01-02 10:30 0.1 0.2 0.3
B1Ch 4 2020-02-15 11:40 NULL 0.52 0.83
C1Cu 6 2020-06-18 21:00 0.2 NULL 0.11
Z1Ch 8 2020-08-08 15:30 NULL 0.24 Null
D1Ta 8 2020-06-18 01:30 NULL NULL 0.3
I have the partial solution but finding it hard to get Name and Load Logic right:
SELECT Date, Time,[TypeCULoad], [TypeCHLoad ],[TypeTALoad] FROM
(
SELECT
Date, Time, col, val FROM(
SELECT *, 'Type'+Type+'Load' as Col, Load as Val FROM TESTAIR
) t
) tt
PIVOT ( max(val) for Col in ([TypeCULoad], [TypeCULoad],[TypeCULoad]) ) AS pvt
Result
Date Time TypeCULoad TypeCHLoad TypeTALoad
2020-01-02 10:30 0.1 0.2 0.3
2020-02-15 11:40 NULL 0.52 0.83
2020-06-18 21:00 0.2 NULL 0.11
2020-08-08 15:30 NULL 0.24 Null
2020-06-18 01:30 NULL NULL 0.3
Need help on Name and Load?
First try to get the desired results before applying PIVOT
with cte as
(
SELECT name, unit, date, time, 'Type' + Type + 'Load' as Col, Load as Val, Type, LEFT(name, 2) xxx,
RANK() OVER(PARTITION BY LEFT(name, 2) ORDER BY CASE type WHEN 'CU' THEN 1 WHEN 'CH' THEN 2 ELSE 3 END) dd
FROM TESTAIR
)
select name, unit, Date, Time, [TypeCULoad], [TypeCHLoad ], [TypeTALoad] from
(
select b.name, b.unit, a.date, a.time, a.col, a.val
from cte a
join cte b on a.xxx = b.xxx and b.dd = 1
) f
PIVOT (max(val) for Col in ([TypeCULoad], [TypeCHLoad],[TypeTALoad]) ) AS pvt

Excel Oracle Query Group Function Not Allowed Here

I am making a Excel Oracle Query to achieve the following.
I have two tables, one table with orders and when the are invoiced and one table with exchange rates and from which date that rate is applicable:
Table JOBS:
ID INVOICE_DATE
1 05-05-2017
2 05-03-2017
3 04-28-2017
4 04-15-2017
5 04-01-2017
6 03-28-2017
7 03-15-2017
8 03-02-2017
9 02-27-2017
Table EXCHG:
CURR RATE DATE_FROM
USD 0.92 05-01-2017
GBP 1.21 05-01-2017
USD 0.95 04-04-2017
GBP 1.18 04-04-2017
USD 0.94 04-01-2017
GBP 1.19 04-01-2017
USD 0.91 03-03-2017
GBP 1.17 03-03-2017
USD 0.92 03-01-2017
GBP 1.20 03-01-2017
USD 0.93 02-01-2017
GBP 1.21 02-01-2017
I want to get the orders with invoice dates and the applicable exchange rate at that moment.
Currently I have the following SQL Query:
SELECT JOBS.ID, JOBS.INVOICE_DATE, EXCHG.CURR, EXCHG.RATE, EXCHG.DATE_FROM
FROM LOC.JOBS JOBS
LEFT JOIN LOC.EXCHG EXCHG
ON (JOBS.INVOICE_DATE-EXCHG.DATE_FROM) >= 0) AND (JOBS.INVOICE_DATE-EXCHG.DATE_FROM <= 31)
WHERE
EXCHG.CURR = 'USD'
And this is working fine except that I get some orders double with two or more exchange rates:
ID INVOICE_DATE RATE_USD DATE_FROM
1 5/5/2017 0.92 5/1/2017
1 5/5/2017 0.95 4/4/2017
2 5/3/2017 0.92 5/1/2017
2 5/3/2017 0.95 4/4/2017
3 4/28/2017 0.95 4/4/2017
3 4/28/2017 0.94 4/1/2017
4 4/15/2017 0.95 4/4/2017
4 4/15/2017 0.94 4/1/2017
5 4/1/2017 0.94 4/1/2017
5 4/1/2017 0.91 3/3/2017
5 4/1/2017 0.92 3/1/2017
6 3/28/2017 0.91 3/3/2017
6 3/28/2017 0.92 3/1/2017
7 3/15/2017 0.91 3/3/2017
7 3/15/2017 0.92 3/1/2017
8 3/2/2017 0.92 3/1/2017
8 3/2/2017 0.93 2/1/2017
9 2/27/2017 0.93 2/1/2017
What I would like to get is:
ID INVOICE_DATE RATE_USD DATE_FROM
1 5/5/2017 0.92 5/1/2017
2 5/3/2017 0.92 5/1/2017
3 4/28/2017 0.95 4/4/2017
4 4/15/2017 0.95 4/4/2017
5 4/1/2017 0.94 4/1/2017
6 3/28/2017 0.91 3/3/2017
7 3/15/2017 0.91 3/3/2017
8 3/2/2017 0.92 3/1/2017
9 2/27/2017 0.93 2/1/2017
I am trying to figure out how to do this, somehow I need to select the minimum of the result of these two statements:
JOBS.INVOICE_DATE-EXCHG.DATE_FROM >= 0 AND JOBS.INVOICE_DATE-EXCHG.DATE_FROM <= 31
The best I can come up with is:
SELECT JOBS.ID, JOBS.INVOICE_DATE, EXCHG.CURR, EXCHG.RATE, EXCHG.DATE_FROM
FROM LOC.JOBS JOBS
LEFT JOIN LOC.EXCHG EXCHG
ON (MIN(JOBS.INVOICE_DATE-EXCHG.DATE_FROM) AND (JOBS.INVOICE_DATE-EXCHG.DATE_FROM >= 0))
WHERE
EXCHG.CURR = 'USD'
But this gives me the following error:
[Oracle][ODBC][Ora]ORA-00934: group function is not allowed here
Can someone please solve this issue for me? I would be really happy.
Floris
PS. This is my first question here so I hope it is good :)
"Do the simplest thing that could possibly work" - Ward Cunningham
I suggest that you add another column to your EXCHG table named DATE_TO which represents the expiration date of the exchange rate. Whenever you get a new exchange rate for a particular currency you set DATE_TO on whatever row matches the currency and has DATE_TO = NULL, which can be done using a compound trigger. Then your query becomes:
SELECT j.ID,
j.INVOICE_DATE,
e.CURR,
e.RATE,
e.DATE_FROM
FROM LOC.JOBS j
LEFT OUTER JOIN LOC.EXCHG e
ON (j.INVOICE_DATE BETWEEN e.DATE_FROM
AND e.DATE_TO) OR
(e.DATE_FROM <= j.INVOICE_DATE AND e.DATE_TO IS NULL)
WHERE e.CURR = 'USD'
Best of luck.

How to select only the rows with the latest date for each stock

stock data
ticker date open high low close volume
--------------------------------------------------------------
AAA 2014-06-16 0.9 0.9 0.89 0.895 542
AAA 2014-06-15 1.32 1.33 1.31 1.32 2792
AAA 2014-06-14 1.19 1.25 1.19 1.25 417
AAA 2014-06-13 0.715 0.715 0.705 0.71 36526
BBB 2014-06-16 0.9 0.9 0.89 0.895 542
BBB 2014-06-15 1.32 1.33 1.31 1.32 2792
BBB 2014-06-14 1.19 1.25 1.19 1.25 417
BBB 2014-06-13 0.715 0.715 0.705 0.71 36526
CCC 2014-06-16 0.9 0.9 0.89 0.895 542
CCC 2014-06-15 1.32 1.33 1.31 1.32 2792
CCC 2014-06-14 1.19 1.25 1.19 1.25 417
CCC 2014-06-13 0.715 0.715 0.705 0.71 36526
I want to select so that it only returns the rows with the latest dates(dynamically), the results with 2014-06-16 for each stock
AAA 2014-06-16 0.9 0.9 0.89 0.895 542
BBB 2014-06-16 0.9 0.9 0.89 0.895 542
CCC 2014-06-16 0.9 0.9 0.89 0.895 542
select Stock_data.*
from Stock_data inner join (
select ticker, max(date) maxdate
from Stock_Data
group by ticker) maxdates
on maxdates.maxdate=date
and maxdates.ticker=Stock_data.ticker
Try this
SELECT T.ticker,T.date,T.open,T.high,T.low,T.close,T.volume
FROM Table1 T
INNER JOIN (
SELECT ticker,Max(date) as MaxDate
FROM Table1
GROUP BY ticker
) S ON S.ticker = T.ticker AND T.date = S.MaxDate
Query like following can be used :
select d.ticker, MAX(d.date) from stock_data d group by d.ticker
Try below query:
WITH TAB AS (
SELECT
TICKER,
DAY,
OPEN,
HIGH,
LOW,
CLOSE,
VOLUME,
RANK() OVER(PARTITION BY TICKER
ORDER BY DAY DESC) AS RANKK
FROM Stocks)
SELECT TICKER, DAY, OPEN, HIGH, LOW, CLOSE, VOLUME
FROM TAB
WHERE TAB.RANKK = 1
using Natural join will do the trick :
select * from
table_name
natural join (select ticker, max(date) as date
from table_name
group by ticker);

Simple SQL math operation gives incorrect results

I am running into an issue with a simple SQL math operation of qty * price is returning an incorrect value.
This is SQL server 2005. Compatibility is set to 80 for 2000 SQL server.
Any help on understanding why I am having the problem shown below
For example:
Transaction Table:
id price qty
1 2.77 20.00
1 2.77 25.00
1 2.77 10.00
2 0.10 50.00
2 0.10 80.00
3 0.10 50.00
3 0.10 60.00
SQL
Select id, price, qty, (qty * price) from transact
The actual problem was this and it was my fault :(
Select id, CAST(price AS DECIMAL(5,2)), qty, (qty * price) from transact
Returns the following:
id price qty Total
1 2.77 20.00 55.400000 Correct
1 2.77 25.00 69.250000 Correct
1 2.77 10.00 27.700000 Correct
2 0.10 50.00 4.800000 Should be 5.0000
2 0.10 80.00 7.680000 Should be 8.0000
2 0.10 50.00 5.050000 Should be 5.0000
2 0.10 60.00 6.060000 Should be 6.0000
3 39.00 1.00 39.000000 Correct
3 39.00 2.00 78.000000 Correct
3 39.00 3.00 117.000000 Correct
You price is being rounded somewhere. The select you are running is not showing the actual price.
select round(0.096, 2) price, 0.096 * 50.00 total
Result:
price total
0.10 4.80000