Calculate the number of records for each date between 2 dates
No need to reinvent the wheel - there are many examples of recursive CTE calendar tables out there, similar to below.
DECLARE @StartDate date = '01-Nov-2020', @EndDate date = '22-Feb-2021';
WITH Date_Range_T (d_range) AS (
SELECT @StartDate AS d_range
UNION ALL
SELECT DATEADD(DAY, 1, d_range)
FROM Date_Range_T
WHERE DATEADD(DAY, 1, d_range) < @EndDate
)
SELECT d_range, COUNT(Id) AS Total
FROM Date_Range_T
LEFT JOIN tbl_Support_Requests R ON R.CreatedDate = d_range
GROUP BY d_range
ORDER BY d_range ASC
-- Set to the max number of days you require
OPTION (MAXRECURSION 366);
Comments:
- Why use a
datetime2
for adate
? - Do you definitely want
<
the end date or<=
? - Are you familiar with how
between
works - its not always intuitive. - Alias all tables for better readability.
- Semi-colon terminate all statements.
- Consistent casing makes the query easier to read.
- Use an unambiguous date format for date strings.
Count work days between two dates
For workdays, Monday to Friday, you can do it with a single SELECT, like this:
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = '2008/10/01'
SET @EndDate = '2008/10/31'
SELECT
(DATEDIFF(dd, @StartDate, @EndDate) + 1)
-(DATEDIFF(wk, @StartDate, @EndDate) * 2)
-(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)
If you want to include holidays, you have to work it out a bit...
SQL Server query to calculate daily “carrying” open orders
This should give you the desired output. This query assumes you have a distinct listing of dates to query against.
The portion you had the most trouble with, the carry over, uses a FROM
statement that references two datasets. This is different from a JOIN
and is done by referencing two tables and separating them with a ,
. This will in turn create a query where each date in the dates_table
gets assigned the entire dataset from the orders
table. In order to determine carry over a WHERE
statement is used to filter the copied orders table and a GROUP BY
is used count each filtered order. After that a LEFT JOIN
is used to pull the results by date to the date_table
. Feel free to leave a comment if you want more explanation.
SQL with Dates Table this table is named dates_table
in the query below
SELECT
dates.date,
iif(carry_over.count IS NULL, 0, carry_over.count) AS carry_over,
iif(fulfilled.count IS NULL, 0, fulfilled.count) AS fulfilled,
iif(not_fulfilled.count IS NULL, 0, not_fulfilled.count) AS not_fulfilled
FROM dates_table AS dates
/* Fulfilled that day */
LEFT JOIN
(
SELECT
dateadd(d, datediff(d,0, fulfilled_date), 0) AS date,
COUNT(dateadd(d, datediff(d,0, fulfilled_date), 0)) AS count
FROM orders
GROUP BY dateadd(d, datediff(d,0, fulfilled_date), 0)
) AS fulfilled
ON dates.date = fulfilled.date
/* Not Fulfilled that day */
LEFT JOIN
(
SELECT
dateadd(d, datediff(d,0, order_date), 0) AS date,
COUNT(dateadd(d, datediff(d,0, order_date), 0)) AS count
FROM orders
WHERE (dateadd(d, datediff(d,0, order_date), 0) <> dateadd(d, datediff(d,0, fulfilled_date), 0)) OR fulfilled_date IS NULL
GROUP BY dateadd(d, datediff(d,0, order_date), 0)
) AS not_fulfilled
ON dates.date = not_fulfilled.date
/* Carry Over */
LEFT JOIN
(
SELECT
full_data.date,
COUNT(full_data.order_date) AS count
FROM
(
SELECT
dates.date AS date,
order_dates.order_date AS order_date,
order_dates.fulfilled_date AS fulfilled_date
FROM dates_table AS dates,
/* Allocate all dates to key of dates, filter out what is relevant in where */
(
SELECT
dateadd(d, datediff(d,0, order_date), 0) AS order_date,
iif(fulfilled_date IS NULL, NULL, dateadd(d, datediff(d,0, fulfilled_date), 0)) AS fulfilled_date
FROM orders
) AS order_dates
) AS full_data
/* Determines what is carry over */
WHERE (full_data.date < full_data.fulfilled_date OR full_data.fulfilled_date IS NULL) AND full_data.date >= full_data.order_date
GROUP BY full_data.date
) AS carry_over
ON dates.date = carry_over.date
rextester
Edit: Added field names for final query as they were all labeled count before
Edit: Added another query assuming you have a table of dates and # for orders table
Edit: Removed query without date_table, count on carry_over now done on order_date as was not counting nulls, for fulfilled that day numbers now pulls fulfilled_date instead of order_date
SQL Query to Count Items Within Date Range?
Below is a query returning consecutive dates between given date and given date - 5 days. You may use CURRENT DATE
instead of this constant of course.
WITH T (DT) AS
(
VALUES DATE('2020-02-13') - 5 DAYS
UNION ALL
SELECT DT + 1 DAY
FROM T
WHERE DT < DATE('2020-02-13')
)
SELECT DT FROM T;
The result is:
|DT |
|----------|
|2020-02-08|
|2020-02-09|
|2020-02-10|
|2020-02-11|
|2020-02-12|
|2020-02-13|
Further usage of such a "virtual table" is obvious: you may LEFT JOIN
it with your base table on B.START_DATE < DEC(TO_CHAR(T.DT, 'YYYYMMDD'), 8) AND DEC(TO_CHAR(T.DT, 'YYYYMMDD'), 8) <= B.END_DATE
grouping the result by T.DT
.
SQL : given a year and month how can I count the number of orders per WEEK
You can use CASE
to get a single week number then group by that number.
Use CROSS APPLY (VALUES
to avoid repeating code
SELECT
v.WeekNumber,
TotalOrders = COUNT(*)
FROM
dbo.Orders
CROSS APPLY (VALUES (
CASE WHEN DateCreated >= DATEFROMPARTS(@year, @month, 1) AND DateCreated < DATEFROMPARTS(@year, @month, 8)
THEN 1
WHEN DateCreated >= DATEFROMPARTS(@year, @month, 8) AND DateCreated < DATEFROMPARTS(@year, @month, 15)
THEN 2
WHEN DateCreated >= DATEFROMPARTS(@year, @month, 15)) AND DateCreated < DATEFROMPARTS(@year, @month, 22)
THEN 3
WHEN DateCreated >= DATEFROMPARTS(@year, @month, 22)) AND DateCreated < DATEFROMPARTS(@year, @month, 29)
THEN 4
ELSE 5
END
)) v(WeekNumber)
WHERE DateCreated >= DATEFROMPARTS(@year, @month, 1)
AND DateCreated < DATEADD(month, 1, DATEFROMPARTS(@year, @month, 1))
GROUP BY
v.WeekNumber;
Note the use of >= AND <
for a half-open interval. This ensure that the whole of the last day is included.
Related Topics
Why Can't I Refer to a Column Alias in the Order by Using Case
Calculate the Last Day of the Prior Quarter
Redshift: Executing a Dynamic Query from a String
How to Use Like Condition in SQL with Numeric Field
Spark:Failure: ''Union'' Expected But '(' Found
How to Best Organize the Inner Joins in (Select) Statement
Is This Date Comparison Condition Sarg-Able in SQL
Creating a Trigger to Only Run When a New Table Is Being Created
Postgresql - Replace HTML Entities
How to Display a Default Value When No Match Found in a Query
Convert Nvarchar to Datetime in SQL Server 2008
Activerecord Find - Skipping Records or Getting Every Nth Record
On Delete Cascade for Self-Referencing Table
SQL Query - Select * from View or Select Col1, Col2, ... Coln from View
Access Db Update One Table with Value from Another
Create a Unique Index on a Non-Unique Column
Redshift Split Single Dynamic Column into Multiple Rows in New Table