How to get financial quarters date by current date - sql

The quarters described as below:
APRIL - JUNE - Q1
JULY - SEPT - Q2
OCT - DEC - Q3
JAN - MARCH - Q4
For ex:
Date = '2018-12-24' -- Where this date is under third quarter
So Expected should be [Get all quarter < current date's quarter]
---------------------------
Quarters
---------------------------
01 Jul 2018 - 30 Sep 2018
01 Apr 2018 - 30 Jun 2018
---------------------------
If the
Date = '2019-01-24' -- Where this date is under fourth quarter
Expected result:
---------------------------
Quarters
---------------------------
01 Oct 2018 - 30 Dec 2018
01 Jul 2018 - 30 Sep 2018
01 Apr 2018 - 30 Jun 2018
---------------------------
The query that I have tried:
DECLARE #dt DATETIME = '2019-01-24 18:15:59.517'
DECLARE #FirstDayOfQuarter DATETIME
DECLARE #LastDayOfQuarter DATETIME
SET #FirstDayOfQuarter = (SELECT Dateadd(qq, Datediff(qq, 0, #dt) - 1, 0))
SET #LastDayOfQuarter = (SELECT Dateadd(dd, -1, Dateadd(qq, Datediff(qq, 0, #dt)
, 0)))
DECLARE #year INT
SET #year = Datepart(year, #dt)
DECLARE #currQ NVARCHAR(max)
SET #currQ = (SELECT CONVERT(VARCHAR(20), #FirstDayOfQuarter, 106)
+ Space(1) + '-' + Space(1)
+ CONVERT(VARCHAR(20), #LastDayOfQuarter, 106))
SELECT CONVERT(NVARCHAR(20), Dateadd(m, 3*number, CONVERT(DATE, CONVERT(VARCHAR(
5),
#year)+'-1-1')), 106)
+ Space(1) + '-' + Space(1)
+ CONVERT(NVARCHAR(20), Dateadd(d, -1, Dateadd(m, 3*number+3, CONVERT(
DATE,
CONVERT(VARCHAR(5), #year)+'-1-1'))), 106) AS Quarter,
number,
CASE
WHEN #dt BETWEEN Dateadd(m, 3 * number, CONVERT(DATE, CONVERT(VARCHAR(5
),
#year) +
'-1-1')) AND
Dateadd(d, -1, Dateadd(m, 3 * number + 3,
CONVERT(DATE, CONVERT(VARCHAR(5)
,
#year
) + '-1-1'))) THEN 1
ELSE 0
END AS isCurrentQuarter
INTO #allquarters
FROM master..spt_values
WHERE type = 'p'
AND number BETWEEN 1 AND 4
SELECT TOP 1 number,
CASE
WHEN #dt BETWEEN Dateadd(m, 3 * number,
CONVERT(DATE, CONVERT(VARCHAR(5),
#year) +
'-1-1')) AND
Dateadd(d, -1, Dateadd(m, 3 * number + 3,
CONVERT(DATE, CONVERT(
VARCHAR(5),
#year
) + '-1-1'))) THEN 1
ELSE 0
END AS isCurrentQuarter
INTO #currentquarter
FROM master..spt_values
WHERE type = 'p'
AND number BETWEEN 1 AND 4
ORDER BY iscurrentquarter DESC,
number ASC
SELECT quarter
FROM #allquarters
WHERE number < (SELECT number
FROM #currentquarter)
ORDER BY number DESC
DROP TABLE #allquarters
DROP TABLE #currentquarter
It is working for GETDATE() but when I put the date as 2019-01-24 18:15:59.517 then it gives me empty result
EDIT:
If the
Date = '2019-05-24' -- Where this date is under first quarter of next year
Expected result:
---------------------------
Quarters
---------------------------
01 Jan 2019 - 30 March 2019
01 Oct 2018 - 30 Dec 2018
01 Jul 2018 - 30 Sep 2018
01 Apr 2018 - 30 Jun 2018
---------------------------
If the
Date = '2018-05-24' -- Where this date is under the first quarter of current year
Expected result:
---------------------------
Quarters
---------------------------
01 Jan 2018 - 30 March 2018
01 Oct 2017 - 30 Dec 2017
01 Jul 2017 - 30 Sep 2017
01 Apr 2017 - 30 Jun 2017
---------------------------

I believe this does what you want:
with dte as (
select cast('2019-07-24' as date) as dte
)
select dte,
(convert(varchar(255), dateadd(month, v.n, datefromparts(year(dte), ((month(dte) - 1) / 3) * 3 + 1, 1)), 106) + ' - ' +
convert(varchar(255), dateadd(day, -1, dateadd(month, v.n + 3, datefromparts(year(dte), ((month(dte) - 1) / 3) * 3 + 1, 1))), 106)
) as string
from dte cross apply
(values (0), (-3), (-6), (-9)) v(n)
where month(dte) < 4 or month(dte) >= 13 + v.n
order by v.n;
Here is a db<>fiddle.

Use the formula (n + 5) % 12 + 3 to convert month numbers 1, 2, ..., 12 to 9, 10, ..., 14, 3, ..., 8 which is the number of months you need to subtract from a given date. In SQL Server 2008 you would translate it as:
DATEADD(MONTH, DATEDIFF(MONTH, 0, inputdate) - ((MONTH(inputdate) + 5) % 12 + 3), 0)
The converts 2018-04-xx to 2017-04-01 and 2018-07-xx to 2018-04-01. Adding 3, 6 and 9 months is trivial.
DB Fiddle

Related

How to pass variable of adding 270 days to the date?

Below is my query:
select
facility_lob as FACILITY_LOB,
TO_DATE(REPLACE(posting_d_date_sk, ',', ''), 'YYYYMMDD') as PostingDate,
count(distinct encounter_num ||cast(date_of_service as varchar(20) )) as ENCOUNTER_VOLUME,
SUM(charge_amt) as Gross_Charges
from sources.Table
where 1=1
and REPLACE(posting_d_date_sk, ',', '') >= '20210101'
and REPLACE(posting_d_date_sk, ',', '') <= '20210928'
and posting_d_date_sk <> '-1'
and posting_d_date_sk is not NULL
group by facility_lob, posting_d_date_sk
order by REPLACE(posting_d_date_sk, ',', '')
For now, I have hard coded the dates from Jan 1, 2021 to Sep 28, 2021 ( which is 270 days from Jan 1, 2021).
My requirement is the query should should pull data from and greater than year 2021 (>= 2021 of the posting date), and I need to pull the data from Jan 1, 2021, to 270 days. If I run the query today, I need to get the data from Jan 1, 2021 to Sep 28 2021 ( which is 270 days from jan 1 2021). If I execute this query tomorrow, I need to get the data from Jan 2 2021 to Sep 29 2021. jan 3, 2021 to sep 30 2021 etc.. If I run the query on April 3, 2022 then the calculation of 270 days is from Feb 1, 2021, to Oct 29, 2021.
Could you please help how do I fix this?
Why not using a simple dateadd based on getdate and then format it into your format ?
Declare #to varchar(10), #from varchar(10), #mydate smalldatetime
Set #mydate = Getdate()
Set #from = convert(varchar,year(#mydate)) + right('0' + convert(varchar,month(#mydate)),2) + right('0' + convert(varchar,day(#mydate)),2)
Set #mydate = dateadd(dd,270,getdate())
Set #to = convert(varchar,year(#mydate)) + right('0' + convert(varchar,month(#mydate)),2) + right('0' + convert(varchar,day(#mydate)),2)

SQL Middle of the Month

I know you can set #Date to 01/01/2001 as beginning of the month.
and then call dates that are first of every month, for example:
01/01/2001
01/02/2001
01/03/2001
but how would I please if possible is always find the date in the middle of the month? I would use 15th, but issue you have is with February
I need to make analysis of sum of sales mid month
any ideas please team
you can use this formula
DECLARE #Date DATE ='20180201'
SELECT DATEADD(DAY, (DAY(EOMONTH(#Date)) / 2) - 1, #Date)
Solution:
Get the count of the days in the month and calculate the "middle" day. In the next example the count of the days (28, 29, 30 or 31) is divided by an integer divisor (2), so the result will be an integer that has any fractional part truncated. Choose your preferred method.
DECLARE #date date
SET #date = DATEFROMPARTS(2020, 2, 1)
-- 15 is the half of the month with 30 and 31 days, 14 for months with 28, 29 days
SELECT DATEDIFF(d, #date, DATEADD(month, 1, #date)) / 2
-- 16 is the half of the month with 31 days, 15 for months with 29, 30 days, 14 for month with 28 days
SELECT (DATEDIFF(d, #date, DATEADD(month, 1, #date)) + 1) / 2
Example:
WITH Months AS
(
SELECT SomeDate = DATEFROMPARTS(2018, 1, 1)
UNION ALL
SELECT DATEADD(month, 1, SomeDate)
FROM Months
WHERE DATEPART(month, SomeDate) < 12
)
SELECT
SomeDate AS FirstDate,
DATEADD(d, -1, DATEADD(month, 1, SomeDate)) AS LastDate,
DATEDIFF(d, SomeDate, DATEADD(month, 1, SomeDate)) AS DaysBetween,
DATEDIFF(d, SomeDate, DATEADD(month, 1, SomeDate)) / 2 AS HalfOfMonth1,
(DATEDIFF(d, SomeDate, DATEADD(month, 1, SomeDate)) + 1) / 2 AS HalfOfMonth2
FROM Months
Output:
FirstDate LastDate DaysBetween HalfOfMonth1 HalfOfMonth2
01/01/2018 31/01/2018 31 15 16
01/02/2018 28/02/2018 28 14 14
01/03/2018 31/03/2018 31 15 16
01/04/2018 30/04/2018 30 15 15
01/05/2018 31/05/2018 31 15 16
01/06/2018 30/06/2018 30 15 15
01/07/2018 31/07/2018 31 15 16
01/08/2018 31/08/2018 31 15 16
01/09/2018 30/09/2018 30 15 15
01/10/2018 31/10/2018 31 15 16
01/11/2018 30/11/2018 30 15 15
01/12/2018 31/12/2018 31 15 16
i have tried the following
SELECT DATEADD(dd, (datediff(DD, DATEADD(m, DATEDIFF(m, 0, GETDATE()), - 1), eomonth(getdate())) / 2), DATEADD(m, DATEDIFF(m, 0, GETDATE()), - 1)),
CEILING((datediff(DD, DATEADD(m, DATEDIFF(m, 0, GETDATE()), - 1), eomonth(getdate())) / 2.00))
An update to the answer
DECLARE #Date DATE ='2018-10-01'---'20180201'
SELECT DATEADD(DAY, CEILING((DAY(EOMONTH(#Date)) / 2.00)) - 1, #Date)
Here is a query that get start date of month and end date of month by using datediff you can find the number of day to add and subtract
Set #tdate = '02/10/2018';
Select DATEFROMPARTS(YEAR(#tdate),MONTH(#tdate),1) as startdate , dateadd(day,-1,DATEFROMPARTS(YEAR(#tdate),MONTH(#tdate)+1,1)) as enddate
Regards

How to SUM over month columns in past year best way?

I have following columns from Jan to Dec:
Year - Jan - Feb - Mar - (etc.) - Dec
---- --- --- --- ---
2015 25 32 102 12
2016 30 40 50 60
How to effectively do SUM over past year? Let's say from GETDATE(), If today is 16.08.2017, I want SUM from 16.08.2016 (from august 2016 till august 2017).
I have following code:
select sum(val)
from t cross apply
(values (t.year, t.Jan, 1),
(t.year, t.Feb, 2),
. . .
) v(yyyy, val, mon)
where yyyy * 100 + mon >= (year(getdate()) - 1) * 100 + month(getdate());
which works, but is there any way to do it without cross apply? (for instance: just where clause)
how about something like below which uses UNPIVOT notation.
select sum(val)
from
(select * from t )s
unpivot
( val for month in ( Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec))up
where
cast(month+ cast(year as varchar(20)) as date)
between dateadd(m,-12,getdate()) and getdate()
Live Demo
Assuming all your column month names are 3 letters, you could also use dynamic SQL. Something like the following should work.
DECLARE #CurrentDate DATE = CAST(GETDATE() AS DATE)
DECLARE #Year INT = DATEPART(YEAR, #CurrentDate)
DECLARE #PrevYear INT = #Year - 1
DECLARE #Month CHAR(3)
SET #Month = convert(char(3), #CurrentDate, 0)
BEGIN
EXEC('SELECT SUM(t.'+#Month+') FROM t WHERE Year >= ' + #PrevYear + ' AND Year <= ' + #Year)
END

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

How do I build ISO Week Number table programatically in T-SQL query?

Anyone knows how to built temp table of week using T-SQL query?
I heard there has a lot of type of calculations for that, Gregorian or etc... My needs are ISO Week No and bind to temp table depends on week no.
The temp table has 2 columns : ISOWeekNo and WeekName
ISOWeekNo WeekName
1 01 Jan 2013 To 07 Jan 2013
2 08 Jan 2013 To 14 Jan 2013
How do I build programmatically in T-SQL Query based on ISO Week No?
Updated : I want to pass the parameter year only. e.g : 2013
EDIT: Added WHERE clause to terminate for sought year only.
This seems to match the Wikipedia description and I am sure there is room for optimisation.
Mikael, I copied your formatting code for the friendly column, thank you.
This code will work on SQL Server 2008 onwards because of the use of the ISOWEEK datepart.
use tempdb
go
DECLARE #Year SMALLINT = 2013
,#FirstISOWKDay DATETIME
;WITH FindISOWEEKFirstDay AS
(
SELECT DT = DATEADD(DAY, -7, DATEFROMPARTS(#Year, 1, 1))
UNION ALL
SELECT DATEADD(DAY, 1, DT)
FROM FindISOWEEKFirstDay
WHERE DATEADD(DAY, 1, DT) < DATEADD(DAY, 14, DATEFROMPARTS(#Year, 1, 1))
)
SELECT TOP 1 #FirstISOWKDay = DT
FROM FindISOWEEKFirstDay
WHERE DATEPART(ISO_WEEK, DT) = 1
ORDER BY DT ASC -- Eliminate probability of arb sorting (Thanks Mikael)
;WITH Base10 (n) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1
)
,Base1000 (n) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1
FROM Base10 T1, Base10 T2, Base10 T3
)
SELECT Start = DATEADD(DAY, n*7, #FirstISOWKDay)
,[End] = DATEADD(DAY, n*7 + 6, #FirstISOWKDay)
,Friendly = CONVERT(VARCHAR(101), DATEADD(DAY, n*7, #FirstISOWKDay), 106)+' To '+CONVERT(VARCHAR(101), DATEADD(DAY, n*7 + 6, #FirstISOWKDay), 106)
,ISOWEEK = DATEPART(ISO_WEEK, DATEADD(DAY, n*7, #FirstISOWKDay))
FROM Base1000
-- Filter to terminate, resulting only in sought year's calendar
WHERE DATEPART(YEAR, DATEADD(DAY, n*7 + 6, #FirstISOWKDay)) = #Year
declare #Year int;
set #Year = 2016;
with C as
(
select datefromparts(#Year, 1, 1) as D
union all
select dateadd(day, 1, C.D)
from C
where C.D < datefromparts(#Year, 12, 31)
)
select datepart(iso_week, C.D) as ISOWeekNo,
convert(varchar(101), min(C.D), 106)+' To '+convert(varchar(101), max(C.D), 106) as WeekName
from C
group by datepart(iso_week, C.D),
case when datepart(month, C.D) = 12 and
datepart(iso_week, C.D) > 50
then 1
else 0
end
order by min(C.D)
option (maxrecursion 0);
Result:
ISOWeekNo WeekName
----------- --------------------------
53 01 Jan 2016 To 03 Jan 2016
1 04 Jan 2016 To 10 Jan 2016
2 11 Jan 2016 To 17 Jan 2016
3 18 Jan 2016 To 24 Jan 2016
4 25 Jan 2016 To 31 Jan 2016
5 01 Feb 2016 To 07 Feb 2016
6 08 Feb 2016 To 14 Feb 2016
7 15 Feb 2016 To 21 Feb 2016
.
.
.
47 21 Nov 2016 To 27 Nov 2016
48 28 Nov 2016 To 04 Dec 2016
49 05 Dec 2016 To 11 Dec 2016
50 12 Dec 2016 To 18 Dec 2016
51 19 Dec 2016 To 25 Dec 2016
52 26 Dec 2016 To 31 Dec 2016
This may help:
Select date '2012-12-31' + level*7 WK_STARTS_DT
, to_char(date '2012-12-31' + level*7, 'IW') ISO_WEEK
, to_char(date '2012-12-31' + level*7, 'WW') WEEK
From dual
Connect By Level <=
(
Select Round( (ADD_MONTHS(TRUNC(SYSDATE,'Y'),12)-TRUNC(SYSDATE,'Y') )/7, 0) From dual
) --365/7
/
WK_STARTS_DT ISO_WEEK WEEK
------------------------------------
1/7/2013 02 01
1/14/2013 03 02
1/21/2013 04 03
......
2/4/2013 06 05
2/11/2013 07 06
......
3/4/2013 10 09
To confirm week numbers:
http://www.epochconverter.com/date-and-time/weeknumbers-by-year.php?year=2013