SQL group by days interval - mysql

I have a sample table here with the following columns and sample records. I want to be able to sum my column cases using with a specific date range (the helper column).
I want to get my results this way:
Sum all cases WHERE date range is in between 2022-03-23 - 2022-04-01 and so on.
date range
Sum of Cases
2022-03-23-2022-04-01
5 (sample result only)
2022-03-24-2022-04-02
9 (sample result only)
The logic of the date range is always n - n9 days.
I 've tried this type of query but it does not work, it there a way for me to get this without have to use a query to create another column?
SELECT Date,
sum([QUERY 1]) as "Reports 7 days prev",
sum ([QUERY 2]) as "Reports 7 days after"
FROM REPORTS
GROUP BY Date
Data:
Date
BuyerID
Cases
Helper (Date Range)
4/1/2022
20001
2
2022-03-23-2022-04-01
4/1/2022
20001
1
2022-03-23-2022-04-01
4/2/2022
20002
3
2022-03-24-2022-04-02
4/5/2022
20003
5
2022-03-27-2022-04-05
4/7/2022
20004
6
2022-03-29-2022-04-07
4/7/2022
20005
9
2022-03-29-2022-04-07

Are you looking to get total cases for last X number of days? What does your initial data look like?
you can try something like:
Step 1: You aggregate all the cases for each date.
WITH CASES_AGG_BY_DATE AS
(
SELECT Date,
SUM(Cases) AS Total_Cases
FROM REPORTS
GROUP BY Date
),
Step 2: you aggregate the last 7 days rolling cases sum for each date
LAST_7_DAY_AGG AS
(
SELECT Date, SUM(Total_Cases) OVER(ORDER BY Date ASC ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) AS sum_of_cases,
LAG(Date, 7) AS 7th_day
FROM CASES_AGG_BY_DATE
)
Step 3: create final output and concatenate date and 7th day before that
SELECT Date, CONCAT(Date, "-", 7th_day), sum_of_cases
FROM LAST_7_DAY_AGG;

Related

How to get date from week number and day in sql?

I have both the week number and their corresponding day of week(i.e. mon,tue,wed,.....) stored in tables.
The following code is supposed to return week number from date but I'm unable to turn this around
select WEEKOFYEAR(CURDATE())
My table:
RecordID|Record|WeekID|DayofWeek
--------------------------------
1 |text1 |43 |mon
2 |text2 |43 |tue
3 |text3 |44 |wed
Desired output:
RecordID|Record|Date
--------------------------------
1 |text1 |2019/10/30
2 |text2 |2019/10/31
3 |text3 |2019/11/01
I want to retrieve the date from them(assuming current year). Is it possible in sql or can it be done only on server side?
*Dates just for representation
This following sample script might help you. Hope all necessary values are available in your database and you have pass them to the function accordingly-
SELECT STR_TO_DATE('2013 10 Tuesday', '%X %V %W');
--2013 is the year value
--10 is the week number
--Tuesday is the day name
If you have all three values available in your table and run the STR_TO_DATE function providing appropriate values - this will return you a date like - "2013-03-12".
You can check the below script-
SELECT
STR_TO_DATE(concat('2019',' ', WeekID,' ', DayofWeek), '%X %V %W')
FROM (
SELECT 1 RecordID, 'text1' Record, 43 WeekID,'mon' DayofWeek UNION ALL
SELECT 2,'text2',43,'tue' UNION ALL
SELECT 3,'text3',44,'wed'
)A;
Your final query should be as below-
SELECT
STR_TO_DATE(concat('2019',' ', WeekID,' ', DayofWeek), '%X %V %W')
FROM your_table_name A;
Note: Year 2019 is fixed as this value is not available in your table. If available, you can also use that column dynamically as other columns are used.
Your question isn't completely clear.
I guess you have the columns
year with values like 2001
WeekID with values like 36
DayOfWeek with values like tue.
Then, you can use an expression like this to get the DATE value. MySQL has date format strings for week and weekday.
SELECT STR_TO_DATE (CONCAT(year, '/', week, '/', weekday), '%Y/%v/%a')
Here's a fiddle. https://www.db-fiddle.com/f/iGrnkM5WgWTVPxuqxfPxdK/0
But beware, the computation of week number is a business rule subject to local and international standards. Be sure to test with dates in the first few days of several different calendar years to make sure you understand your situation.
You can read about the choices for week computation here. You use WEEKOFYEAR() to retrieve the week number; that corresponds to the %v format specifier.
You cant get the date from just week number and day of week, you would need the year too.

How to sum order total amount by week

I am trying to retrieve last 3 months records. I need to sum order total amount by week. I have made following query.
select CONCAT("Week", WEEK(created_at)) as week_number, sum(total_cost)
from certified_diamond_orders
where created_at > 2016-11-22
and status = "delivered"
group by week("created_at")
But I am only getting one record with this. Infact my table has 2 years entries. Also I was trying to figure out how I can pull week start date and end date to diplay on my chart.
Any suggestions where I am making mistake?
week("created_at") looks like you're trying to determine the week of the string "created_at" rather than the column created_at. Which might explain why you're only getting one row in your result.
The date 2016-11-22 also looks suspiciously like a sum instead of a date (2016 - 11 - 22 = 1983 vs "2016-11-22"
Try this:
SELECT
CONCAT('Week', WEEK(created_at)) AS week_number,
SUM(total_cost)
FROM certified_diamond_orders
WHERE
created_at > '2016-11-22' AND
status = 'delivered'
GROUP BY WEEK(created_at)

Finding records in a range, rounding down when needed

This is a bit difficult to describe, and I'm not sure if this can be done in SQL. Using the following example data set:
ID Count Date
1 0 1/1/2015
2 3 1/5/2015
3 4 1/6/2015
4 3 1/9/2015
5 9 1/15/2015
I want to return records where the Date column falls into a range. But, if the "from" date doesn't exist in the table, I want to use the most recent date as my "From" select. For example, if my date range is between 1/5 and 1/9, I would expect to have records 2,3, and 4 returned. But, if I have a date range of 1/3 - 1/6 I want to return records 1,2,and 3. I want to include record 1 because, as 1/3 does not exist, I want the value of the Count that is rounded down.
Any thoughts on how this can be done? I'm using MySQL.
Basically, you need to replace the from date with the latest date before or on that date. Let me assume that the variables are #v_from and #v_to.
select e.*
from example e
where e.date >= (select max(e2.date) from example e2 where e2.date <= #v_from) and
e.date <= #v_to;
EDIT AFTER EDIT:
SELECT *
FROM TABLE
WHERE DATE BETWEEN (
SELECT Date
FROM TABLE
WHERE Date <= #Start
ORDER BY Date DESC
LIMIT 1
)
AND #End
Or
SELECT *
FROM TABLE
WHERE DATE BETWEEN (
SELECT MAX(Date)
FROM TABLE
WHERE Date <= #Start
)
AND #End

Using DatePart() with date ranges crossing the datepart boundary

I am currently trying to summarise some data tables into a report. Each record in the table consists of a date range, something like this:
StartDate EndDate
--------------------
13/04/13 15/04/13
17/04/13 24/04/13
28/04/13 03/05/13
05/05/13 10/05/13
Assuming the date ranges signify something like days of leave, I want to be able to calculate the total amount of days of leave per month. I came across the DatePart function which seems to work apart from one edge case: when the date range crosses a month boundary. Since the DatePart function returns the month for one given date, I am no longer able to use that to determine the amount of days of leave for that edge case record (in the example above it is record 3), since it applies to two separate months.
Ideally I want my final table to look like:
Month #OfDays
--------------------
4 11 (1st record - 2, 2nd record - 7, 3rd record - 2)
5 8 (3rd record - 3, 4th record - 5)
I've considered some messy options, such as populating a temporary table having each record signifying a different day and then doing a query on that, but I am not sure how this ties in with a report. Right now my report record source is the (incorrect) query, is it possible to have a record source as a VBA function that returns a recordsource?
Another thing I thought was to possibly to have an initial query that splits up any edge cases into two seperate records, where the date range only covers one month, and then use that for my final grouping query. Is that even possible?
I feel there may be a much simpler solution to this problem yet I can't see it.
If anyone has any ideas it would be much appreciated!
To accomplish your task using Access queries you will need to create a table named [Numbers] with a single Number (Long Integer) column named [n] containing the numbers 1, 2, 3, ... up to the highest year you expect to be working with. I created mine as follows
n
----
1
2
3
...
2499
2500
You'll also need to paste the following VBA function into an Access Module
Public Function IsValidDayOfYear(YearValue As Long, DayValue As Long) As Boolean
Dim IsLeapYear As Boolean
If (YearValue Mod 400) = 0 Then
IsLeapYear = True
ElseIf (YearValue Mod 100) = 0 Then
IsLeapYear = False
ElseIf (YearValue Mod 4) = 0 Then
IsLeapYear = True
Else
IsLeapYear = False
End If
IsValidDayOfYear = (DayValue <= IIf(IsLeapYear, 366, 365))
End Function
Let's assume that your source table is called [DateRanges]. We'll start by creating a query that generates every day of the year for each year represented in the source table. The trick here is that DateSerial() "rolls over" month boundaries, so
DateSerial(2013, 1, 32) = #2013-02-01#
and
DateSerial(2013, 1, 234) = #2013-08-22#
SELECT DateSerial(yr.n, 1, dy.n) AS [Date]
FROM Numbers yr, Numbers dy
WHERE
(
yr.n
BETWEEN (SELECT MIN(DatePart("yyyy", DateRanges.StartDate)) FROM DateRanges)
AND (SELECT MAX(DatePart("yyyy", DateRanges.EndDate)) FROM DateRanges)
)
AND (dy.n < 367) AND IsValidDayOfYear(yr.n, dy.n)
For your sample data, that query returns all days in 2013.
Let's save that query as [AllDays]. Now we can use it to extract the individual days for each date range (omitting StartDate so the final counts match yours in the question)
SELECT [Date] FROM AllDays
WHERE EXISTS
(
SELECT * FROM DateRanges
WHERE AllDays.[Date] BETWEEN DateAdd("d", 1, DateRanges.StartDate) AND DateRanges.EndDate
)
That returns the individual days corresponding to each range, i.e.,
Date
----------
2013-04-14
2013-04-15
2013-04-18
2013-04-19
2013-04-20
2013-04-21
2013-04-22
2013-04-23
2013-04-24
2013-04-29
2013-04-30
2013-05-01
2013-05-02
2013-05-03
2013-05-06
2013-05-07
2013-05-08
2013-05-09
2013-05-10
We can save that query as [RangeDays] and then use it to calculate our counts by month...
SELECT DatePart("m", [Date]) AS [Month], COUNT(*) AS NumOfDays
FROM RangeDays
GROUP BY DatePart("m", [Date])
...returning
Month NumOfDays
----- ---------
4 11
5 8

Date ranking in Access SQL?

I have a query pulling the last six months of data from a table which has a column, UseDates (so as of today in June, this table has dates for December 2011 through May 2012).
I wish to include a "rank" column that associates a 1 to all December dates, 2 to all January dates, etc -- up to 6 for the dates corresponding one month prior. If I were to open up this query a month from now, the 1 would then be associated with January, etc.
I hope this makes sense!
Example, if I ran the query right now
UseDate Rank
12/31/2011 1
1/12/2012 2
...
5/23/2012 6
Example, if I ran the query in August:
UseDate Rank
2/16/2012 1
3/17/2012 2
...
7/21/2012 6
Example, if I ran the query in March:
UseDate Rank
9/16/2011 1
10/17/2011 2
...
2/24/2012 6
SELECT
UseDates,
DateDiff("m", Date(), UseDates) + 7 AS [Rank]
FROM YourTable;
You can use month function for UseDates and subtract it from the result of now function. If it goes negative, just add 12. Also you may want to add 1 since you start with 1 and not 0. Apparently it should work for half a year date ranges. You'll get into trouble when you need to "rank" several years.
You can rank with a count.
SELECT
Table.ADate,
(SELECT Count(ADate)
FROM Table b
WHERE b.ADate<=Table.ADate) AS Expr1
FROM Table3;
You have to repeat any where statement in the subquery:
SELECT
Table.ADate,
(SELECT Count(ADate)
FROM Table b
WHERE b.ADate<=Table.ADate And Adate>#2012/02/01#) AS Expr1
FROM Table3
WHERE Adate>#2012/02/01#