Split Date Range in months SQL Server - sql

I want to split date range in months. I will pass startdate(1-jan-2011) and enddate(31-dec-2011) as a parameter then it must return result like
1-jan-2011 - 31-jan-2011
1-feb-2011 - 28-feb-2011
1-mar-2011 - 31-mar-2011
Please send me a stored procedure.....
Thanks,
Abhishek

Try this:
CREATE PROC SplitDateRange
#from DATETIME,
#to DATETIME
AS
BEGIN
SET NOCOUNT ON;
SET #from = CONVERT(VARCHAR, DATEADD(DAY, -DATEPART(DAY, #from)+1, #from), 112)
-- Sql 2000
CREATE TABLE #temp (DateFrom DATETIME, DateTo DATETIME)
WHILE #from < #to
BEGIN
INSERT #temp VALUES (#from, DATEADD(DAY, -1, DATEADD(MONTH, 1, #from)))
SET #from = DATEADD(MONTH, 1, #from)
END
SELECT * FROM #temp
DROP TABLE #temp
--sql 2005+
/*
;WITH Ranges(DateFrom, DateTo) AS
(
SELECT #from DateFrom, DATEADD(DAY, -1, DATEADD(MONTH, 1, #from)) DateTo
UNION ALL
SELECT DATEADD(MONTH, 1, DateFrom), DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(MONTH, 1, DateFrom)))
FROM Ranges
WHERE DateFrom < DATEADD(MONTH, -1, #To)
)
SELECT * FROM Ranges
OPTION(MAXRECURSION 0)
*/
END
GO
EXEC SplitDateRange '2011-01-02', '2012-06-06'

So that you can use the results in another SQL Query (which I assume is where you're going) I'd put that into a table valued function.
Assuming SQL Server 2005+ you could use this...
CREATE FUNCTION dbo.ufnMonthlyIntervals(
#from_date SMALLDATETIME,
#end_date SMALLDATETIME
)
RETURNS TABLE
WITH
intervals (
from_date,
end_date
)
AS
(
SELECT #from_date, DATEADD(MONTH, 1, #from_date ) - 1
UNION ALL
SELECT end_date + 1, DATEADD(MONTH, 1, end_date + 1) - 1 FROM intervals WHERE end_date < #end_date
)
RETURN
SELECT
from_date,
CASE WHEN end_date > #end_date THEN #end_date ELSE end_date END AS end_date
FROM
intervals
Then you just use SELECT * FROM dbo.ufnMonthlyIntervals('20110101', '20111201') AS intervals

Related

Recursive CTE on Dates

I want to recursively loop though the temporary table by date1 field using following query in Sql server. I want that the #stardate and #enddate should auto increment up to the #stopcriteria initially starting from
'01/01/2011' to 12/31/2011' and then
'01/01/2012' to 12/31/2012' and so on up to #stopCriteria and resultset should keep joining with union. I have written following query using cte but is not working.
CREATE TABLE #tempbbs576 ( id int, amount money, date1 date)
insert into #tempbbs576(id,amount,date1) values(1,1000,'1/1/2018')
insert into #tempbbs576(id,amount,date1) values(2,20010,'22/3/2019')
insert into #tempbbs576(id,amount,date1) values(3,40010,'1/1/2017')
insert into #tempbbs576(id,amount,date1) values(4,50010,'23/4/2018')
insert into #tempbbs576(id,amount,date1) values(5,60010,'1/1/2018')
insert into #tempbbs576(id,amount,date1) values(6,70010,'21/1/2018')
DECLARE #startDate DATE;
DECLARE #endDate DATE;
DECLARE #stopCriteria DATE;
SET #startDate='01/01/2011'; SET #endDate='12/31/2011'; SET #stopCriteria='01/01/2018';
;WITH ctesequence
AS (SELECT 'Year' + Datename(year, Dateadd(year, 1, #startDate)) /*'2012'*/
AS FiscalYear, Count(DISTINCT id) AS Last2Years
FROM [dbo].[#tempbbs576](nolock) WHERE date1 BETWEEN #startDate AND
#endDate AND id IN (SELECT id FROM [dbo].[#tempbbs576]
WHERE date1 < Dateadd(year, -1, #startDate) AND id
NOT IN (SELECT id FROM [dbo].[#tempbbs576] WHERE date1 BETWEEN
Dateadd(year,-1, #startDate) AND Dateadd( year, -1, #endDate ) ))
UNION
SELECT 'Year' + Datename(year, Dateadd(year, 1, #startDate)) /*'2012'*/
AS FiscalYear, Count(DISTINCT id) AS Last2Years FROM ctesequence WHERE date1 <= #stopCriteria)
SELECT * FROM ctesequence OPTION(maxrecursion 0)
Please let me know if it is possible through cte.
Thanks in Advance,
Amar

check is there any weekday inside time given sql server

I have been wondering is there any operator/function in sql server to tell about weekday between given day.
Example :11-19-2016 to 11-29-2016 I want check if there is tuesday between that day?
Try This:
declare #start varchar(100)='11-19-2016'
declare #end varchar(100)='11-29-2016'
;with dateRange as
(
select date = dateadd(dd, 1, #start)
where dateadd(dd, 1, #start) < #end
union all
select dateadd(dd, 1, date)
from dateRange
where dateadd(dd, 1, date) < #end
)
select date,DATENAME(dw,CAST(DATEPART(m, GETDATE()) AS VARCHAR)
+ '/'+ CAST(DATEPART(d, date) AS VARCHAR)
+ '/'+ CAST(DATEPART(yy, getdate()) AS VARCHAR)) as 'Day'
from dateRange where (DATENAME(dw,CAST(DATEPART(m, GETDATE()) AS VARCHAR)
+ '/'+ CAST(DATEPART(d, date) AS VARCHAR)
+ '/'+ CAST(DATEPART(yy, getdate()) AS VARCHAR)))='Tuesday'
The query below uses a recursive query to unfold the date range.
Then uses DATEPART to select only the Tuesdays from it.
But one could also use DATENAME instead.
declare #StartDate DATE = '2016-11-19';
declare #EndDate DATE = '2016-11-29';
--SET DATEFIRST 7;
-- The dw for tuesday is 3 when ##datefirst = 7 (default setting)
-- Since it depends on a usersetting, lets calculate it anyway.
declare #TuesdayWeekday INT = (7-##datefirst + 2)%7+1;
;with DATES as
(
select #startdate as [Date]
union all
select dateadd(day, 1, [Date]) from DATES
where [Date] < #enddate
)
select [Date], datepart(dw,[Date]) as day_of_week, datename(dw,[Date]) as day_of_weekname
from DATES
where datepart(dw,[Date]) = #TuesdayWeekday;

Find the Same day of Previous Year Given by Current Year Date in SQL Server

I am working with SQL Server, The scenario is to find out the Same Day's Date of Previous Year as of Today's Day.
Suppose 2014-03-06 is Today Date and Day is Thursday I want to Find the Same day in Previous lies in the same week .which is 2013-03-07
can any body help?
HERE is what i Have Written:
DECLARE #DateFrom AS DATETIME
DECLARE #DateTo AS DATETIME
SET #DateFrom = '2014-01-01'
SET #DateTo = '2014-02-10'
DECLARE #Count AS INT
SET #Count = DATEDIFF(DAY, #DateFrom, #DateTo)
CREATE TABLE #current_year /*This Year*/
(
[Date] DATETIME ,
WeekNum INT,
[Day] VARCHAR(20),
Data INT
)
CREATE TABLE #last_year /*This Year -1*/
(
[Date] DATETIME ,
WeekNum INT,
[Day] VARCHAR(20),
Data INT
)
WHILE ( #Count > 0 )
BEGIN
INSERT INTO #current_year
VALUES ( CONVERT(VARCHAR(10), #DateFrom, 101),
DATEPART(week,#DateFrom),
DATENAME(weekday, #DateFrom),#Count)
INSERT INTO #last_year
VALUES ( CONVERT(VARCHAR(10), DATEADD(YEAR, -1, #DateFrom), 101),
DATEPART(week,DATEADD(YEAR,1,#DateFrom)),
DATENAME(weekday, DATEADD(YEAR, -1, #DateFrom)),#Count)
SET #DateFrom = DATEADD(day, 1, #DateFrom)
SET #Count = #Count - 1
END
SELECT * from #current_year
SELECT * from #last_year
SELECT CONVERT(varchar(10),#current_year.[Date],111) AS CYDate,
--ISNULL(CONVERT(varchar(10),#last_year.[Date],111) ,/*CONVERT(varchar(10),DateAdd(dd, 1, DATEADD(yy, -1, #current_year.Date)),111)*/) AS LYDate
--CONVERT(varchar(10),#last_year.[Date],111) AS LYDate
Coalesce(CONVERT(varchar(10),#last_year.[Date],111) ,DateAdd(dd, 1, DATEADD(yy, -1, #current_year.Date))) AS LYDate,
#current_year.Data AS CD,
#last_year.Data AS LD
FROM #current_year
--LEFT JOIN #last_year ON #last_year.WeekNum = #current_year.WeekNum
-- AND #last_year.[Day] = #current_year.[Day]
Left JOIN #last_year ON #last_year.WeekNum = DatePart(wk, GETDATE())
DROP TABLE #current_year
DROP TABLE #last_year
Here is the Output:
Here is the output after adding your solution, now in left join it excludes (NULL) data of previous year
Basically you need to find difference in days between same dates in this and previous years, then understand "day difference" by mod 7, and sum it with date in previous year:
DECLARE #now DATETIME
SET #now = '2014-03-06'
SELECT CAST (DATEADD(YEAR, -1, #now) + (CAST (#now as INT) - CAST (DATEADD(YEAR, -1, #now) AS INT)) % 7 AS DATE)
Returns
2013-03-07
Try
DECLARE #now Date
SET #now = '2014-06-03'
SELECT DATEADD(week, -52, #now)
SELECT DateName(dw, DATEADD(yy, -1, GETDATE()))
gives Wednesday
SELECT DateName(dw, DateAdd(dd, 1, DATEADD(yy, -1, GETDATE())))
gives Thursday
edit:
SELECT DateAdd(dd, 1, DATEADD(yy, -1, GETDATE()))
gives '2013-03-07 17:30:16.590'
you need to cast the date as per you requirement..
update:
change this part with,
Left JOIN #last_year ON #last_year.WeekNum = DatePart(wk, GETDATE())
in your case:
Left JOIN #last_year ON DatePart(wk, #last_year.[Date]) = DatePart(wk, #current_year.[Date])
update 2:
Left JOIN #last_year ON (MONTH(#last_year.[Date])=MONTH(#current_year.[Date]) and Day(#last_year.[Date])=Day(#current_year.[Date]))
Output:
or
output:
Left JOIN #last_year ON (#last_year.WeekNum = #current_year.WeekNum and #last_year.[Day] = #current_year.[Day])
choose which ever is your required output.
DECLARE #Date DATE = '2014-03-06'
SELECT DATEADD(WEEK,-52,#Date)
Retrun value :
2013-03-07

Find last sunday

How will you find last sunday of a month in sql 2000?
SELECT
DATEADD(day,DATEDIFF(day,'19000107',DATEADD(month,DATEDIFF(MONTH,0,GETDATE() /*YourValuehere*/),30))/7*7,'19000107')
Edit: A correct, final, working answer from my colleague.
select dateadd(day,1-datepart(dw, getdate()), getdate())
An alternative approach, borrowed from data warehousing practice. Create a date-dimension table and pre-load it for 10 years, or so.
TABLE dimDate (DateKey, FullDate, Day, Month, Year, DayOfWeek,
DayInEpoch, MonthName, LastDayInMonthIndicator, many more..)
The easiest way to fill-in the dimDate is to spend an afternoon with Excel and then import to DB from there. A half-decent dimDate table has 50+ columns -- anything you ever wanted to know about a date.
With this in place, the question becomes something like:
SELECT max(FullDate)
FROM dimDate
WHERE DayOfWeek = 'Sunday'
AND Month = 11
AND Year = 2009;
Essentially, all date related queries become simpler.
Next sunday in SQL, regardless which day is first day of week: returns 2011-01-02 23:59:59.000 on 22-dec-2010:
select DateADD(ss, -1, DATEADD(week, DATEDIFF(week, 0, getdate()), 14))
I find some of these solutions hard to understand so here's my version with variables to explain the steps.
ALTER FUNCTION dbo.fn_LastSundayInMonth
(
#StartDate DATETIME
,#RequiredDayOfWeek INT /* 1= Sunday */
)
RETURNS DATETIME
AS
/*
A detailed step by step way to get the answer...
SELECT dbo.fn_LastSundayInMonth(getdate()-31,1)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,2)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,3)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,4)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,5)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,6)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,7)
*/
BEGIN
DECLARE #MonthsSince1900 INTEGER
DECLARE #NextMonth INTEGER
DECLARE #DaysToSubtract INTEGER
DECLARE #FirstDayOfNextMonth DATETIME
DECLARE #LastDayOfMonthDayOfWeek INTEGER
DECLARE #LastDayOfMonth DATETIME
DECLARE #ReturnValue DATETIME
SET #MonthsSince1900=DateDiff(month, 0, #StartDate)
SET #NextMonth=#MonthsSince1900+1
SET #FirstDayOfNextMonth = DateAdd(month,#NextMonth, 0)
SET #LastDayOfMonth = DateAdd(day, -1, #FirstDayOfNextMonth)
SET #ReturnValue = #LastDayOfMonth
WHILE DATEPART(dw, #ReturnValue) <> #RequiredDayOfWeek
BEGIN
SET #ReturnValue = DATEADD(DAY,-1, #ReturnValue)
END
RETURN #ReturnValue
END
DECLARE #LastDateOfMonth smalldatetime
SELECT #LastDateOfMonth = DATEADD(month, DATEDIFF(month, -1, GETDATE()), 0) -1
Select DATEADD(dd,-( CASE WHEN DATEPART(weekday,#LastDateOfMonth) = 1 THEN 0 ELSE DATEPART(weekday,#LastDateOfMonth) - 1 END ),#LastDateOfMonth)
Holy cow, this is ugly, but here goes:
DECLARE #dtDate DATETIME
SET #dtDate = '2009-11-05'
SELECT DATEADD(dd, -1*(DATEPART(dw, DateAdd(day, -1, DateAdd(month, DateDiff(month, 0, #dtDate)+1, 0)))-1),
DateAdd(day, -1, DateAdd(month, DateDiff(month, 0, #dtDate)+1, 0)))
First built a tally table.
http://www.sqlservercentral.com/articles/T-SQL/62867/
then get what you want..
http://www.sqlservercentral.com/Forums/Topic515226-1291-1.aspx
DECLARE #DateStart DATETIME,
#DateEnd DATETIME
SELECT #DateStart = '20080131',
#DateEnd = '20101201'
SELECT DATEADD(wk,DATEDIFF(wk,6,DATEADD(mm,DATEDIFF(mm,-1,DATEADD(mm,t.N-1,#DateStart)),-1)),6)
FROM dbo.Tally t
WHERE t.N <= DATEDIFF(mm,#DateStart,#DateEnd)
Here's the correct way, accounting for ##DATEFIRST
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fu_dtLastSundayInMonth]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
BEGIN
EXECUTE(N'CREATE FUNCTION [dbo].[fu_dtLastSundayInMonth]() RETURNS int BEGIN RETURN 0 END ')
END
GO
/*
SET DATEFIRST 3; -- Monday
WITH CTE AS (
SELECT 1 AS i, CAST('20190101' AS datetime) AS mydate
UNION ALL
SELECT i+1 AS i, DATEADD(month, 1, CTE.mydate) AS mydate
FROM CTE WHERE i < 100
)
SELECT -666 AS i, dbo.fu_dtLastSundayInMonth('17530101') AS lastSundayInMonth, dbo.fu_dtLastSundayInMonth('17530101') AS Control
UNION ALL
SELECT -666 AS i, dbo.fu_dtLastSundayInMonth('99991231') AS lastSundayInMonth, dbo.fu_dtLastSundayInMonth('99991231') AS Control
UNION ALL
SELECT
mydate
,dbo.fu_dtLastSundayInMonth(mydate) AS lastSundayInMonth
,dbo.fu_dtLastSundayInMonth(mydate) AS lastSundayInMonth
,DATEADD(day,DATEDIFF(day,'19000107', DATEADD(MONTH, DATEDIFF(MONTH, 0, mydate, 30))/7*7,'19000107') AS Control
FROM CTE
*/
-- =====================================================================
-- Description: Return date of last sunday in month
-- of the same year and month as #in_DateTime
-- =====================================================================
ALTER FUNCTION [dbo].[fu_dtLastSundayInMonth](#in_DateTime datetime )
RETURNS DateTime
AS
BEGIN
-- Abrunden des Eingabedatums auf 00:00:00 Uhr
DECLARE #dtReturnValue AS DateTime
-- 26.12.9999 SO
IF #in_DateTime >= CAST('99991201' AS datetime)
RETURN CAST('99991226' AS datetime);
-- #dtReturnValue is now last day of month
SET #dtReturnValue = DATEADD
(
DAY
,-1
,DATEADD
(
MONTH
,1
,CAST(CAST(YEAR(#in_DateTime) AS varchar(4)) + RIGHT('00' + CAST(MONTH(#in_DateTime) AS varchar(2)), 2) + '01' AS datetime)
)
)
;
-- SET DATEFIRST 1 -- Monday - Super easy !
-- SET DATEFIRST != 1 - PHUK THIS !
SET #dtReturnValue = DATEADD
(
day
,
-
(
(
-- DATEPART(WEEKDAY, #lastDayofMonth) -- with SET DATEFIRST 1
DATEPART(WEEKDAY, #dtReturnValue) + ##DATEFIRST - 2 % 7 + 1
)
%7
)
, #dtReturnValue
);
RETURN #dtReturnValue;
END
GO
select next_day(last_day(sysdate)-7, 'Sunday') from dual

Compare current date with stored datetime using month an year only

Using SQL Server 2005 I have a field that contains a datetime value.
What I am trying to do is create 2 queries:
Compare to see if stored datetime is of the same month+year as current date
Compare to see if stored datetime is of the same year as current date
There is probably a simple solution but I keep hitting brick walls using various samples I can find, any thoughts?
Thanks in advance.
Compare the parts of the date:
WHERE YEAR( columnName ) = YEAR( getDate() )
While the other answers will work, they all suffer from the same problem: they apply a transformation to the column and therefore will never utilize an index on that column.
To search the date without a transformation, you need a couple built-in functions and some math. Example below:
--create a table to hold our example values
create table #DateSearch
(
TheDate datetime not null
)
insert into #DateSearch (TheDate)
--today
select getdate()
union all
--a month in advance
select dateadd(month, 1, getdate())
union all
--a year in advance
select dateadd(year, 1, getdate())
go
--declare variables to make things a little easier to see
declare #StartDate datetime, #EndDate datetime
--search for "same month+year as current date"
select #StartDate = dateadd(month, datediff(month, 0, getdate()), 0), #EndDate = dateadd(month, datediff(month, 0, getdate()) + 1, 0)
select #StartDate [StartDate], #EndDate [EndDate], TheDate from #DateSearch
where TheDate >= #StartDate and TheDate < #EndDate
--search for "same year as current date"
select #StartDate = dateadd(year, datediff(year, 0, getdate()), 0), #EndDate = dateadd(year, datediff(year, 0, getdate()) + 1, 0)
select #StartDate [StartDate], #EndDate [EndDate], TheDate from #DateSearch
where TheDate >= #StartDate and TheDate < #EndDate
What the statement does to avoid the transformations, is find all values greater-than or equal-to the beginning of the current time period (month or year) AND all values less-than the beginning of the next (invalid) time period. This solves our index problem and also mitigates any issues related to 3ms rounding in the DATETIME type.
SELECT * FROM atable
WHERE
YEAR( adate ) = YEAR( GETDATE() )
AND
MONTH( adate ) = MONTH( GETDATE() )
It sounds to me like DATEDIFF is exactly what you need:
-- #1 same month and year
SELECT *
FROM your_table
WHERE DATEDIFF(month, your_column, GETDATE()) = 0
-- #2 same year
SELECT *
FROM your_table
WHERE DATEDIFF(year, your_column, GETDATE()) = 0
The datepart function lets you pull the bits you need:
declare #d1 as datetime
declare #d2 as datetime
if datepart(yy, #d1) = datepart(yy, #d2) and datepart(mm, #d1) = datepart(mm, #d2) begin
print 'same'
end
You can use something like this
a)
select *
from table
where MONTH(field) = MONTH(GetDATE())
and YEAR(field) = YEAR(GetDATE())
b)
select *
from table
where YEAR(field) = YEAR(GetDATE())