SSRS Report per month with 3 Columns count - sql

I am working on SSRS report where I have 3 dates to deal with and get the count of each column per month starting September. Here is an image of what I am trying to achieve and I am not sure of what exactly I am missing in the Groupings. Any help would be really appreciated.
Query -
SELECT CONVERT(NVARCHAR(10), TableA.DueDate, 101) AS DueDate ,
CONVERT(NVARCHAR(10), TableB.DateFrom, 101) AS DateFrom ,
CONVERT(NVARCHAR(10), TableB.DateTo, 101) AS DateTo
FROM dbo.TableA
INNER JOIN dbo.TableB ON dbo.TableA.Id = dbo.TableB.TableAid
WHERE ( TableA.DueDate BETWEEN '2015-08-01'
AND '2016-07-30' )
AND ( TableB >= '08/01/2013' )
AND ( TableB <= '07/30/2014' )

Its a little ugly but will get you the intended results - Just paste your query inside the definition of the CTE -
WITH DateCTE AS (SELECT
DueDate, DateFrom, DateTo FROM DateTable)
SELECT MONTH, SUM(DueDate), SUM(DateFROM), SUM(DateTo)
FROM (
SELECT DateName(month,DueDate) MONTH, Count(*) AS DueDate, 0 DateFROM , 0 DateTo
FROM DateCTE
GROUP BY DateName(month,DueDate)
UNION
SELECT DateName(month,DateFrom) MOntH, 0 AS DueDate, COUNT(*) DateFROM , 0 DateTo
FROM DateCTE
GROUP BY DateName(month,DateFrom)
UNION
SELECT DateName(month,DateTo) Month, 0 AS DueDate, 0 DateFROM , COUNT(*) Dateto
FROM DateCTE
GROUP BY DateName(month,DateTo)) UnionTable
GROUP BY MONTH
Heres the SQL fiddle - http://sqlfiddle.com/#!6/0a639/10

Ankit Khetan,
What you're displaying in your report layout is an SSRS MATRIX format (like excel). See if this works you instead of using a another query .... In your Select Statements extract the month number for each date variable. Then try to use these numbers as your columns. and use your Date variables as your rows in the matrix layout.

Related

Finding Active Clients By Date

I'm having trouble writing a recursive function that would count the number of active clients on any given day.
Say I have a table like this:
Client
Start Date
End Date
1
1-Jan-22
2
1-Jan-22
3-Jan-22
3
3-Jan-22
4
4-Jan-22
5-Jan-22
5
4-Jan-22
6-Jan-22
6
7-Jan-22
9-Jan-22
I want to return a table that would look like this:
Date
NumActive
1-Jan-22
2
2-Jan-22
2
3-Jan-22
3
4-Jan-22
4
5-Jan-22
4
6-Jan-22
3
7-Jan-22
3
8-Jan-22
3
9-Jan-22
4
Is there a way to do this? Ideally, I'd have a fixed start date and go to today's date.
Some pieces I have tried:
Creating a recursive date table
Truncated to Feb 1, 2022 for simplicity:
WITH DateDiffs AS (
SELECT DATEDIFF(DAY, '2022-02-02', GETDATE()) AS NumDays
)
, Numbers(Numbers) AS (
SELECT MAX(NumDays) FROM DateDiffs
UNION ALL
SELECT Numbers-1 FROM Numbers WHERE Numbers > 0
)
, Dates AS (
SELECT
Numbers
, DATEADD(DAY, -Numbers, CAST(GETDATE() -1 AS DATE)) AS [Date]
FROM Numbers
)
I would like to be able to loop over the dates in that table, such as by modifying the query below for each date, such as by #loopdate. Then UNION ALL it to a larger final query.
I'm now stuck as to how I can run the query to count the number of active users:
SELECT
COUNT(Client)
FROM clients
WHERE [Start Date] >= #loopdate AND ([End Date] <= #loopdate OR [End Date] IS NULL)
Thank you!
You don't need anything recursive in this particular case, you need as a minimum a list of dates in the range you want to report on, ideally a permanent calendar table.
for purposes of demonstration you can create something on the fly, and use it like so, with the list of dates something you outer join to:
with dates as (
select top(9)
Convert(date,DateAdd(day, -1 + Row_Number() over(order by (select null)), '20220101')) dt
from master.dbo.spt_values
)
select d.dt [Date], c.NumActive
from dates d
outer apply (
select Count(*) NumActive
from t
where d.dt >= t.StartDate and (d.dt <= t.EndDate or t.EndDate is null)
)c
See this Demo Fiddle

SQL How can I get a count of messages going out by month

I have a table that sends out messages, I would like to get a total count of the messages that have been going out month by month over the last year . I am new to SQL so I am having trouble with it . I am using MSSQL 2012 this is my sql
SELECT sentDateTime, MessageID, status AS total, CONVERT(NVARCHAR(10), sentDateTime, 120) AS Month
FROM MessageTable
WHERE CAST(sentDateTime AS DATE) > '2017-04-01'
GROUP BY CONVERT(NVARCHAR(10), sentDateTime, 120), sentDateTime, MessageID, status
ORDER BY Month;
I think the month() and year() functions are more convenient than datepart() for this purpose.
I would go for:
select year(sentDateTime) as yr, month(sentDateTime) as mon, count(*)
from MessageTable
where sentDateTime > '2017-04-01'
group by year(sentDateTime), month(sentDateTime)
order by min(sentDateTime);
Additional notes:
Only include the columns in the select that you care about. This would be the ones that define the month and the count.
Only include the columns in the group by that you care about. Every combination of the expressions in the group by found in the data define a column.
There is no need to convert sentDateTime to a date explicitly for the comparison.
The order by orders the results by time. Using the min() is a nice convenience.
Including the year() makes sure you don't make a mistake -- say by including data from 2018-04 with 2017-04.
-- this selects the part of the date you are looking for, replace this with the date format you are using, this should give you what you are looking for
SELECT DATEPART(mm, GETDATE())
SELECT COUNT(DATEPART(mm, sentDateTime)), MessageID, status
From MessageTable where Cast(sentDateTime as date) > '2017-04-01'
group by DATEPART(mm, sentDateTime), MessageID, status
order by DATEPART(mm, sentDateTime)
You can group by the month number of the sentDateTime with the function DATEPART(MONTH, sentDateTime). The next select will also yield results if no message was sent for a particular month (total = 0).
;WITH PossibleMonths AS
(
SELECT
M.PossibleMonth
FROM
(VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) M(PossibleMonth)
),
MonthTotals AS
(
select
COUNT(1) AS Total,
DATEPART(MONTH, sentDateTime) [Month]
From
MessageTable
where
Cast(sentDateTime as date) > '2017-04-01'
group by
DATEPART(MONTH, sentDateTime)
)
SELECT
P.PossibleMonth,
Total = ISNULL(T.Total, 0)
FROM
PossibleMonths AS P
LEFT JOIN MonthTotals AS T ON P.PossibleMonth = T.Month

How To Select Records in a Status Between Timestamps? T-SQL

I have a T-SQL Quotes table and need to be able to count how many quotes were in an open status during past months.
The dates I have to work with are an 'Add_Date' timestamp and an 'Update_Date' timestamp. Once a quote is put into a 'Closed_Status' of '1' it can no longer be updated. Therefore, the 'Update_Date' effectively becomes the Closed_Status timestamp.
I'm stuck because I can't figure out how to select all open quotes that were open in a particular month.
Here's a few example records:
Quote_No Add_Date Update_Date Open_Status Closed_Status
001 01-01-2016 NULL 1 0
002 01-01-2016 3-1-2016 0 1
003 01-01-2016 4-1-2016 0 1
The desired result would be:
Year Month Open_Quote_Count
2016 01 3
2016 02 3
2016 03 2
2016 04 1
I've hit a mental wall on this one, I've tried to do some case when filtering but I just can't seem to figure this puzzle out. Ideally I wouldn't be hard-coding in dates because this spans years and I don't want to maintain this once written.
Thank you in advance for your help.
You are doing this by month. So, three options come to mind:
A list of all months using left join.
A recursive CTE.
A number table.
Let me show the last:
with n as (
select row_number() over (order by (select null)) - 1 as n
from master..spt_values
)
select format(dateadd(month, n.n, q.add_date), 'yyyy-MM') as yyyymm,
count(*) as Open_Quote_Count
from quotes q join
n
on (closed_status = 1 and dateadd(month, n.n, q.add_date) <= q.update_date) or
(closed_status = 0 and dateadd(month, n.n, q.add_date) <= getdate())
group by format(dateadd(month, n.n, q.add_date), 'yyyy-MM')
order by yyyymm;
This does assume that each month has at least one open record. That seems reasonable for this purpose.
You can use datepart to extract parts of a date, so something like:
select datepart(year, add_date) as 'year',
datepart(month, date_date) as 'month',
count(1)
from theTable
where open_status = 1
group by datepart(year, add_date), datepart(month, date_date)
Note: this counts for the starting month and primarily to show the use of datepart.
Updated as misunderstood the initial request.
Consider following test data:
DECLARE #test TABLE
(
Quote_No VARCHAR(3),
Add_Date DATE,
Update_Date DATE,
Open_Status INT,
Closed_Status INT
)
INSERT INTO #test (Quote_No, Add_Date, Update_Date, Open_Status, Closed_Status)
VALUES ('001', '20160101', NULL, 1, 0)
, ('002', '20160101', '20160301', 0, 1)
, ('003', '20160101', '20160401', 0, 1)
Here is a recursive solution, that doesn't rely on system tables BUT also performs poorer. As we are talking about months and year combinations, the number of recursions will not get overhand.
;WITH YearMonths AS
(
SELECT YEAR(MIN(Add_Date)) AS [Year]
, MONTH(MIN(Add_Date)) AS [Month]
, MIN(Add_Date) AS YMDate
FROM #test
UNION ALL
SELECT YEAR(DATEADD(MONTH,1,YMDate))
, MONTH(DATEADD(MONTH,1,YMDate))
, DATEADD(MONTH,1,YMDate)
FROM YearMonths
WHERE YMDate <= SYSDATETIME()
)
SELECT [Year]
, [Month]
, COUNT(*) AS Open_Quote_Count
FROM YearMonths ym
INNER JOIN #test t
ON (
[Year] * 100 + [Month] <= CAST(FORMAT(t.Update_Date, 'yyyyMM') AS INT)
AND t.Closed_Status = 1
)
OR (
[Year] * 100 + [Month] <= CAST(FORMAT(SYSDATETIME(), 'yyyyMM') AS INT)
AND t.Closed_Status = 0
)
GROUP BY [Year], [Month]
ORDER BY [Year], [Month]
Statement is longer, also more readable and lists all year/month combinations to date.
Take a look at Date and Time Data Types and Functions for SQL-Server 2008+
and Recursive Queries Using Common Table Expressions

How can I sum values per day and then plot them on calendar from start date to last date

I have a table, part of which is given below. It contain multiple values (durations) per day. I need two things 1) addition of durations per day. 2) plotting them on calendar in such a way that startdate is first_date from the table and last_date is Last_update from the table. I want to mention 0 for which date there is no duration. I think it will something like below but need help.
;WITH AllDates AS(
SELECT #Fromdate As TheDate
UNION ALL
SELECT TheDate + 1
FROM AllDates
WHERE TheDate + 1 <= #ToDate
)SELECT UserId,
TheDate,
COALESCE(
SUM(
-- When the game starts and ends in the same date
CASE WHEN DATEDIFF(DAY, GameStartTime, GameEndTime) = 0
Here is what I am looking for
Another way to generate the date range you are after would be something like .....
;WITH DateLimits AS
(
SELECT MIN(First_Date) FirstDate
,MAX(Last_Update) LastDate
FROM TableName
),
DateRange AS
(
SELECT TOP (SELECT DATEDIFF(DAY,FirstDate,LastDate ) FROM DateLimits)
DATEADD(DAY
,ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
, (SELECT FirstDate FROM DateLimits)
) AS Dates
FROM master..spt_values a cross join master..spt_values b
)
SELECT * FROM DateRange --<-- you have the desired date range here
-- other query whatever you need.

SQL Server return date range and associated value between specified values

I'm fetching records from the DB using a query like:
SELECT date as "Date", count(date) as "NumIssues"
FROM Issues
WHERE Date BETWEEN '2015-03-25' AND '2015-03-28'
GROUP BY date
ORDER BY date;
The query works fine but I need it to fetch results even if there are no values for the specified date and return 0 for the NumIssues value.
Would the best way to go about this would be to put in case statements? Thanks in advance!
;WITH dates ( "Date" ) AS (
SELECT CONVERT( DATE, '2015-03-25' )
UNION ALL
SELECT DATEADD( DAY, 1, Date )
FROM dates
WHERE DATEADD( DAY, 1, Date ) < '2015-03-28'
)
SELECT d.Date
, COUNT(date) as "NumIssues"
FROM dates AS d
LEFT JOIN Issues AS i
ON i.date = d.Date
GROUP BY d.date
ORDER BY d.date;