SQL group dates by month - sql

I have a query that returns expiration dates:
SELECT ci.accountnumber
, ci.accountname
, cvu.ExpirationDate
FROM dbo.clientinfo ci
INNER JOIN clientvehicleunit cvu ON ci.clientid = cvu.clientid
The expiration dates can be anytime during any month and any year.
I need to return counts of how many units are due to expire within each month for a 12 month period....
I have no idea how I would do this?

You can do something like this:
e.g. how many units are due to expire in 2012:
SELECT MONTH(cvu.ExpirationDate) AS Mnth, YEAR(cvu.ExpirationDate) AS Yr,
COUNT(*) AS DueToExpire
FROM clientvehicleunit cvu
WHERE cvu.ExpirationDate >= '20120101' AND cvu.ExpirationDate < '20130101'
GROUP BY MONTH(cvu.ExpirationDate), YEAR(cvu.ExpirationDate)

I need to return counts of how many units are due to expire within each month for a 12 month period.
If you mean from the current month forward, then
SELECT
[YYYY.MM] = CONVERT(varchar(7), cvu.ExpirationDate, 102),
CountInMonth = COUNT(*)
FROM dbo.clientinfo ci
JOIN clientvehicleunit cvu ON ci.clientid = cvu.clientid
WHERE cvu.ExpirationDate >= DATEADD(m, DATEDIFF(m,0,getdate()), 0)
AND cvu.ExpirationDate < DATEADD(m, DATEDIFF(m,0,getdate())+12, 0)
GROUP BY CONVERT(varchar(7), cvu.ExpirationDate, 102)
ORDER BY [YYYY.MM]
Note: The period is printed in the form [YYYY.MM], e.g. 2011.01

Related

Perform a monthly distinct beneficiary count between 1/1/2018 -12/31/2020 based on two date fields

Perform a monthly distinct beneficiary count between 1/1/2018 -12/31/2020 using Microsoft SQL Server.
Below is my code but I have to change it for every month, is there any way to group by each month from 2018 to 2020 with 2 different date fields?
SELECT COUNT(distinct BEN_ID)
FROM LDS_2017andbeyond
WHERE
[DTE_FIRST_SVC] between '2018-01-01' and '2018-01-31'
AND
[DTE_LAST_SVC] between '2018-01-01' and '2018-01-31'
One simple way to group dates on the same month is the EOMONTH function. It'll return the last day of the month for a date.
SELECT
FORMAT(EOMONTH([DTE_FIRST_SVC]), 'yyyy-MM') AS MONTH_FIRST_SVC
, FORMAT(EOMONTH([DTE_LAST_SVC]), 'yyyy-MM') AS MONTH_LAST_SVC
, COUNT(DISTINCT BEN_ID) AS TOTAL_UNIQUE_BEN_ID
FROM LDS_2017andbeyond
WHERE [DTE_FIRST_SVC] BETWEEN '2018-01-01' AND '2020-12-31'
AND [DTE_LAST_SVC] BETWEEN '2018-01-01' AND '2020-12-31'
GROUP BY EOMONTH([DTE_FIRST_SVC]), EOMONTH([DTE_LAST_SVC])
ORDER BY MONTH_FIRST_SVC DESC, MONTH_LAST_SVC DESC
One solution would be to use a recursive CTE. You start with an anchor query and union it to itself with a DATEADD function in the recursive portion. This solution will give you every month month, even if the count is 0, as opposed to just grouping on the data, which will omit any months that arn't present.
Something like:
WITH CTE_Date AS (
SELECT CAST('01/01/2018' AS DATE) AS GroupMonth -- Start Date. Set as far back as necessary. Can use a DATEADD() to make dynamic.
UNION ALL
SELECT DATEADD(month, 1, GroupMonth) AS GroupMonth
FROM CTE_Date
WHERE DATEADD(month, 1, GroupMonth) < '12/31/2020' -- End Date. Remove the where to go to current.
)
SELECT
COUNT(distinct BEN_ID),
CAST(MONTH(d.GroupMonth) AS VARCHAR(2)) + '-' + CAST(YEAR(d.GroupMonth) AS VARCHAR(4)) AS Dt
FROM
LDS_2017andbeyond lds
LEFT OUTER JOIN CTE_Date d ON
MONTH(lds.[DTE_FIRST_SVC]) = MONTH(d.GroupMonth)
AND
YEAR(lds.[DTE_LAST_SVC]) = YEAR(d.GroupMonth)
GROUP BY
CAST(MONTH(d.GroupMonth) AS VARCHAR(2)) + '-' + CAST(YEAR(d.GroupMonth) AS VARCHAR(4))

How to subtract an offset to dates generated through a recursive CTE?

The query below uses a recursive CTE to generate days if there is no data for that specific day. I want to group the daily downtime total starting at 7:15 the previous day until 7:15 the next day and do it over a month. This query works fine but I need to subtract DATEADD(minute, -(7 * 60 + 15) from each day.
WITH dates as (
SELECT CONVERT(date, 'Anydate') as dte
UNION ALL
SELECT DATEADD(day, 1, dte)
FROM dates
WHERE dte < 'Anydate + 1 month later'
)
SELECT CONVERT(datetime,d.dte), ISNULL(SUM(long_stop_minutes), 0) AS downtime
FROM dates d LEFT JOIN
long_stops_table b
ON CAST(t_stamp as DATE) = d.dte AND Type = 'downtime'
GROUP BY CONVERT(datetime, d.dte)
ORDER BY CONVERT(datetime, d.dte) ASC;
Just subtract the appropriate time units. Here is one way:
SELECT d.dte,
COALESCE(SUM(lst.long_stop_minutes), 0) AS downtime
FROM dates d LEFT JOIN
long_stops_table lst
ON CONVERT(date, DATEADD(minute, -(7 * 60 + 15), lst.t_stamp) = d.dte AND
lst.Type = 'downtime'
GROUP BY d.dte
ORDER BY d.dte ASC;
I see no reason to convert dates.dte to a datetime, so I just removed the conversion.

Comparing dates in SQL Server

I have a DateTime column named EXP_Date which contains date like this :
2014-07-13 00:00:00.000
I want to compare them, like this query :
SELECT COUNT(*)
FROM DB
WHERE ('2014-07-15' - EXP_DATE) > 1
I expect to see the number of customers who have their services expired for over a month.
I know this query wouldn't give me the correct answer, the best way was if I separate the Year / Month / Day into three columns, but isn't any other way to compare them as they are?
You can use DATEADD
SELECT COUNT(*)
FROM DB
where EXP_DATE < DATEADD(month, -1, GETDATE())
Try this
SELECT COUNT(*)
FROM DB
where DATEADD(month, -1, GETDATE()) > EXP_DATE
SELECT COUNT(EXPIRE)FROM
(Select CASE WHEN EXP_DATE < DATEADD(month, -1, GETDATE())THEN 1 ELSE 0 END)AS EXPIRE FROM DB
)tt
Another way using DATEDIFF
SET DATEFORMAT DMY --I like to use "dateformat"
SELECT COUNT(*)
FROM DB
WHERE (DATEDIFF(DAY,#EXP_DATE,GETDATE())) >= 30 --Remember, instead "Day" you can use week, month, year, etc
Syntax: DATEDIFF ( datepart , startdate , enddate )
Depart: year, quarter, month, day, week...
For more information you can visit MSDN

How To: Count widgets sold every 7 days for a period of a year

SELECT
CAST(CONVERT(varchar, W.CreateTS, 101)AS SMALLDATETIME) AS [SoldDate]
,COUNT(*) AS NumberOfWidgets
,FT.FormName
FROM tblWidget W
JOIN tblFormType FT ON (W.FormTypeID = FT.FormTypeID)
WHERE W.CreateTS >= DATEADD(YEAR, -1, #RunDate)
GROUP BY CAST(CONVERT(varchar, W.CreateTS, 101)AS SMALLDATETIME), FT.FormName
The current Code aggregates the amount of widgets sold per day and goes back year - 1 day. I need to find out how many are sold per 7 days.
Any help would be awesome.
SELECT
DATEPART(week, w.CreateTS) AS [SoldWeek]
,COUNT(*) AS NumberOfWidgets
,FT.FormName
FROM tblWidget W
JOIN tblFormType FT ON (W.FormTypeID = FT.FormTypeID)
WHERE W.CreateTS >= DATEADD(YEAR, -1, #RunDate)
GROUP BY DATEPART(week, w.CreateTS), FT.FormName

How can I count and group by between two date?

For example,
the start date = '20100530' and
the end date = '20100602'
How can I write a SQL to display the below result?
month: may, 2 days
month: June, 2 days
Use a recursive CTE to generate all of the dates between the start and end, and then do a simple group and count (caution, not tested, but should be close if not exactly right):
with dates (the_date) as (
select #start_date
UNION ALL
select dateadd(dd, 1, the_date) from dates where the_date <= #end_date
)
select
datepart(mm, the_date) month,
count(*) num_days
from
dates
group by
datepart(mm, the_date)
TBH, you really need to provide more schema and information about the source data. However, given what little we know, you should be able to write:
Select DateName('month', [Date]) As Month
, Cast(DateDiff(d, #StartDate, #EndDate) As varchar(10) - 1) + ' days'
From Table
Where [Date] Between #StartDate And #EndDate
What we'd need to know to refine our solutions is exactly how 2 days is supposed to be calculated. Is it the days between the start and end date? Is it the day of the second parameter?