Faster alternative of MIN/MAX in SQL Server - sql

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.

Related

Before&After purchase of a product

I have two tables:
orders_product: all the orders. Each line is a product sold with some details about the order in which it was included. So, if the order has more than 1 product, there are more than 1 line for this order.
orders_grouped: each line is an order with some details about this specific order.
I would like know if there was a previous purchase and a following purchase for each product.
SELECT
product_name,
last_value(product_all_grouped_list) over (partition by ord.customer_id order by created_at asc rows between unbounded preceding and 1 preceding ) as last_order,
last_value(product_all_grouped_list) over (partition by ord.customer_id order by created_at desc rows between unbounded preceding and 1 preceding ) as next_order_products,
last_value(basket_size) over (partition by ord.customer_id order by created_at desc rows between unbounded preceding and 1 preceding ) as next_order_basket_size
FROM
`orders_product` ord
left join `orders_grouped` ordgroup
on ord.order_number=ordgroup.order_number
When the order has only one product (basket_size=1), everything is correct but when the basket_size>1, the results for the first product of this order is OK but for the rest of products of the order is wrong.
Can someone help me?
Because several orders items are present and thus several rows the windows function has to be different.
RANGE instead of ROWS in the over statement.
Also use window at the end:
With tbl as (
Select * from unnest(generate_timestamp_array("2022-09-01","2022-09-15",interval 1 hour)) update_time
)
SELECT
*,
LAST_VALUE(update_time) OVER (ORDER BY update_time ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ),
timestamp_diff(update_time,timestamp("1999-01-01"),second) ,
LAST_VALUE(update_time) OVER SETUP_window
FROM
tbl
window SETUP_window as (ORDER BY timestamp_diff(update_time,timestamp("1999-01-01"),second) ASC RANGE BETWEEN UNBOUNDED PRECEDING AND 36000 PRECEDING )
order by update_time desc

Finding sales growth from cumulative totals over period in SQL

SELECT CUST_ID,CONTACTS
Sum("CONTACTS") Over (PARTITION by "CUST_ID" Order By "end_Period" ROWS UNBOUNDED PRECEDING) as RunningContacts,
"SALES",
Sum("SALES") Over (PARTITION by "CUST_ID" Order By "end_Period" ROWS UNBOUNDED PRECEDING) as RunningSales,
end_Period
FROM Table2
I have currently created the Running growth column in excel formula is (New Runningsales - Previous Running sales) / Previous RunningSales.
Any help here is appreciated.
Are you looking for this?
select t.*,
RunningSales / (Running - Sales) - 1
from (< your query here > ) x
The SQL derived table can hold a query to aggregate sales by period, and you an join such to itself to compare each period to the prior period.

How to do a STDEV calculation with the LAG function?

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;

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

Moving trailing 13-week average in Postgres

I am trying to build a view that generates a movable 13-week average over the past year.
My source data includes a date, customer ID, and integer, and basically I want to average the 13 prior values (including the current one), over the previous 52 weeks. When I'm finished, I'd like to have a table with a date, each customer ID, and trailing 13-week average for that customer.
After upgrading Postgres to 9.1, the window functions worked great for this:
SELECT vs.weekending,
cs.slinkcust AS customer,
cs.slinkid AS id,
round(avg(vs.maxattached) OVER (PARTITION BY cs.slinkid ORDER BY vs.weekending DESC ROWS BETWEEN 0 PRECEDING AND 12 FOLLOWING), 2) AS rolling_conc_avg,
round(avg(vs.totsessions) OVER (PARTITION BY cs.slinkid ORDER BY vs.weekending DESC ROWS BETWEEN 0 PRECEDING AND 12 FOLLOWING), 2) AS rolling_sess_avg,
dense_rank() OVER (ORDER BY vs.weekending) AS week_number
FROM cfg_slink cs
JOIN view_statslink vs ON cs.slinkid = vs.id
WHERE vs.weekending >= (now() - '364 days'::interval) AND cs.disabled = 0
GROUP BY vs.weekending, cs.slinkid, vs.maxattached, vs.totsessions
ORDER BY vs.weekending DESC, cs.slinkcust;