Calculating last 7 days for each day in range - sql

My table (products) is as follow:
id, productId, price, saleDate
I want to build a query that for specific productId and specific data range will return the average of the price for the last 7 days for each day in the range.
The following query will give me all the data for specific productId between 1/1/16 and 02/01/16
SELECT * FROM products WHERE productId='PS54434' AND saleDate BETWEEN '2016-01-01' AND '2016-02-01'
BUT I want that for each day 01/01/16 until 02/01/16 I will receive the last 7 days
so for data 01/01/16 I will receive the average of prices from the 12/26/16-01/01/16

One way to do it is using a loop. You declare a start date and go back 7 days from that date and get the average price for that date range. Then add 1 day and repeat the process. If you need all the results as a table, create a temp table and store the result from each iteration.
declare #startdate date = '2016-01-01';
create table #tmpavgprice (price numeric(10,2));
while #startdate <= '2016-02-01'
begin
SELECT avg(price)
INTO #tmpavgprice
FROM products
WHERE productId='PS54434'
AND saleDate BETWEEN dateadd(dd,-7,#startdate) AND #startdate;
set #startdate = select dateadd(dd,1,#startdate);
end;
select * from #tmpavgprice; --to get the final result

Related

Using SQL query how to check a certain value of a column along with the whole values in other columns?

I have a table with sample data
Inventory
shop_code product_id date QTY
10 20 20210101 5
**EDIT: Please add additional data above too**
I want to select shop_codes and product_ids for which the QTY was not 0 for all the dates in the last 60 days.
EDIT: The OP put this in an answer, It should be here
what I am trying to is:
select top 1000
SHOPCODE,
ProductId,
COUNT(DateKey) as dayNumber
from
Inventory
where
DateKey > (the date of 60 days ago)
and QTY > 0
group by
SHOPCODE,
ProductID
having
COUNT(DateKey) = ( select COUNT(distinct DateKey)
from Inv where DateKey > (the date of 60 days ago)
)
I'm not sure that it is a suitable way and wonder if there is a way rather than counting the dates
First, we calculate the date of the previous 60 days and put it in the variable numerically.
Then we extract all the products, provided that their date is for 60 days and their number is above 0, and we group them according to the store and the product ID.
Use this snippet:
declare #dateInt int
set #dateInt=cast(Convert(CHAR(8),DATEADD(day,-60, getdate())+1,112) as int)
select product_id
,shop_code
,sum(QTY) as sumQTY
from yourTable
where date>=#dateInt and QTY>0
group by product_id,shop_code
Your question is not very clear, but from what I understand of it and from the comments on Sayeed's answer, I think this may be what you are after
select top 1000
i.SHOPCODE,
i.ProductId
from Inventory i
where not exists ( select 1
from inventory i2
where i2.shopcode = i.shopcode
and i2.productid = i.productid
and i2.DateKey > datepart(day, -60, getdate())
and i2.QTY = 0
)

Calculating daily average transaction balance of IDs

need to calculate daily average balance of ids. firstdate is when the ID was generated, currentdate is the dates with balance shown for the IDs.
I am expecting something like this [image 2](manually calculated) for each IDs. So basically need to calculate numbers of days between the firstdate when the id was generated and the last currentdate and the balance should be filled in the blank (between dates) to accurately calculating the daily average.
I created the calender table but not sure how I can get the balance for everyday in order to calculate the average.
CREATE TABLE #Calendar
(
[CalendarDate] DATE
)
DECLARE #StartDate DATE
DECLARE #EndDate DATE
SET #StartDate = '20000101'
SET #EndDate = GETDATE()
WHILE #StartDate <= #EndDate
BEGIN
INSERT INTO #Calendar
(
CalendarDate
)
SELECT
#StartDate
SET #StartDate = DATEADD(day, 1, #StartDate)
Thanks for any help.
Assuming the last observation is weighted to getdate()
There is no need for a calendar table, you can use the window function lead() over() to determine the number of days.
Example
Select ID
,ADB = sum(Balance*Days)/sum(Days)
From (
Select *
,Days = datediff(Day,CurrentDate,lead(CurrentDate,1,getdate() ) over (partition by ID order by CurrentDate ) )
from YourTable
) A
Group By ID
Results
ID ADB
110 109.5597
EDIT
I should add that the window functions can invaluable. They are well worth your time getting comfortable with them.

we need to add the sales condition between two dates, but the first date is the transactions from 7 am

i need sum amount where trans time in first date >= 9:00 am
when i write
select sum(amount)
from <table>
where (trans date between '25-10-2018 ' and '26-10-2018' ) and transtime >9am
not sum amount in 26 because time < the trans time i add it
need add time condition in first date only like where (trans date ='25-10-2018 ' and and transtime >9am and transdate between '25-10-2018 ' and '26-10-2018'
The idea is I have sales sold after 12 am this sales to 3 am followed the previous day
we need to add the sales condition between two dates, but the first date is the transactions from 7 am
First solution:
select sum(amount)
from <table>
where
(transdate between '25-10-2018' and '26-10-2018') and
((transtime > 9am AND transdate = '25-10-2018') OR
(transdate <> '25-10-2018'))
Second solution:
select sum(amount)
from <table>
where
(
CAST(transdate AS DATETIME) +
CAST(transtime AS DATETIME)
) between '25-10-2018 09:00' and '26-10-2018'
There may be other solutions.
Each of these has it's pros and cons, so choose depending on your needs, model and indexes.

Get valid orders at the starting day of each year

In a table containing Order information (call it Order) we have the following fields:
OrderId int
OrderDate Date
BindingTime int
Binding time is in months.
An order is called "Active" between its OrderDate and DATEADD(mm, BindingTime, OrderDate).
What I'd like to do is to group the orders by year so that if an order is "active" on the first day of a year it would be taken into account. The aim is to calculate each year's inbound and outbound orders. So the query result will be COUNT of orders and the year. And by year we mean the number of orders which were active on the first day of that year.
Mind that, we would like to have all the years between two given numbers in our results. E.g. If there was no active order on the first day of 2016 we would still like to to have a row for (0, 2016).
I've used a recursive CTE to generate a range of years, so that a 'zero' year will not be omitted
declare #YEAR1 as date = '20110101';
declare #YEAR2 as date = '20190101';
WITH YEARS AS (SELECT #YEAR1 y
UNION ALL
SELECT dateadd(year,1,y) FROM YEARS WHERE y < #YEAR2)
SELECT YEARS.y,count(0) YearStartActiveOrders FROM YourTable
CROSS JOIN YEARS
WHERE YEARS.y BETWEEN CAST(orderdate as date)
AND CAST(DATEADD(mm, BindingTime, OrderDate) as date)
GROUP BY Years.y
Seems like what you need is a Date table (having a list of all days per year) and left joining that table with your grouped data (active order count, per day of the year).
You can use this date table from Aaron Bertrand. I generated the #dim table with the following params, to only generate two years data (2015, 2016):
DECLARE #StartDate DATE = '20150101', #NumberOfYears INT = 2;
Then you can do the following:
with ordertable as
(
select 1 as orderid, '20160101' as orderdate, 2 as bindingtime union all
select 2, '20160305', 3 union all
select 3, '20160305', 5 union all
select 4, '20150305', 5
)
select d.year, isnull(count(orderid), 0) nrActiveOrdersFirstDayOfYear
from #dim d
left join ordertable g on d.year = year(g.orderdate)
and g.orderdate = d.date
and d.FirstOfYear between g.orderdate and DATEADD(mm, g.bindingtime, OrderDate)
group by d.year
With the sample data I took as an example, you would get the result:
year nrActiveOrdersFirstDayOfYear
2015 0
2016 1
Working demo here.

Dynamic Grouping based on date field SSRS

In my SSRS report which has a dataset with date field as below
The dataset returns the following type of data (just an example)
Voucher Amount Date
R3221 € 3,223.00 1-Dec-17
R3222 € 123.00 28-Nov-17
R3223 € 1,233.00 19-Oct-17
R3224 € 442.00 27-Sep-17
R3225 € 123.00 17-Nov-17
R3226 € 423.00 29-Oct-17
R3227 € 1,234.00 8-Oct-17
What I would like to know is how to show this data grouped by Voucher and Due Date
User should be able to select the Start Date and the period type (Day, Week, month,) and the interval between the two columns (e.g 3 , 10 or 30 or any other number)
so the user should be able to select the period type, e.g if he select Day and interval as 3 then the report should show
**voucher start date <Dynamic grouping columns based on the selection criteria>**
R3221
R3222
R3223
R3224
R3225
R3226
R3227
Any kind of hint will be much appreciated!
This is only part of the solution. First generate date periods you want in the report, then do a LEFT JOIN against your table, filter and group.
declare #dateFrom date
declare #periodInDays int
declare #periods int --how many periods of 10 days
set #periodInDays = 10;
set #periods = 15; --how many periods of 10 days
set #dateFrom = getdate();
with [dates] as (
select #dateFrom as date --start
union all
select dateadd(day, #periodInDays, [date]) as date
from [dates]
where [date] < DATEADD(day, #periodInDays * #periods, #dateFrom) --end
)
select [date]
from [dates]
option (maxrecursion 0)
In this example returns 16 dates (1 per row), from start date (2017-12-01), every 10 days
2017-12-01, 2017-12-11, 2017-12-21, 2017-12-31, 2018-01-10, 2018-01-20
2018-01-30, 2018-02-09, 2018-02-19, 2018-03-01, 2018-03-11, 2018-03-21
2018-03-31, 2018-04-10, 2018-04-20, 2018-04-30
To filter by period get start date from the above date table, so the end date for that period can be calculated as DATEADD(day, #periodInDays, [date]) and we don't need to look into next row at this point.
Just let me know if someone find more straight forward solution.