How to do a STDEV calculation with the LAG function? - sql

I'm running code like this:
SELECT ID, Date, Price,
STDEV(Price) OVER (ORDER BY ID, Date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) As OneMonths,
STDEV(Price) OVER (ORDER BY ID, Date ROWS BETWEEN 60 PRECEDING AND CURRENT ROW) As TwoMonths,
STDEV(Price) OVER (ORDER BY ID, Date ROWS BETWEEN 90 PRECEDING AND CURRENT ROW) As ThreeMonths
FROM Price_Table
That gives me this result.
In the fiver first row I always have three nulls for the three variances. This makes sense. However, every time the ID changes, I must be getting the preceding ID's prices, because each time the ID changes, I would expect the standard deviation to get reset. So, the first line in orange should be null, I think, and the next one should be zero, because there is no change in price the second day. I tried wrapping the LAG function around the STDEV function and I got an error. I tried the opposite and also got an error.

If you want the value per id, then you need partition by:
SELECT ID, Date, Price,
STDEV(Price) OVER (PARTITION BY ID ORDER BY Date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) As OneMonths,
STDEV(Price) OVER (PARTITION BY ID ORDER BY Date ROWS BETWEEN 60 PRECEDING AND CURRENT ROW) As TwoMonths,
STDEV(Price) OVER (PARTITION BY ID ORDER BY Date ROWS BETWEEN 90 PRECEDING AND CURRENT ROW) As ThreeMonths
FROM Price_Table;

Related

Faster alternative of MIN/MAX in SQL Server

I need the lowest/highest price of stocks for the past n days. The following query works really slow. I would appreciate faster alternative:
SELECT
*,
MIN(Close) OVER (PARTITION BY Ticker ORDER BY PriceDate ROWS BETWEEN 14 PRECEDING AND 1 PRECEDING) AS MinPrice14d,
MAX(Close) OVER (PARTITION BY Ticker ORDER BY PriceDate ROWS BETWEEN 14 PRECEDING AND 1 PRECEDING) AS MaxPrice14d
FROM
(SELECT CompanyID, Ticker, PriceDate, Close
FROM price.PriceHistoryDaily) a
I need the columns specified.
It is trailing, so I need it day by day.
As for period, I will limit it to one year.
Although it doesn't affect the performance, no subquery is needed. So start with the simpler version:
SELECT phd.CompanyID, phd.Ticker, phd.PriceDate, phd.Close,
min(Close) over (partition by Ticker
order by PriceDate
rows between 14 preceding and 1 preceding
) as MinPrice14d,
max(Close) over (partition by Ticker
order by PriceDate
rows between 14 preceding and 1 preceding
) as MaxPrice14d
FROM price.PriceHistoryDaily phd;
Then try adding an index: PriceHistoryDaily(Ticker, PriceDate).
Note: That this returns all rows from PriceHistoryDaily and -- depending on the size of the table -- that might be what is driving the performance.

SQL Server : PRECEDING with another condition

I have a query that is working fine: The query is to find the sum & Avg for the last 3 months and last year. It is working fine, till I got a new request to break the query down to more details by AwardCode.
So how to include that?
I mean for this section
SUM(1.0 * InvolTerm) OVER (ORDER BY Calendar_Date ASC
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS InvolMov3Mth,
I want to find the last 3 months based on AwardCode.
My original query that is working is
SELECT
Calendar_Date, Mth, NoOfEmp, MaleCount, FemaleCount,
SUM(1.0*InvolTerm) OVER (ORDER BY Calendar_Date ASC
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS InvolMov3Mth,
SUM(1.0*TotalTerm) OVER (ORDER BY Calendar_Date ASC
ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) AS TermSum12Mth
FROM #X
The result is
But now I need to add another group AwardCode
SELECT
Mth, AwardCode, NoOfEmp, MaleCount, FemaleCount,
SUM(1.0 * InvolTerm) OVER (ORDER BY Calendar_Date ASC
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS InvolMov3Mth,
SUM(1.0 * TotalTerm) OVER (ORDER BY Calendar_Date ASC
ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) AS TermSum12Mth
FROM #X
The result will be like this
You can notice that the sum of InvolMov3Mth & TermSum12Mth for the whole period does not match the query above
I think I found the answer for my question.
I used PARTITION BY AwardCode before ORDER BY
seems to be working.
SUM(1.0*TotalTerm) OVER (PARTITION BY AwardCode ORDER BY Calendar_Date ASC
ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) AS TermSum12Mth,
Yes. "Partition by" will make it work for your requirment

Subtract the value of the most recent row with the value of the previous row (day -1)

I have a table with incremental value for each day. I'd like to subtract the value of the most recent row with the value of the previous row (day -1)
For example, this would be perfect :
SUM(value) OVER (PARTITION BY item_name ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
However, I would need to apply a DIFF function instead of a SUM function.
Simply use lag():
select val - lag(val) over (partition by item_name order by date)

Calculate MAX for value over a relative date range

I am trying to calculate the max of a value over a relative date range. Suppose I have these columns: Date, Week, Category, Value. Note: The Week column is the Monday of the week of the corresponding Date.
I want to produce a table which gives the MAX value within the last two weeks for each Date, Week, Category combination so that the output produces the following: Date, Week, Category, Value, 2WeeksPriorMAX.
How would I go about writing that query? I don't think the following would work:
SELECT Date, Week, Value,
MAX(Value) OVER (PARTITION BY Category
ORDER BY Week
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) as 2WeeksPriorMAX
The above query doesn't account for cases where there are missing values for a given Category, Week combination within the last 2 weeks, and therefore it would span further than 2 weeks when it analyzes the 2 preceding rows.
Left joining or using a lateral join/subquery might be expensive. You can do this with window functions, but you need to have a bit more logic:
select t.*,
(case when lag(date, 1) over (partition by category order by date) < date - interval '2 week'
then value
when lag(date, 2) over (partition by category order by date) < date - interval '2 week'
then max(value) over (partition by category order by date rows between 1 preceding and current row)
else max(value) over (partition by category order by date rows between 2 preceding and current row)
end) as TwoWeekMax
from t;

Last value from previous quarter, given that it's date is less than or equal the current rows date - SQL

I have the following table data:
I generated the last two columns with the following:
SELECT PublishDate, QuarterEndDate, Value, FiscalYear, FiscalQuarter,
FIRST_VALUE(Value) OVER(PARTITION BY FiscalYear ORDER BY FiscalQuarter, PublishDate
ROWS 1 PRECEDING) as LAST_VAL,
Value - FIRST_VALUE(Value) OVER(PARTITION BY FiscalYear ORDER BY FiscalQuarter,PublishDate
ROWS 1 PRECEDING) as QTR_DIFF
FROM tabledata
I am trying to calculate what the differences are between quarters given that the information was published.
Basically, I want to calculate the current row value minus the last value of the previous fiscal quarter (in the same fiscal year) given that its PublishDate is less than or equal to the current rows PublishDate.
If it is the first quarter than the first quarter numbers should be retained without any change.
In the above figure, the highlighted rows show a couple of the problems:
1) The zero value for the first quarter even though it should be the values itself (i.e. 19461)
2) The preceding row is taking the previous row not the previous quarter - its taking the last value as the preceding row's value - not the last value from the quarter given that the publish date is less than or equal to it.
Any help would be greatly appreciated... Thanks!
I have not tested this yet but looking at your code you are partitioning by the year only, I wonder if this will work:
SELECT PublishDate, QuarterEndDate, Value, FiscalYear, FiscalQuarter,
FIRST_VALUE(Value) OVER(PARTITION BY FiscalYear,FiscalQuarter ORDER BY FiscalQuarter, PublishDate
ROWS 1 PRECEDING) as LAST_VAL,
Value - FIRST_VALUE(Value) OVER(PARTITION BY FiscalYear,FiscalQuarter ORDER BY FiscalQuarter,PublishDate
ROWS 1 PRECEDING) as QTR_DIFF
FROM tabledata