Difference in Days Between Two Dates with Years, Months, and Days - sql

I'm not a SQL expert, would you know if it's possible to have a query provide Days Between Two Dates to count days outstanding with today's date and output: Years, Months, Days and outstanding days providing 30 Days, 60 Days, 90 Days?
If I Declare "Years, Months, Days" from "Check_Date" and "Created_Date".
SQL provides a separate window, and, I only see Declared "FromDate" time
with "ToDate" displaying total Years, Months, Days. I am looking for a way
to have results provide a roll BY "Created_Date" records and include:
Years, Months, Days and outstanding days providing 30 Days, 60 Days, 90 Days? Can you suggest something with a similar result?
Scrip Code:
DECLARE #FromDate DATETIME = '2015-01-01 00:00:00',
#ToDate DATETIME = '2019-09-18 00:00:00',
#Years INT, #Months INT, #Days INT, #tmpFromDate DATETIME
SET #Years = DATEDIFF(YEAR, #FromDate, #ToDate)
- (CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, #FromDate, #ToDate),
#FromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(YEAR, #Years , #FromDate)
SET #Months = DATEDIFF(MONTH, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(MONTH,DATEDIFF(MONTH, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(MONTH, #Months , #tmpFromDate)
SET #Days = DATEDIFF(DAY, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(DAY, DATEDIFF(DAY, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SELECT #FromDate FromDate, #ToDate ToDate,
#Years Years, #Months Months, #Days Days
SELECT DISTINCT
ge.Name, --table columns
ge.Entity_Type,
ge.Entity_Number,
bc.Super_Entity_ID,
ch.Check_Date, --check created
ch.Created_Date, --if payment was received
ch.Check_Number,
ch.Amount,
vn.Vendor_Name
Check_Date,Created_Date,DATEDIFF("DAY",Check_Date,Created_Date) AS DAY
FROM dbo.gl_entities AS ge
INNER JOIN
dbo.super_entity AS se
ON ge.Super_Entity_ID = se.Super_Entity_ID
INNER JOIN
dbo.bank_codes AS bc
ON se.Super_Entity_ID = bc.Super_Entity_ID
INNER JOIN
dbo.checks AS ch
ON bc.Bank_Code_ID = ch.Bank_Code_ID
INNER JOIN
dbo.vendors AS vn
ON ch.Vendor_ID = vn.Vendor_ID
WHERE
ge.Active = 1 and vn.active = 1 and (ge.IS_Shadow = 1 OR se.IS_Tiered = 0)
AND CHECK_DATE > '20150101 00:00:00'
AND CHECK_DATE< '20190918 00:00:00'
ORDER BY ch.Check_Date, ch.Created_Date

To simply repeat them in their own columns in the query:
DECLARE #FromDate DATETIME = '2015-01-01 00:00:00',
#ToDate DATETIME = '2019-09-18 00:00:00',
#Years INT, #Months INT, #Days INT, #tmpFromDate DATETIME
SET #Years = DATEDIFF(YEAR, #FromDate, #ToDate)
- (CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, #FromDate, #ToDate),
#FromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(YEAR, #Years , #FromDate)
SET #Months = DATEDIFF(MONTH, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(MONTH,DATEDIFF(MONTH, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(MONTH, #Months , #tmpFromDate)
SET #Days = DATEDIFF(DAY, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(DAY, DATEDIFF(DAY, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SELECT DISTINCT
ge.Name, --table columns
ge.Entity_Type,
ge.Entity_Number,
bc.Super_Entity_ID,
ch.Check_Date, --check created
ch.Created_Date, --if payment was received
ch.Check_Number,
ch.Amount,
vn.Vendor_Name,
Check_Date,Created_Date,DATEDIFF("DAY",Check_Date,Created_Date) AS DAY,
#FromDate FromDate, #ToDate ToDate, #Years Years, #Months Months, #Days Days
FROM
. . .
If you run into problems with the DISTINCT clause, you can always use a subquery. If you want Years, Months, Days to be different based on one of the columns, you'll have to elaborate and then we can move everything you did in the SET statements into the SELECT statement.
Without your tables and data I cannot test very well.

pseudocode to try and demonstrate moving set statements to select statements
declare #begin date = '2018-01-01'
declare #end date = '2019-01-01'
declare #middletest int = datediff("dd", #begin, #end)/2
declare #middledate date = dateadd("dd", #middletest, #begin)
declare #middlemonth int = month(#middledate)
select #middlemonth half_month, #middledate middle_date
-- ,other_columns here
from table
where something
Start replacing.
#middlemonth is in the select statement so replace it with month(#middledate).
declare #begin date = '2018-01-01'
declare #end date = '2019-01-01'
declare #middletest int = datediff("dd", #begin, #end)/2
declare #middledate date = dateadd("dd", #middletest, #begin)
select month(#middledate) half_month, #middledate middle_date
-- ,other_columns here
from table
where something
#middledate is now in the select statement in 2 places so replace it with dateadd("dd", #middletest, #begin) each time.
declare #begin date = '2018-01-01'
declare #end date = '2019-01-01'
declare #middletest int = datediff("dd", #begin, #end)/2
select month(dateadd("dd", #middletest, #begin)) half_month,
dateadd("dd", #middletest, #begin) middle_date
-- ,other_columns here
from table
where something
Continue along.
declare #begin date = '2018-01-01'
declare #end date = '2019-01-01'
select month(dateadd("dd", datediff("dd", #begin, #end)/2, #begin)) half_month,
dateadd("dd", datediff("dd", #begin, #end)/2, #begin) middle_date
-- ,other_columns here
from table
where something
And you can, as desired, replace things with values from the table. If the table has a column start_date and you want that to be the begin and then use the current date as the end:
select month(dateadd("dd", datediff("dd", start_date, getdate())/2, start_date)) half_month,
dateadd("dd", datediff("dd", start_date, getdate())/2, start_date) middle_date
-- ,other_columns here
from table
where something

Related

Get the remaining days between two dates

I am trying to calculate the remaining year, month and days between 2 dates using the method below, but I cannot get the remaining dates right. Is there a function or different method I should try?
Select (DATEDIFF(m, '1965-10-17', '2021-04-07')) /12 as AgeYr ,
(DATEDIFF(m, '1965-10-17', '2021-04-07')) %12 as AgeMth,
(DATEDIFF(d, '1965-10-17', '2021-04-07')) %30 as AgeDay;
This is the result of my code
AgeYr
AgeMth
AgeDay
55
6
10
but the result should be
AgeYr
AgeMth
AgeDay
55
6
21
DECLARE #date datetime, #startdate datetime, #enddate datetime, #years int, #months int, #days int
SELECT #startdate = '1965-10-17'
SELECT #enddate = '2021-04-07'
SELECT #date = #startdate
SELECT #years = DATEDIFF(yy, #startdate, #enddate) - CASE WHEN (MONTH(#date) > MONTH(#enddate)) OR (MONTH(#date) = MONTH(#enddate) AND DAY(#date) > DAY(#enddate)) THEN 1 ELSE 0 END
SELECT #startdate = DATEADD(yy, #years, #startdate)
SELECT #months = DATEDIFF(m, #startdate, #enddate) - CASE WHEN DAY(#date) > DAY(#enddate) THEN 1 ELSE 0 END
SELECT #startdate = DATEADD(m, #months, #startdate)
SELECT #days = DATEDIFF(d, #startdate, #enddate)
SELECT #years years, #months months, #days days
Output:
AgeYr
AgeMth
AgeDay
55
5
21
db<>fiddle here
You can also do it with common table expression:
;with years as
(SELECT (DATEDIFF(yy, '1965-10-17', '2021-04-07') - CASE WHEN (MONTH('1965-10-17') > MONTH('2021-04-07')) OR (MONTH('1965-10-17') = MONTH('2021-04-07') AND DAY('1965-10-17') > DAY('2021-04-07')) THEN 1 ELSE 0 END)AgeYr,
'1965-10-17' startdate)
,months as
(SELECT (DATEDIFF(m, DATEADD(yy, years.AgeYr, '1965-10-17'), '2021-04-07') - CASE WHEN DAY('1965-10-17') > DAY('2021-04-07') THEN 1 ELSE 0 END)AgeMth, DATEADD(yy, years.AgeYr, '1965-10-17') temp
from years)
,days as
(select DATEDIFF(d, DATEADD(m, months.AgeMth, temp), '2021-04-07')AgeDay from months)
select years.AgeYr,months.AgeMth,days.AgeDay from years,months,days
Output:
AgeYr
AgeMth
AgeDay
55
5
21
db<>fiddle here

SQL function in view table

I have this function which shows years, months and days between dates. On a view table I have data with start and finish dates. How is it possible to integrate that function it into my view table?
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter FUNCTION [db].[GetDateDifference]
(
#FromDate DATETIME, #ToDate DATETIME
)
RETURNS
#DateDifference TABLE (
YEAR INT, MONTH INT, DAYS INT)
AS
BEGIN
DECLARE #Years INT, #Months INT, #Days INT, #tmpFromDate DATETIME
SET #Years = DATEDIFF(YEAR, #FromDate, #ToDate)
- (CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, #FromDate, #ToDate),
#FromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(YEAR, #Years , #FromDate)
SET #Months = DATEDIFF(MONTH, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(MONTH,DATEDIFF(MONTH, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(MONTH, #Months , #tmpFromDate)
SET #Days = DATEDIFF(DAY, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(DAY, DATEDIFF(DAY, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
INSERT INTO #DateDifference
VALUES(#Years, #Months, #Days)
RETURN
END
and here is my view table:
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter VIEW [db].[View_ServiceTickets]
AS
SELECT TOP 99
ServiceTicketDate,
BillingDate as 'Project Finished',
InspectionScheduleDate
FROM tblServiceTicket INNER JOIN
tblServiceTicketReport on tblServiceTicket.ServiceTicketID = tblServiceTicketReport.ServiceTicketID
where ServiceTicketDate > '2016'
order by ServiceTicketDate desc
GO
Thank you so much
I saw the return data type of your function is a table, so you use treat it as a table.
you can test the following:
alter VIEW [db].[View_ServiceTickets]
AS
SELECT TOP 99
ServiceTicketDate,
BillingDate as 'Project Finished',
InspectionScheduleDate,
d.*
FROM tblServiceTicket INNER JOIN
tblServiceTicketReport on tblServiceTicket.ServiceTicketID = tblServiceTicketReport.ServiceTicketID
OUTER APPLY(SELECT YEAR,MONTH,DAYS FROM [db].[GetDateDifference](ServiceTicketDate,BillingDate)) d
where ServiceTicketDate > '2016'
order by ServiceTicketDate desc

SQL Table-Valued User-Defined Functions between TWo dates

I need to build a table valued user defined function using two parameters
input like select * from func_1('01/01/2012','09/09/2015');
output should be like :
month quator semi_annual annual
1 1 1 2012
2 1 1 2012
3 1 1 2012
4 2 1 2012
5 2 1 2012
6 2 1 2012
7 3 2 2012
. . . ...
. . . ....
upto
9 3 2 2015
I need a table valued function for this.
i tried a code like this
create function func3_D_D
(#startDate date, #endDate date)
RETURNS #dates table
(months int,quatorly int,Semi_anuual int,Annual int)
As
Begin
declare
#months int,
#quatorly int,
#Semi_anuual int,
#Annual int;
select #months= DATEDIFF(MONTH, #startDate, #endDate);
select #quatorly= DATEDIFF(QUARTER, #startDate, #endDate);
select #Semi_anuual= DATEDIFF(QUARTER, #startDate, #endDate)/ 2;
select #Annual= DATEDIFF(YEAR, #startDate, #endDate);
WHILE (#endDate > #startDate)
begin
insert into #dates
select #months,#quatorly,#Semi_anuual,#Annual;
End;
return;
End;
Using a loop for this is about a awful for performance as you can get. You need to use a tally table for this type of thing. You need to start thinking in sets instead of row by row. Once you have a tally table (which I generated here with a cte), this is pretty simple.
create function MyFunctionThatGetsDatesByRange
(
#StartDate DATE
, #EndDate DATE
) RETURNS TABLE WITH SCHEMABINDING AS RETURN
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select DATEADD(DAY, N - 1, #StartDate) as date
, DATEPART(MONTH, DATEADD(DAY, N - 1, #StartDate)) as Month
, DATEPART(QUARTER, DATEADD(DAY, N - 1, #StartDate)) as Quarter
, CASE when DATEPART(QUARTER, DATEADD(DAY, N - 1, #StartDate)) <= 2 then 1 else 2 end as SemiAnnual
, DATEPART(YEAR, DATEADD(DAY, N - 1, #StartDate)) as Annual
from cteTally
where N <= DATEDIFF(DAY, #StartDate, #EndDate);
GO
declare #StartDate date = '2012-01-01'
, #EndDate date = '2015-09-09';
select *
from dbo.MyFunctionThatGetsDatesByRange(#StartDate, #EndDate)
hi thanks for your reply i achived that by using the below code.
create function func5_D_D
(#startDate date, #endDate date)
RETURNS #dates table
(months int,
quators int,
semi_annual int,
annual int)
As
Begin
WHILE #startDate <= #endDate
BEGIN
INSERT INTO #dates(months,quators,semi_annual,annual) values (MONTH(#startDate), datepart(qq,#startDate),
case when datepart(qq,#startDate) in (1,2) then 1 else
2 End,datepart(yyyy,#startdate))
SET #startDate = DATEADD(MONTH,1,#startDate)
END
return;
end;
Difference between two dates in X years Y Months and Z days (For example: Age in Years, Months and days)
We can use a script like below to get the difference between two dates in Years, Months and days.
Difference between two dates in X years Y Months and Z days (For example: Age in Years, Months and days)
We can use a script like below to get the difference between two
datDECLARE #FromDate DATETIME = '2010-01-01 23:59:59.000',
#ToDate DATETIME = '2015-01-02 00:00:00.000',
#Years INT, #Months INT, #Days INT, #tmpFromDate DATETIME
SET #Years = DATEDIFF(YEAR, #FromDate, #ToDate)
- (CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, #FromDate, #ToDate),
#FromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(YEAR, #Years , #FromDate)
SET #Months = DATEDIFF(MONTH, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(MONTH,DATEDIFF(MONTH, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(MONTH, #Months , #tmpFromDate)
SET #Days = DATEDIFF(DAY, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(DAY, DATEDIFF(DAY, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SELECT #FromDate FromDate, #ToDate ToDate,
#Years Years, #Months Months, #Days Days
s in Years, Months and days.

how view result date time datediff dateadd , but out-of-range value

i try compare date now and start date working from master_employee.
but i failed...
if at line i write
select #date = date_start
from Master_Employee
where id = '2'
its succes.
but i hope, can view all result in table Master_Employee.
can you help me ?
thank's very much..
DECLARE #date DATETIME
,#tmpdate DATETIME
,#years INT
,#months INT
,#days INT
SELECT #date = date_Start
FROM Master_Employee
SELECT #tmpdate = #date
SELECT #years = DATEDIFF(yyyy, #tmpdate, GETDATE()) - CASE
WHEN (MONTH(#date) > MONTH(GETDATE()))
OR (
MONTH(#date) = MONTH(GETDATE())
AND DAY(#date) > DAY(GETDATE())
)
THEN 1
ELSE 0
END
SELECT #tmpdate = DATEADD(yyyy, #years, #tmpdate)
SELECT #months = DATEDIFF(mm, #tmpdate, GETDATE()) - CASE
WHEN DAY(#date) > DAY(GETDATE())
THEN 1
ELSE 0
END
SELECT #tmpdate = DATEADD(mm, #months, #tmpdate)
SELECT #days = DATEDIFF(dd, #tmpdate, GETDATE())
SELECT #years AS Years
,#months AS Months
,#days AS Dayss
,GETDATE() AS Date_Now
This will give you how many days, months, years have passed in aggregate for all employees, As far as I can tell this is what you are tying to do.
DECLARE #Today as datetime = CONVERT(Date,GETDATE())
SELECT SUM(DATEDIFF(day,ISNULL(convert(datetime,#date),Today),#Today)) [Days]
,SUM(DATEDIFF(MONTH,ISNULL(convert(datetime,#date),Today),#Today)) [Months]
,SUM(DATEDIFF(Year,ISNULL(convert(datetime,#date),Today(,#Today)) [Years]
FROM Master_Employee
The reason that
SELECT #date = date_Start
FROM Master_Employee
is failing is because you are trying to assign all the start dates to the same variable.
If you want separate lines for each employee try:
DECLARE #Today as datetime = CONVERT(Date,GETDATE())
SELECT Id
,SUM(DATEDIFF(day,ISNULL(convert(datetime,#date),Today),#Today)) [Days]
,SUM(DATEDIFF(MONTH,ISNULL(convert(datetime,#date),Today),#Today)) [Months]
,SUM(DATEDIFF(Year,ISNULL(convert(datetime,#date),Today),#Today)) [Years]
FROM Master_Employee
GROUP BY ID
Be careful, month and year can be misleading, if the person started 12/31/14 and you ran this on 1/1/15 you will see 1 day, 1 month, 1 year. You might be better off using only days and figuring your own math for how long that is...

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