Query Sales Group by week no and Month - sql

I have to calculate sales based on WeekNo(Yearly) and Month.
Table1: Sales
ID SalDate Amount Region
1 2020-12-27 1000 USA
2 2020-12-28 1000 EU
3 2020-12-29 1000 AUS
4 2021-01-01 1000 USA
5 2021-01-02 1000 EU
6 2021-01-05 1000 AUS
7 2020-09-30 1000 EU
8 2020-10-01 1000 AUS
Select DateName(Month,SalDate)+' - '+Convert(Varchar(10),Year(SalDate)) Months,
'Week '+ Convert(Varchar(50), DATEPART(WEEK, SalDate)) As Weeks,
Sum(Amount) OrderValue
From [Sales]
Group By DateName(Month,SalDate)+' - '+Convert(Varchar(10),Year(SalDate)),
Convert(Varchar(50), DATEPART(WEEK, SalDate))
Months Weeks Total
January - 2021 Week 1 2000.00
January - 2021 Week 2 1000.00
December - 2020 Week 53 3000.00
October - 2020 Week 40 1000.00
September - 2020 Week 40 1000.00
But client want to merge Week1 Total with Week 53
And Week2 show as Week1.
And Week 40 Merge with Sep 2020.
I want result like below
Months Weeks Total
January - 2021 Week 1 1000.00
December - 2020 Week 53 5000.00 (2000+3000)
September - 2020 Week 40 2000.00 (1000+100)
Kindly help me to fix this problem.

Related

Calculate year on year Run_time from cumulative Run_time

In SQL Server, I have maintained following details.
S.No
Vehicle_ID
Start Date
Failed Date
Total Run years
1
1
2011-01-01
2013-12-31
3
2
1
2014-01-01
2015-12-31
2
3
1
2016-01-01
2019-12-31
4
4
1
2020-01-01
2022-12-31
3
5
2
2011-01-01
2015-12-31
5
6
2
2016-01-01
2022-12-31
7
8
3
2013-01-01
2016-12-31
4
10
3
2017-01-01
2021-12-31
5
I would like to calculate year on year Run_time from cumulative Run_time
Required result like this:
Year
Run Years
2011
2
2012
2
2013
3
2014
3
2015
3
2016
3
2017
3
2018
3
2019
3
2020
3
2021
3
2022
2
Year column first year is MIN year from Start Date
Year column end year is MAX year from Failed Date
First of all we can generate list of relevant years using GENERATE_SERIES
SELECT value [Year]
FROM GENERATE_SERIES(
(SELECT YEAR(MIN(StartDate)) FROM Cars),
(SELECT YEAR(MAX(EndDate)) FROM Cars)
)
After this we can JOIN YEARS table with our data group it by Year ad get count:
WITH YEARS AS (
SELECT value [Year]
FROM GENERATE_SERIES(
(SELECT YEAR(MIN(StartDate)) FROM Cars),
(SELECT YEAR(MAX(EndDate)) FROM Cars)
)
) SELECT [Year], COUNT(*)
FROM YEARS
JOIN Cars ON [Year] BETWEEN YEAR(StartDate) AND YEAR(EndDate)
GROUP BY [Year]
And test above queries on:
https://sqlize.online/sql/mssql2022/9ae8b354190c9cf2d19739bf9b9a9816/

Calculating incremental values from a cumulative sum field in Teradata

Good afternoon -
I have a table in Teradata that stores a rolling cumulative sum that resets every month. I would like to be able to calculate the incremental gain between each day of the month. Is this something that I can accomplish with olap functions or should it be handled in a recursive cte? Would love assistance thinking through this. Thanks!
example source
date
month
cum_value
2022-07-02
July 2022
25
2022-07-01
July 2022
5
2022-06-30
June 2022
100
2022-06-29
June 2022
70
2022-06-28
June 2022
65
2022-06-27
June 2022
50
example result
date
month
cum_value
incremental_value
2022-07-02
July 2022
25
20
2022-07-01
July 2022
5
5
2022-06-30
June 2022
100
30
2022-06-29
June 2022
70
5
2022-06-28
June 2022
65
15
2022-06-27
June 2022
50
..

Error building a SQL query while trying to get order by a day for a period of week

I have an ASP.NET Core application, through controller endpoint I pass #by and #period string values to the SQL query.
#by takes one of the following values: day, week
#period takes one of the following values: week, month, year
When the #period is month or year, then #by is a week, else it's a day.
I have the following working query when the #period is a month or a year:
SELECT
l.region_id AS region_id,
'Region ' + r.region_desc AS region_name,
MIN(DATEADD(D, -(DATEPART(WEEKDAY, s.pos_date) - 1), s.pos_date)) AS date_pos,
CONVERT(VARCHAR(20), MIN(DATEADD(D, -(DATEPART(WEEKDAY, s.pos_date) - 1), s.pos_date)), 107) AS display_date_pos
FROM
incent_summary s
INNER JOIN
location l ON s.store_num = l.store_num
INNER JOIN
region r ON l.region_id = r.region_id
WHERE
s.pos_date >= DATEADD(day, #period , CONVERT(date, GETDATE()))
AND s.pos_date <= GETDATE()
GROUP BY
DATEPART (#by, s.pos_date),
l.region_id, r.region_desc
ORDER BY
DATEPART (#by, pos_date),
l.region_id, r.region_desc
The issue is when the #period is a week, #by is day, and the statement
MIN(DATEADD(D, -(DATEPART(WEEKDAY, s.pos_date) - 1), s.pos_date)) AS date_pos
returns the same day for all the 7 days.
Sample output when #period = year and #by = week:
region_id region_name date_pos display_date_pos
---------------------------------------------------------------------
34 Region 43 2019-12-29 00:00:00.000 Dec 29, 2019
50 Region 22 2019-12-29 00:00:00.000 Dec 29, 2019
34 Region 43 2020-01-05 00:00:00.000 Jan 05, 2020
50 Region 22 2020-01-05 00:00:00.000 Jan 05, 2020
34 Region 43 2020-01-12 00:00:00.000 Jan 12, 2020
50 Region 22 2020-01-12 00:00:00.000 Jan 12, 2020
34 Region 43 2020-01-19 00:00:00.000 Jan 19, 2020
50 Region 22 2020-01-19 00:00:00.000 Jan 19, 2020
34 Region 43 2020-01-26 00:00:00.000 Jan 26, 2020
50 Region 22 2020-01-26 00:00:00.000 Jan 26, 2020
Sample output when #period = week and #by = day:
region_id region_name date_pos display_date_pos
--------------------------------------------------------------------
34 Region 43 2020-07-12 00:00:00.000 Jul 12, 2020
50 Region 22 2020-07-12 00:00:00.000 Jul 12, 2020
34 Region 43 2020-07-12 00:00:00.000 Jul 12, 2020
50 Region 22 2020-07-12 00:00:00.000 Jul 12, 2020
34 Region 43 2020-07-19 00:00:00.000 Jul 19, 2020
50 Region 22 2020-07-19 00:00:00.000 Jul 19, 2020
34 Region 43 2020-07-19 00:00:00.000 Jul 19, 2020
50 Region 22 2020-07-19 00:00:00.000 Jul 19, 2020
34 Region 43 2020-07-19 00:00:00.000 Jul 19, 2020
50 Region 22 2020-07-19 00:00:00.000 Jul 19, 2020
How can I fix this?
SELECT
DATEADD(D, -(DATEPART(WEEKDAY, s.pos_date) - 1), s.pos_date)
Will always return the first day of the week because the logic is: "subtract from my date the number of days from sunday and add 1."
Sunday: 1 - 1 + 1 = 1 = Sunday
Monday: 2 - 2 + 1 = 1 = Sunday
.
.
.
Saturday: 7 - 7 + 1 = Sunday
That's fine when you want the first Sunday of the year/month/whatever. But the first sunday of every week is always... sunday. But in this case you really just need to take the MIN(s.pos_date) if #period is week.
There's probably some crazy way to do this in a single statement using quaternions or something else super mathy, but it's easiest to just use a case statement:
MIN
(
CASE
WHEN '#by' = 'day' THEN s.pos_date
ELSE DATEADD(D, -(DATEPART(WEEKDAY, s.pos_date) - 1), s.pos_date)
END
)
I'm not a C# programmer so I can't tell you the exact way to make sure the string DAY is passed to the query as "DAY" but I'm sure you can handle that part.
ALSO IMPORTANT The datepart "day" is day of month, so if you're going to possibly have a span greater than one month (but under a year), use dayofyear.

Logic to get dynamic date range in query for Fiscal Year

I have a requirement to select data for different date ranges, depending one the current month it is run on. I have a Stored Procedure that takes in a user supplied Date i.e. 04/06/2020 into the variable #PPE. Based on the Month portion of this date, I need to query back varying ranges as in a Fiscal Year (July 1 - June 30th) follows: I am using the example using a 2020 Financial Year.
MONTH(#PPE) Date Range to Query
July 07/01/2019 - 07/01/2019
August 07/01/2019 - 08/31/2019
September 07/01/2019 - 09/30/2019
October 07/01/2019 - 09/30/2019
November 07/01/2019 - 09/30/2019
December 07/01/2019 - 09/30/2019
January 07/01/2019 - 12/31/2019
February 07/01/2019 - 12/31/2019
March 07/01/2019 - 12/31/2019
April 07/01/2019 - 03/31/2020
May 07/01/2019 - 03/31/2020
June 07/01/2019 - 03/31/2020
Then Starting next Fiscal Year (2021) it would go as follows, and onwards...
MONTH(#PPE) Date Range to Query
July 07/01/2020 - 07/01/2020
August 07/01/2020 - 08/31/2020
September 07/01/2020 - 09/30/2020
October 07/01/2020 - 09/30/2020
November 07/01/2020 - 09/30/2020
December 07/01/2020 - 09/30/2020
January 07/01/2020 - 12/31/2020
February 07/01/2020 - 12/31/2020
March 07/01/2020 - 12/31/2020
April 07/01/2019 - 03/31/2021
May 07/01/2019 - 03/31/2021
June 07/01/2019 - 03/31/2021
I started with this query , but I'm having trouble manipulating the correct FISCAL_YEAR to put in, depending on what the month of the #PPE date is, because it spans 2 years between April and June.
PERIOD represents the Fiscal Month number i.e. July = 1 , August = 2, ....June = 12
DECLARE #PPE datetime; SET #PPE = '04/06/2020'
SELECT COMPANY, DEPTID, FISCAL_YEAR, PERIOD, GH_REPORTID, SUM(GH_HOURS), SUM(GH_DOLLARS)
FROM PS_GH_SLT_ACTUALS
WHERE DEPTID = 55650000
AND GH_REPORTID = 'BA'
AND PERIOD <= CASE WHEN MONTH(#PPE) BETWEEN 1 AND 3 THEN 12
WHEN MONTH(#PPE) BETWEEN 4 AND 6 THEN 3
WHEN MONTH(#PPE) BETWEEN 7 AND 9 THEN 6
WHEN MONTH(#PPE) BETWEEN 10 AND 12 THEN 9
END
-- AND PERIOD <= 7 ???
AND FISCAL_YEAR = CASE WHEN MONTH(#PPE) BETWEEN 1 AND 3 THEN YEAR(#PPE)
WHEN MONTH(#PPE) BETWEEN 4 AND 6 THEN ....???
GROUP BY COMPANY, DEPTID, FISCAL_YEAR, PERIOD, GH_REPORTID
If your fiscal year is already in the format, then you can use the following and condition:
FISCAL_YEAR = CASE WHEN MONTH(#PPE) BETWEEN 1 AND 6 THEN YEAR(#PPE)
ELSE YEAR(#PPE)+1 END
The above condition should work under the assumption that, Jul 2019 to Jun 2020 is called as Fiscal year 2020, as per your data. Hope this helps.

Select and group past data relative to a certain date

I have data in two tables ORDERS and training.
Different kinds of training are provided to various customers. I would like to see what was the affect of these training on revenue for the customers involved. For achieving this, I would like to look at the revenue for the past 90 days and the future 90 days for each customer from the date of receiving the training. In other words, if a customer received a training on March 30 2014, I would like to look at the revenue from Jan 1 2014 till June 30 2014. I have come up with the following query which pretty much does the job:
select
o.custno,
sum(ISNULL(a.revenue,0)) as Revenue,
o.Date as TrainingDate,
DATEADD(mm, DATEDIFF(mm, 0, a.created), 0) as RevenueMonth
from ORDERS a,
(select distinct custno, max(Date) as Date from Training group by custno) o
where a.custnum = o.custno
and a.created between DATEADD(day, -90, o.Date) and DATEADD(day, 90, o.Date)
group by o.custno, o.Date, DATEADD(mm, DATEDIFF(mm, 0, a.created), 0)
order by o.custno
The sample output of this query looks something like this:
custno Revenue TrainingDate RevenueMonth
0000100 159.20 2014-06-02 00:00:00.000 2014-03-01 00:00:00.000
0000100 199.00 2014-06-02 00:00:00.000 2014-04-01 00:00:00.000
0000100 79.60 2014-06-02 00:00:00.000 2014-05-01 00:00:00.000
0000100 29.85 2014-06-02 00:00:00.000 2014-06-01 00:00:00.000
0000100 79.60 2014-06-02 00:00:00.000 2014-07-01 00:00:00.000
0000100 99.50 2014-06-02 00:00:00.000 2014-08-01 00:00:00.000
0000250 437.65 2013-02-26 00:00:00.000 2012-11-01 00:00:00.000
0000250 4181.65 2013-02-26 00:00:00.000 2012-12-01 00:00:00.000
0000250 4146.80 2013-02-26 00:00:00.000 2013-01-01 00:00:00.000
0000250 6211.93 2013-02-26 00:00:00.000 2013-02-01 00:00:00.000
0000250 2199.72 2013-02-26 00:00:00.000 2013-03-01 00:00:00.000
0000250 4452.65 2013-02-26 00:00:00.000 2013-04-01 00:00:00.000
Desired output example:
If the training was provided on March 15 2014, for customer number 100, I’d want revenue data in the following format:
CustNo Revenue TrainingDate RevenueMonth
100 <Some revenue figure> March 15 2014 Dec 15 2013 – Jan 14 2014 (Past month 1)
100 <Some revenue figure> March 15 2014 Jan 15 2014 – Feb 14 2014 (Past month 2)
100 <Some revenue figure> March 15 2014 Feb 15 2014 – Mar 14 2014 (Past month 3)
100 <Some revenue figure> March 15 2014 Mar 15 2014 – Apr 14 2014 (Future month 1)
100 <Some revenue figure> March 15 2014 Apr 15 2014 – May 14 2014 (Future month 2)
100 <Some revenue figure> March 15 2014 May 15 2014 – Jun 14 2014 (Future month 3)
Here, the RevenueMonth column doesn’t need to be in this format as long as it has the data relative to the training date. The ‘past’ and ‘future’ month references in the braces are only to explain the output, they need not be present in the output.
My query gets the data and groups the data by month. I would like the months to be grouped relative to the training date. For example - If the training was given on March 15, I would like the past month to be from Feb 15 till March 14, my query doesn't do that. I believe a little tweak in this query might just achieve what I'm after.
Any help with the query would be highly appreciated.
Something along these lines may do what you want:
select
t.custno,
sum(ISNULL(o.revenue,0)) as Revenue,
t.maxDate as TrainingDate,
((DATEDIFF(day, TrainingDate, o.created) + 89) / 30) - 3 as DeltaMonth
from ORDERS o
join (select custno, max([Date]) as maxDate from Training group by custno) t
on o.custnum = t.custno
where o.created
between DATEADD(day, -89, t.maxDate) and DATEADD(day, 90, t.maxDate)
group by t.custno, t.maxDate, DeltaMonth
order by t.custno
The general strategy is to compute a difference in months (or 30-day periods, really) from the training date, and group by that. This version uses from 89 days before to 90 days after the training, because if you run from -90 to +90 then you have one more day (the training day itself) than divides evenly into 30-day periods.
The query follows the general structure of the original, but there are several changes:
it computes DeltaMonth (from -3 to 2) as an index of 30-day periods relative to the training date, with the training date being the last day of DeltaMonth number -1.
it uses the DeltaMonth alias in the GROUP BY clause instead of repeating its formula. That provides better clarity, simplicity, and maintainability.
I changed the table aliases. I simply could not handle there being a table named "ORDERS" and an alias "o", with the latter not being associated with the former.
the query uses modern join syntax, for better clarity
the GROUP BY clause updated appropriately