Grouping several years' data by week - sql

I am using Covid world data, which tracks number of new_cases every day. I have data from 2020-01-01 to present day. This is my current query:
SELECT MIN(date) as week, datepart(iso_week, date) week_num, sum(new_cases) as [Total Cases]
FROM covid_data_cleaned
GROUP BY DATEPART(iso_week, date), DATEPART(year, date)
ORDER BY MIN(date) DESC
Which gives me pretty much what I want except for when the year changes:
week week_num Total Cases
2022-01-10 2 20803473
2022-01-03 1 17217248
**2022-01-01 52 2115780**
**2021-12-27 52 7971560**
2021-12-20 51 5561762
I want to figure out the workaround to combining the '52' values together. Alternatively, my dataset has 112 weeks; can I assign the values 1-112 to the whole dataset rather than 1-52 for each year?

You could aggregate on a correction via a CASE WHEN for the iso year.
SELECT
min(weekstart) as [week]
, [iso_week] as weeknum
, sum(new_cases) as [Total Cases]
FROM
(
SELECT
min([date]) as weekstart
, datepart(iso_week, [date]) as [iso_week]
, case
when month(min([date])) = 1
and datepart(iso_week, [date]) >= 52
then year([date]) - 1
when month(min([date])) = 12
and datepart(iso_week, [date]) = 1
then year([date]) + 1
else year([date])
end as iso_year
, sum(new_cases) as new_cases
FROM covid_data_cleaned
GROUP BY year([date]), datepart(iso_week, [date])
) q
GROUP BY iso_year, [iso_week]
ORDER BY [week] DESC;

Instead of iso week, you can use week.
DECLARE #table table(datev date, new_Cases int)
INSERT INTO #table values
('2022-01-01',123),('2022-01-09',432),('2022-01-03',123),('2021-12-27',234);
SELECT MIN(datev) as week, datepart(week, datev) week_num, sum(new_cases) as [Total Cases]
FROM #table
GROUP BY DATEPART(week, datev), DATEPART(year, datev)
ORDER BY MIN(datev) DESC
week
week_num
Total Cases
2022-01-09
3
432
2022-01-03
2
123
2022-01-01
1
123
2021-12-27
53
234

Related

Keep last n business days records from today date in SQL Server

How can we keep last n business days records from today date in this table:
Suppose n = 7
Sample Data:
Table1:
Date
----------
2021-11-29
2021-11-30
2021-12-01
2021-12-02
2021-12-03
2021-12-04
2021-12-05
2021-12-06
2021-12-07
2021-12-08
2021-12-09
2021-12-10
2021-12-11
2021-12-12
2021-12-13
Based on this table data we want output like below. It should delete all the rows before the 03-Dec or data for last 7 business days.
Date
-------
2021-12-03
2021-12-06
2021-12-07
2021-12-08
2021-12-09
2021-12-10
2021-12-13
Note: It's fine if we keep data for Saturday, Sunday in between business days.
I tried this query
DECLARE #n INT = 7
SELECT * FROM Table1
WHERE [date] < Dateadd(day, -((#n + (#n / 5) * 2)), Getdate())
but Saturday, Sunday logic doesn't fit here with my logic. Please suggest better approach.
You can get the 7th working day from today as
select top(1) cast(dateadd(d, -n + 1, getdate()) as date) d
from (
select n
, sum (case when datename(dw, dateadd(d, -n + 1, getdate())) not in ('Sunday', 'Saturday') then 1 end) over(order by n) wdn
from (
values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)
)t0(n)
) t
where wdn = 7
order by n;
Generally using on-the-fly tally for a #n -th day
declare #n int = 24;
with t0(n) as (
select n
from (
values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
) t(n)
), tally as (
select top(#n + (#n/5 +1)*2) row_number() over(order by t1.n) n
from t0 t1, t0 t2, t0 t3
)
select top(1) cast(dateadd(d, -n + 1, getdate()) as date) d
from (
select n
, sum (case when datename(dw, dateadd(d, -n + 1, getdate())) not in ('Sunday', 'Saturday') then 1 end) over(order by n) wdn
from tally
) t
where wdn = #n
order by n;
You can use CTE to mark target dates and then delete all the others from the table as follows:
; With CTE As (
Select [Date], Row_number() Over (Order by [Date] Desc) As Num
From tbl
Where DATEPART(weekday, [Date]) Not In (6,7)
)
Delete From tbl
Where [Date] Not In (Select [Date] From CTE Where Num<=7)
If the number of business days in the table may be less than 7 and you need to bring the total number of days to 7 by adding days off, try this:
Declare #n Int = 7
; With CTE As (
Select [Date], IIF(DATEPART(weekday, [Date]) In (6,7), 0, 1) As IsBusinessDay
From tbl
)
Delete From tbl
Where [Date] Not In (Select Top(#n) [Date] From CTE Order By IsBusinessDay Desc, [Date] Desc)
If there is only one date for each day, you can simply do this:
SELECT TOP 7 [Date] FROM Table1
WHERE
[Date] < GETDATE() AND DATENAME(weekday, [DATE]) NOT IN ('Saturday', 'Sunday')
ORDER BY
[DATE] DESC

sql dates quater of specific year

I am trying to create a report that gives me number to an event that occurred in the week, month and quarter of a specific date.
I have been able to so so for weeks and months but having issue with quarter. I want results for quarter of that specific year- like in the example below for 2016 only.
For example
declare #date date set #date = '2016/02/30'
select case_id, event_date
from #total
WHERE datepart(quarter, event_DATE) = datepart(quarter, #date)
order by 2
when I use this code it gives me result for not only 2016 but also for same quater of 2015,2014 (previous years).
case_id event_date
1234 1986-02-06
5567 2014-01-04
3456 2015-03-11
6378 2016-02-23
4789 2016-02-06
6782 2016-01-04
2346 2016-03-11
9098 2016-02-23
what I want: only for 2016 and not previous years.
case_id event_date
4789 2016-02-06
6782 2016-01-04
2346 2016-03-11
9098 2016-02-23
You could try adding a condition for the year:
[...] AND datepart(year, event_DATE) = datepart(year, #date)
You query would look something like
SELECT case_id, event_date
FROM #total
WHERE datepart(quarter, event_DATE) = datepart(quarter, #date)
AND datepart(year, event_DATE) = datepart(year, #date)
ORDER BY 2
declare #date date set #date = '2016/02/30'
select case_id, event_date
from #total
WHERE datepart(quarter, event_DATE) = datepart(quarter, #date)
AND datepart(YYYY,event_DATE) = '2016'
order by 2

How to get sum by MonthYear in sql?

I have a table like this
id Date Amount
1 2016-09-29 09:25:37.000 25.13
2 2016-08-01 17:20:39.000 598.00
3 2016-09-29 09:24:47.000 15.60
4 2016-07-28 17:50:11.000 61.80
5 2016-07-28 17:53:56.000 31.40
6 2016-07-22 10:40:27.000 74.16
I'm trying to get two columns like this,
MonthYear Total
Sep 2016 40.73
Aug 2016 598.00
Jul 2016 167.36
But, I want to get most recent year and month to top.
Try this sql,
SELECT CONVERT(CHAR(4), Date, 100) + CONVERT(CHAR(4), Date, 120)
AS MonthYear, SUM(Amount)
AS Total,
CAST(CONVERT(varchar(4), Date, 120) AS int)
AS Year, DATEPART(m, Date) As Month
FROM your_table
GROUP BY CONVERT(CHAR(4), Date, 100) + CONVERT(CHAR(4), Date,120),CAST(CONVERT(varchar(4), Date, 120) AS int), DATEPART(m, Date)
ORDER BY Year DESC, Month DESC
Just an other perspective.
Query
SELECT t.[MonthYear], SUM(t.[Amount]) AS [Total] FROM(
SELECT RIGHT((CONVERT(VARCHAR(11), [Date], 106)), 8) as [MonthYear], [Amount]
FROM [your_table_name]
)t
GROUP BY t.[MonthYear];
Try below
SELECT Datename(MONTH, [Date]) month_name,
Year([Date]) year,
Sum([Amount]),
Month([date]) month_no
FROM #Table1
GROUP BY Datename(MONTH, [Date]),
Year([Date]),
Month([date])
ORDER BY Month([date]) DESC,
Year([Date]),
Datename(MONTH, [Date])

OrderBy date but containing recors from "half" the day before

SELECT cast(Ord.regdate AS date) AS Date,
COUNT(Ord.Ordernumber) AS [Backlog of line],
(SELECT CASE
WHEN CAST(SUM(Ord.Qty) AS INT) IS NULL THEN 0
ELSE CAST(SUM(Ord.Qty) AS INT)
END) AS [Backlog of Qty]
FROM Orders [Ord]
WHERE Ord.regdate < CAST(CAST(CAST(DATEADD(DAY,-1,GETDATE()) AS date) AS varchar(10)) + ' 12:00' AS datetime)
GROUP BY cast(Ord.regdate AS date)
ORDER BY cast(Ord.regdate AS date) DESC
Date : Backlog of line : Backlog of Qty
2015-09-20 : 10 : 50
2015-09-21 : 5 : 25
The problem here is that when we get to next day... the 21 will get more records if the are orders that are done after 12:00 the 2015-09-21...
When we run this it just takes the records that are older then 12:00 the day before and groups them by date.
My Question is..
I want the date 2015-09-22 to show and have the records after 12:00 from 2015-09-21 until 12:00 the 2015-09-22... and so an
This should works. It shifts regdate by 12 hours first.
SELECT Ord.regdate AS Date,
COUNT(Ord.Ordernumber) AS [Backlog of line],
(SELECT CASE
WHEN CAST(SUM(Ord.Qty) AS INT) IS NULL THEN 0
ELSE CAST(SUM(Ord.Qty) AS INT)
END) AS [Backlog of Qty]
FROM (
Select Ordernumber, Qty, CAST(DATEADD(HOUR, 12, regdate) as date) as regdate
From Orders
WHERE regdate < CAST(CAST(CAST(DATEADD(DAY,-1,GETDATE()) AS date) AS varchar(10)) + ' 12:00' AS datetime)
) [Ord]
GROUP BY Ord.regdate
ORDER BY Ord.regdate DESC

Select sum of items based on their monthly entry date

I am trying to select sum of items based on their monthly entry date:
The Inventory table is as below:
EntryDate Items
1/1/2013 2
1/20/2013 5
1/23/2013 3
1/30/2013 2
2/4/2013 4
2/17/2013 34
The desired output with Total row added:
EntryDate Items
1/1/2013 2
1/20/2013 5
1/23/2013 3
1/30/2013 2
**Total 12**
2/4/2013 4
2/17/2013 34
**Total 38**
Below is my attempt. I am trying to do this using rollup but its counting all items at once and not by monthly basis, how to achieve this:
Select Convert(date, EntryDate) AS [DATE],SUM(Items) AS Total,
Case WHEN GROUPING(Items) = 1 THEN 'Rollup'
Else Status end AS Total From [Inventory] Group by Convert(date, EntryDate) WITH
Rollup
If you actually want results like your example, you can use the following:
SELECT EntryDate, Items
FROM (SELECT YEAR(EntryDate)'Year_',MONTH(EntryDate)'Month_',CAST(EntryDate AS VARCHAR(12))'EntryDate',Items,1 'sort'
FROM Inventory
UNION ALL
SELECT YEAR(EntryDate)'Year_',MONTH(EntryDate)'Month_','Total',SUM(Items)'Items',2 'sort'
FROM Inventory
GROUP BY YEAR(EntryDate),MONTH(EntryDate)
)sub
ORDER BY Year_,Month_,sort
Demo: SQL Fiddle
Try this, it will give you the month total in a new column, it will also work when your dates stretch over more than 1 year
SELECT EntryDate, Items,
SUM(Items) OVER (partition by dateadd(month, datediff(month, 0, entrydate), 0)) Total
FROM [Inventory]
Result:
EntryDate Items Total
2013-01-01 2 12
2013-01-20 5 12
2013-01-23 3 12
2013-01-30 2 12
2013-02-04 4 38
2013-02-17 34 38
DATEPART will do try this,
SELECT DATEPART(month, EntryDate) AS 'Month Number',sum(items1) FROM ITEMS
GROUP BY DATEPART(month, EntryDate)
# sqlfiddle
Try:
select entryDate, Items, sum(Items)
from (select entryDate,Items, to_date(entry_date, 'mm/yyyy') month_date from Inventory)
group by month_date
Here's a perfect solution for you
select isnull(cast(DATEFROMPARTS(year,month,day) as varchar),'Total'),
items
from ( SELECT datepart(yyyy,EntryDate) year,
DATEPART(mm, EntryDate) month,
DATEPART(dd, EntryDate) day,
sum(items) items
From Inventory
GROUP BY
ROLLUP (datepart(yyyy,EntryDate),
DATEPART(mm, EntryDate),
DATEPART(dd, EntryDate)
)
) a
where a.year is not null
and a.month is not null;
Demo HERE