Incremental and decremental count based on a date - sql

Name Start_date end_date
aaa 01/02/2017 05/03/2017
bbb 03/05/2017 07/07/2017
ccc 02/01/2017 10/09/2017
I want to write a query that calculates the number of people who exist in the DB in a certain month/year.
Answer:
Jan 2017 1
Feb 2017 2
Mar 2017 3
Apr 2017 3
May 2017 2 (one person - aaa ,ended in May 2017)
Jun 2017 2
Jul 2017 1 (bbb ended in July 2017)
How do I write a PSQL query to get the desired output?
Thanks.

First, get the max and min dates in order to declare the dates range.
Second, with etc select all the month in the range.
Third, sum the number of the records in each dates.
Like:
declare #date date
declare #toDate date
select #date = min(Start_date),
#toDate = max(end_date)
from table_name
;With dt As
(
Select #date As [TheDate]
Union All
Select DateAdd(month, 1, TheDate) From dt Where [TheDate] < #toDate
)
select month(dt.TheDate),
year(dt.TheDate),
sum(case when table_name.Name is not null then 1 else 0 end)
from dt
left join table_name
on table_name.Start_date >= dt.TheDate
and table_name.end_date < dateadd(day,-1,dateAdd(month,1,dt.TheDate))

Related

Get the COUNT(*) records for each month in the year

I have Start_Date(which is '2021-12-01') and End_Date(which is current calendar month)
I need to get COUNT(*) for each month from 2021-12-01 to the current month
Result set should look like this:
December, 2021 - 21
January, 2022 - 44
Feb, 2023 - 11
etc.
So what I tried(I only how do that manually):
DECLARE #datestamp DATE = '12/01/2021'
DECLARE #CurrentDate VARCHAR(100)
SET #CurrentDate = CONVERT(varchar, GETDATE(), 101)
SELECT COUNT(*) AS 'December, 2021'
FROM #TMP
WHERE Start_Date IS NOT NULL AND [Signup_Date] IS NOT NULL
AND Start_Date BETWEEN #datestamp AND '2021-12-31'
But I don't want to copy this query for each of 12 months. How do that dynamically?

SQL - Create a temp table or CTE of first day of the month and month names

I need to create a temp table or common table expression based on 2 paremters in a SQL Server 2012 environment
#calYear
#currentYear
so if #calYear = 5 and #currentYear='2014'
I would like to generate a temp table of 5 years starting from current year with 4 columns like
YearDesc MonthName MonthNum FirstDayOfMonth
2014 Jan 1 1/1/2014
2014 Feb 2 2/1/2014
2014 Mar 3 3/1/2014
...
...
...
2018 Oct 10 10/1/2018
2018 Nov 11 11/1/2018
2018 Dec 12 12/1/2018
Is it possible to do a Do While loop efficently? How would I account for the month names?
I'm using a really cumbersome Do While loop to iterate all the months of the year then iterate all the years.
One way using a recursive cte:
declare #calYear int = 5, #currentYear char(4) = '2014'
;with cte (dt) as (
select DATEFROMPARTS(#currentyear,1,1) dt
union all
select dateadd(month,1,dt)
from cte where dt < dateadd(year,#calyear,DATEFROMPARTS(#currentyear,1,1))
)
select year(dt) YearDesc, datename(month, dt) MonthName, month(dt) MonthNum, dt FirstDayOfMonth
from cte
order by dt
Or using a numbers table: (in this case master..spt_values)
declare #calYear int = 5, #currentYear char(4) = '2014'
;with cte2 (dt) as (
select dateadd(month,number,DATEFROMPARTS(#currentyear,1,1)) dt
from master..spt_values where type = 'p'
and number <= 12*#calYear
)
select year(dt) YearDesc, datename(month, dt) MonthName, month(dt) MonthNum, dt FirstDayOfMonth
from cte2
order by dt

How to iterate last six month(including current) loop without any custom table?

I want output like follow:
Currently I am using a table. But I don't want to use this with any table(EXCEPT SYSTEM TABLES). Is it possible?
Query(Using a table):
DECLARE #End_date DATETIME
SET #End_Date = DATEADD(month, -6, GETDATE())
SELECT DISTINCT MONTH(S.ACDATE) AS Mon,CONVERT(CHAR(4),S.ACDATE) AS Month_Name,
(YEAR(S.ACDATE) % 100) AS Year_No
FROM SALES as S
WHERE S.ACDATE < DATEADD(month,MONTH(getdate()),
DATEADD(year,YEAR(getdate())-1900,0))
AND S.ACDATE >= DATEADD(month,MONTH(#End_Date)-1,
DATEADD(year,YEAR(#End_Date)-1900,0))
DECLARE #dt DATE = CONVERT(DATE, '05/03/2013', 101)
SELECT MONTH (dt) AS Mon, LEFT (DATENAME (mm, dt), 3) AS Month_Name, YEAR (dt) % 1000 AS Year_No
FROM (
SELECT DATEADD (mm, -diff, #dt) dt
FROM (VALUES(1),(2),(3),(4),(5),(6))t(diff)
) t
Result set is:
Mon Month_Name Year_No
----------- ---------- -----------
4 Apr 13
3 Mar 13
2 Feb 13
1 Jan 13
12 Dec 12
11 Nov 12

SQL Server query : how can I SUM one SELECT to another?

I have a problem with my SQL Server query, and I hope you will help me
The main select must output date and sum of the weight
How can I sum one select to another? Data is taking from one table Tbreport, and condition is - to sum weight of the concrete date and previous date (concrete date minus 1 day)
For example:
CONCRETE DATE WEIGHT
Jan 1 100
Jan 2 150
Jan 3 210
PREVIOUS DATE WEIGHT
Jan 1 100
Jan 2 250 (Jan 1 + Jan 2)
Jan 3 460 (Jan 1 + Jan 2 + Jan 3)
In real table I have format in seconds. For ex: 1358892000 seconds is 2013 Jan 23 0:00:00 and 1358978400 is 2013 Jan 23 23:59:00. And every time is own weight
Query:
SELECT CONVERT(varchar, DATEADD(s, TBreport.date, 25568), 102) AS DATE,
SUM(TBreport.weight)
+
(
SELECT SUM(TBreport.weight) AS WEIGHT
FROM TBreport INNER JOIN TBway ON TBreport.id_way = TBway.id
WHERE (SUBSTRING(TBway.name, 5, 8) LIKE 'to warehouse')
AND ... ???
GROUP BY CONVERT(varchar, DATEADD(s, TBreport.date, 25568), 102)
)
FROM TBreport INNER JOIN TBway ON TBreport.id_way = TBway.id
WHERE (SUBSTRING(TBway.name, 5, 8) LIKE 'to warehouse')
GROUP BY CONVERT(varchar, DATEADD(s, TBreport.date, 25568), 102)
I'm assuming date is unique in TBreport
SELECT this.date, SUM(upToThis.weight)
FROM TBreport this
INNER JOIN TBreport upToThis ON upToThis.date <= this.date
GROUP BY this.date

SQL days available using a not exists on current financial year

I have a table called 'holiday table' which basically contains dates for all days where employees will not be in work (e.g bank holidays etc)
The below query is basically looking at the current financial year and working out how many days are available firstly by month, and then using the unuion all cummulatively, (e.g April-May, April-June) I dont need one for April though as I can use the non-cumulative for this.
See query:
DECLARE #StartDate DATETIME,
#EndDate DATETIME
--available days
--current – start of this financial year
SELECT #StartDate = (select
case when month(getdate()) >= 4 then
convert(datetime, cast(year(getdate()) as varchar) + '-4-1')
else
convert(datetime, cast(year(getdate())-1 as varchar) + '-4-1')
end),
--current – end of this financial year
#EndDate = (select
case when month(getdate()) < 4 then
convert(datetime, cast(year(getdate()) as varchar) + '-3-31')
else
convert(datetime, cast(year(getdate())+1 as varchar) + '-3-31')
end)
CREATE TABLE #data
(
firstday DATETIME NOT NULL PRIMARY KEY,
workingdays INT NOT NULL
);
WITH dayscte ([Date])
AS (SELECT #StartDate
UNION ALL
SELECT Dateadd(DAY, 1, [Date])
FROM dayscte
WHERE [Date] <= #Enddate)
INSERT INTO #data
SELECT MIN([Date]),
COUNT(*) [Day]
FROM dayscte
LEFT JOIN dbo.Holiday_Table
ON [Date] BETWEEN dbo.Holiday_Table.sch_cal_d AND dbo.Holiday_Table.sch_cal_ed
where
NOT EXISTS (
SELECT sch_id,sch_cal_d,sch_cal_ed FROM dbo.Holiday_Table WHERE
sch_id ='66291100Ks'
AND
[date] <= sch_cal_d
AND
[date] >= sch_cal_ed
)
AND Datename(weekday, [Date]) NOT IN ( 'Saturday', 'Sunday' )
GROUP BY Datepart(MONTH, [Date]),
Datepart(YEAR, [Date])
OPTION (MAXRECURSION 366)
DECLARE #Date DATETIME
SET #Date = (SELECT MIN(firstday)
FROM #data)
SELECT Period,
workingdays [Days_Available_Minus_Holidays] ,
year (firstday) AS [Year]
FROM (SELECT Datename(MONTH, firstday) [Period],
workingdays,
0 [SortField],
firstday
FROM #data
UNION
SELECT Datename(MONTH, #Date) + '-' + Datename(MONTH, firstday),
(SELECT SUM(workingdays)
FROM #data b
WHERE b.firstday <= a.firstday ) [WorkingDays],
1 [SortField],
firstday
FROM #data a
WHERE
firstday > #Date) data
ORDER BY sortfield,
firstday
DROP TABLE #data
GO
The results for this are as follows:
Period Days_Available_Minus_Holidays Year
April 19 2012
May 22 2012
June 19 2012
July 22 2012
August 22 2012
September 20 2012
October 23 2012
November 22 2012
December 19 2012
January 23 2013
February 20 2013
March 21 2013
April 1 2013
April-May 41 2012
April-June 60 2012
April-July 82 2012
April-August 104 2012
April-September 124 2012
April-October 147 2012
April-November 169 2012
April-December 188 2012
April-January 211 2013
April-February 231 2013
April-March 252 2013
April-April 253 2013
My problem is when I get to the cumulative, it does another 'April' and then at the bottom it does an 'April-April' I do not need a cumulative for April as it is only one month do basically I dont want the first or last cumulative values as April is covered by the non-cumulatives, or if the second 'April' must stay, then it should not read '1' as days available, by be the same as the non-cumulative, which is 19 as this is how many days are actually available.
Try removing the equals in your WITH clause
Change WHERE [Date] <= #Enddate to WHERE [Date] < #Enddate
It seems your adding a day to the date before the WHERE clause therefore it is overstepping by a day.