DECLARE #MyDate Datetime
set #MyDate = GETDATE();
WITH cte AS
(SELECT #MyDate AS AllDates,
1 AS [count_all_days],
CASE WHEN DATENAME(dw, DATEADD(dd, - 1, #MyDate)) IN ('Saturday', 'Sunday') THEN 1 ELSE 0 END AS [count_week_days]
UNION ALL
SELECT DATEADD(dd, - [count_all_days], #MyDate),
[count_all_days] + 1,
CASE WHEN DATENAME(dw, DATEADD(dd, - [count_all_days], #MyDate)) IN ('Saturday', 'Sunday') THEN [count_week_days] + 1 ELSE [count_week_days]
END
FROM cte
WHERE [count_all_days] - [count_week_days] < 16
)
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, AllDates))
FROM cte left join EmpLog ON AllDates = EmpLog.Date
left JOIN Holiday ON AllDates = Holiday.HolDate
WHERE DATENAME(dw, AllDates) NOT IN ('Saturday', 'Sunday')AND AllDates NOT IN (Select EmpLog.Date from EmpLog where EmpLog.EmpID = 1)and Holiday.HolDate IS NULL
This SQL query displays the current date and the previous 16 days. wherein those dates are not equal to the existing date on the HOLIDAY table and in the EMPLOG table.
My problem is this query works on SQL Server 2008 well but when I tried it on SQL Server 2005 it only displays the current date and the previous 16 days even though some days are in HOLIDAY and EMPLOG table.
Can someone help me please? thanks!
Try casting your Date variables -- you're comparing GetDate to Dates that don't necessarily have the same time:
left JOIN Holiday ON CAST(AllDates as Date) = CAST(Holiday.HolDate as Date)
Wrap that with all your dates and it should work. Take a look at this SQL Fiddle. In this example, I've only added 1 holiday, 1/21/2013 (MLK).
EDIT --
Try using convert(varchar, getdate(), 101) to CAST the date since SQL Server 2005 doesn't support the Date type.
Here is the updated SQL:
left JOIN Holiday ON convert(varchar, AllDates, 101) = convert(varchar, Holiday.HolDate, 101)
Do that on all your date conversions. Here is the updated Fiddle.
Thanks #user148298 for pointing this out.
Good luck.
There appears to be some differences between dates in 2008 and 2005. You have to set your database compatibility. See the following article:
http://msdn.microsoft.com/en-us/library/bb510680.aspx
Try changing the #MyDate initialisation to:
set #MyDate = Convert(DATETIME(CONVERT(VARCHAR(10), GETDATE(), 121) + ' 00:00:00', 121);
Explanation: By doing this you make the #MyDate as a "midnight today", instead of "today with current time". That way it would better join with your tables.
Assumption: The dates in your holiday tables are stored as "midnight"
Related
I am trying to write a report whereby the report will have the contract updated records for the past week using ms sql script. Every Monday the report will be sent for the last Mon-sun. I tried the below query. it doesnt seems to work. Any idea how to achieve this?
SET DATEFIRST 1
select distinct [...]
where CONTRACT_UPDATE_DATE>= dateadd(day, 1-datepart(dw, getdate()), CONVERT(date,getdate()))
AND CONTRACT_UPDATE_DATE< dateadd(day, 8-datepart(dw, getdate()), CONVERT(date,getdate()))
Thanks.
select * from table_abc WHERE
CAST(CONTRACT_UPDATE_DATE as date) between
CAST(DATEADD(dd, -7, GETDATE()) as date) and
CAST(GETDATE() AS DATE)
use dateadd to get 1 week before current date.
You can remove the cast as date if you need to validate by timestamp also.
You can try this,
SELECT Created_Date
FROM sample1
WHERE Created_Date >= DATEADD(day,-11117, GETDATE())
I suggest this solution:
select * from DB where Datediff(day, CONVERT(DATE, Sysdatetime()),
CONVERT(DATE, CONTRACT_UPDATE_DATE))<=7 and Datediff(day, CONVERT(DATE, Sysdatetime()),
CONVERT(DATE, CONTRACT_UPDATE_DATE))>0
You could try to achieve this by using the calender week.
Try the following:
-- Get last calendar week in format JJJJWW
DECLARE #jjjjkw varchar(6)
SELECT #jjjjkw =
CONVERT(varchar, DATEPART(YYYY,GETDATE()-7)) +
CASE WHEN LEN(CONVERT(varchar,DATEPART(ISO_WEEK,GETDATE()-7))) = 1 THEN '0'
+ CONVERT(varchar,DATEPART(ISO_WEEK,GETDATE()-7))
ELSE CONVERT(varchar,DATEPART(ISO_WEEK,GETDATE()-7)) END
-- Compare with the calendar week of your data-set
SELECT DISTINCT [...]
WHERE
CONVERT(varchar, DATEPART(YYYY,CONTRACT_UPDATE_DATE)) +
CASE WHEN LEN(CONVERT(varchar,DATEPART(ISO_WEEK,CONTRACT_UPDATE_DATE))) = 1
THEN '0' + CONVERT(varchar,DATEPART(ISO_WEEK,CONTRACT_UPDATE_DATE))
ELSE CONVERT(varchar,DATEPART(ISO_WEEK,CONTRACT_UPDATE_DATE)) END = #jjjjkw
Maybe not the most elegant way but it should work.
I have an issue regarding date calculations.
I have a datetime column called CreatedLocalTime date with this format: 2015-11-15 19:48:50.000
I need to retrieve a new column called Prod_Date with:
if “CreatedLocalTime” between
(CreatedLocalTime 7 AM)
& (CreatedLocalTime+1 7 AM)
return CreatedLocalTime date with DD/MM/YYYY format
On other words, today production = sum of yesterday from 7 AM till today at 7 AM.
Any help using case?
For day 7AM to day+1 7AM, you can try:
SELECT CAST(CreatedLocalTime as date)
...
FROM ...
WHERE ...
CreatedLocalTime >= DATEADD(hour, 7, CAST(CAST(CreatedLocalTime as date) as datetime))
AND
CreatedLocalTime < DATEADD(hour, 31, CAST(CAST(CreatedLocalTime as date) as datetime))
...
For previous day 7AM to day 7AM, replace 7 by -14 and 31 by 7.
Another way..
SELECT CASE WHEN CreatedLocalTime BETWEEN DATEADD(HOUR, 7,
CAST(CAST (CreatedLocalTime AS DATE) AS DATETIME))
AND DATEADD(HOUR, 31,
CAST(CAST (CreatedLocalTime AS DATE) AS DATETIME))
THEN REPLACE(CONVERT(NVARCHAR, CreatedLocalTime, 103), ' ', '/')
END AS CreatedLocalTime
You can write the else part for this, if needed
It looks like you want somthing along the lines of
DECLARE #StartDateTime Datetime
DECLARE #EndDateTime Datetime
SET #EndDateTime = DATEADD(hour, 7,convert(datetime,convert(date,getdate())) )
SET #StartDateTime = DATEADD(day, -1, #EndDateTime )
--Print out the variables for demonstration purposes
PRINT '#StartDateTime = '+CONVERT(nchar(19), #StartDateTime,120)
PRINT '#EndDateTime = '+CONVERT(nchar(19), #EndDateTime,120)
SELECT SUM (Production) AS Prod_Date FROM YourSchema.YourTable WHERE CreatedLocalTime >= #StartDateTime AND CreatedLocalTime < #EndDateTime
But you could also look at it as all the times which after you remove 7 hours from them are yesterday
SELECT SUM (Production) AS Prod_Date
FROM YourSchema.YourTable
WHERE DATEDIFF(day,DATEADD(hour, -7, CreatedLocalTime ))) = 1
The First version will be more efficient as the query will only have to do the date arithmetic once at the start while the second involved executing DATEDIFF and DATEADD for every record. This will be slower on large amounts of data.
The Gold plated solution would be to add a computed column to your table
ALTER TABLE YourSchema.YourTable ADD EffectiveDate AS CONVERT(date, DATEDIFF(day,DATEADD(hour, -7, CreatedLocalTime ))))
And then an index on that column
CREATE INDEX IX_YourTable_EffectiveDate ON YourSchema.YourTable (EffectiveDate )
So you can write
DECLARE #YesterDay date = DATEADD(day,-1, getdate())
SELECT SUM (Production) AS Prod_Date
FROM YourSchema.YourTable
WHERE EffectiveDate = #YesterDay
i have an ssis Package which runs on business days (mon-Fri). if i receive file on tuesday , background(DB), it takes previous business day date and does some transactions. If i run the job on friday, it has to fetch mondays date and process the transactions.
i have used the below query to get previous business date
Select Convert(varchar(50), Position_ID) as Position_ID,
TransAmount_Base,
Insert_Date as InsertDate
from tblsample
Where AsOfdate = Dateadd(dd, -1, Convert(datetime, Convert(varchar(10), '03/28/2012', 101), 120))
Order By Position_ID
if i execute this query i'll get the results of yesterdays Transactios. if i ran the same query on monday, it has to fetch the Fridays transactions instead of Sundays.
SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
I prefer to use DATENAME for things like this over DATEPART as it removes the need for Setting DATEFIRST And ensures that variations on time/date settings on local machines do not affect the results. Finally DATEDIFF(DAY, 0, GETDATE()) will remove the time part of GETDATE() removing the need to convert to varchar (much slower).
EDIT (almost 2 years on)
This answer was very early in my SO career and it annoys me everytime it gets upvoted because I no longer agree with the sentiment of using DATENAME.
A much more rubust solution would be:
SELECT DATEADD(DAY, CASE (DATEPART(WEEKDAY, GETDATE()) + ##DATEFIRST) % 7
WHEN 1 THEN -2
WHEN 2 THEN -3
ELSE -1
END, DATEDIFF(DAY, 0, GETDATE()));
This will work for all language and DATEFIRST settings.
This function returns last working day and takes into account holidays and weekends. You will need to create a simple holiday table.
-- =============================================
-- Author: Dale Kilian
-- Create date: 2019-04-29
-- Description: recursive function returns last work day for weekends and
-- holidays
-- =============================================
ALTER FUNCTION dbo.fnGetWorkWeekday
(
#theDate DATE
)
RETURNS DATE
AS
BEGIN
DECLARE #importDate DATE = #theDate
DECLARE #returnDate DATE
--Holidays
IF EXISTS(SELECT 1 FROM dbo.Holidays WHERE isDeleted = 0 AND #theDate = Holiday_Date)
BEGIN
SET #importDate = DATEADD(DAY,-1,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
--Satruday
IF(DATEPART(WEEKDAY,#theDate) = 7)
BEGIN
SET #importDate = DATEADD(DAY,-1,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
--Sunday
IF(DATEPART(WEEKDAY,#theDate) = 1)
BEGIN
SET #importDate = DATEADD(DAY,-2,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
RETURN #importDate;
END
GO
Then how about:
declare #dt datetime='1 dec 2012'
select case when 8-##DATEFIRST=DATEPART(dw,#dt)
then DATEADD(d,-2,#dt)
when (9-##DATEFIRST)%7=DATEPART(dw,#dt)%7
then DATEADD(d,-3,#dt)
else DATEADD(d,-1,#dt)
end
The simplest solution to find the previous business day is to use a calendar table with a column called IsBusinessDay or something similar. The your query is something like this:
select max(BaseDate)
from dbo.Calendar c
where c.IsBusinessDay = 0x1 and c.BaseDate < #InputDate
The problem with using functions is that when (not if) you have to create exceptions for any reason (national holidays etc.) the code quickly becomes unmaintainable; with the table, you just UPDATE a single value. A table also makes it much easier to answer questions like "how many business days are there between dates X and Y", which are quite common in reporting tasks.
You can easily make this a function call, adding a second param to replace GetDate() with whatever date you wanted.
It will work for any day of the week, at any date range, if you change GetDate().
It will not change the date if the day of week is the input date (GetDate())
Declare #DayOfWeek As Integer = 2 -- Monday
Select DateAdd(Day, ((DatePart(dw,GetDate()) + (7 - #DayOfWeek)) * -1) % 7, Convert(Date,GetDate()))
More elegant:
select DATEADD(DAY,
CASE when datepart (dw,Getdate()) < 3 then datepart (dw,Getdate()) * -1 + -1 ELSE -1 END,
cast(GETDATE() as date))
select
dateadd(dd,
case DATEPART(dw, getdate())
when 1
then -2
when 2
then -3
else -1
end, GETDATE())
thanks for the tips above, I had a slight variant on the query in that my user needed all values for the previous business date. For example, today is a Monday so he needs everything between last Friday at midnight through to Saturday at Midnight. I did this using a combo of the above, and "between", just if anyone is interested. I'm not a massive techie.
-- Declare a variable for the start and end dates.
declare #StartDate as datetime
declare #EndDate as datetime
SELECT #StartDate = DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
select #EndDate = #StartDate + 1
select #StartDate , #EndDate
-- Later on in the query use "between"
and mydate between #StartDate and #EndDate
I have a database which contains two dates which I am concerned with.
StartDate +
EndDate
These dates are stored in the following format:
2008-06-23 00:00:00.000
I need to add a piece of dynamic SQL to only bring back dates which fall in the current financial year.
so for example 01/04/2011 - 31/03/2012 would be this financial year.
Therfore any record whos enddate is within these dates, or is NULL is classed as 'active'
The year part will need to be dynamic so that as soon as it hits 1st April 2012 we move into the new financial year and will be bringing data back from 01/04/2012 - 31/03/13 and so on.
Can suggest some code or point out any rules I have overlooked?
Try:
...
where StartDate >=
case
when month(getdate()) > 3
then convert(datetime, cast(year(getdate()) as varchar) + '-4-1')
else
convert(datetime, cast(year(getdate()) - 1 as varchar) + '-4-1')
end
and (EndDate is null or EndDate <
case
when month(getdate()) > 3
then convert(datetime, cast(year(getdate()) + 1 as varchar) + '-4-1')
else
convert(datetime, cast(year(getdate()) as varchar) + '-4-1')
end)
Here we go :)
Dynamic solution,
DECLARE #MyDate DATETIME
SET #MyDate = getDate()
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = DATEADD(dd,0, DATEDIFF(dd,0, DATEADD( mm, -(((12 + DATEPART(m, #MyDate)) - 4)%12), #MyDate ) - datePart(d,DATEADD( mm, -(((12 + DATEPART(m, #MyDate)) - 4)%12),#MyDate ))+1 ) )
SET #EndDate = DATEADD(ss,-1,DATEADD(mm,12,#StartDate ))
SELECT #StartDate,#EndDate
Create a Finacial_Year lookup table containing the fields financial_year_start and financial_year_end.
Populate it with the next 50 years of data (easy to do using a spread sheet to calulate the dates).
Join your table to the lookup table using enddate
SELECT ...
FROM Your_Table LEFT JOIN Financial_Year
ON Your_Table.enddate BETWEEN Financial_Year.financial_year_start
AND Financial_Year.financial_year_end
WHERE Your_Table.enddate IS NULL -- Active
OR (getdate() BETWEEN Financial_Year.financial_year_start
AND Financial_Year.financial_year_end)
The current financial will change automatically when the current date falls between the next two dates.
BTW the UK financial year runs from 06-04-YYYY to 05-04-YYYY, not the 1st to the 31st.
Well this is my case: I have an input date X (dd-mm-yyyy), and I want to count the number of days between it with the year part is changed into current year and today's date in SQL. I t comes with the following condition, after the year is changed temporarily: (Here's my current idea of the logic)
- If date X is earlier than today, then difference = datediff(X,now), with the X year is current year
- If date X is later than today, then difference = datediff(X,now), with the X year is one year before
Sample case:
1st case: The input date is 6-6-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(6-6-2011,22-08-2011)
2nd case: The input date is 10-10-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(10-10-2010,22-08-2011)
Any idea how to do this in SQL (in SQL Server)? Or is there any other more simple alternatives for this problem? I'd also like this to be done in the query and not using a stored procedure or function
Sorry if there's already a similar question, I just don't know the exact keyword for this problem :( if there's a question like this previously, feel free to direct me there.
Thanks in advance
Here is the implementation (if I understood the logic you need correctly):
USE YourDbName
GO
CREATE FUNCTION YearPartDiff (#date datetime)
RETURNS int
AS
BEGIN
DECLARE #dateCurrentYear datetime
SET #dateCurrentYear = DATEADD(year, YEAR(GETDATE()) - YEAR(#date), #date)
DECLARE #result int
IF #dateCurrentYear < GETDATE()
SET #result = ABS(DATEDIFF(day, #dateCurrentYear, GETDATE()))
ELSE
SET #result = ABS(DATEDIFF(day, DATEADD(year, -1, #dateCurrentYear), GETDATE()))
RETURN(#result)
END
GO
And the example of usage:
USE YourDbName
GO
DECLARE #someDate datetime
SET #someDate = '2011-06-06'
SELECT dbo.YearPartDiff(#someDate) /*returns 77*/
SET #someDate = '2010-10-10'
SELECT dbo.YearPartDiff(#someDate) /*returns 316*/
Basically, #Andrei's solution, but in a single statement:
SELECT
DayDiff = DATEDIFF(
DAY,
DATEADD(YEAR, CASE WHEN LastOcc > GETDATE() THEN -1 ELSE 0 END, LastOcc),
GETDATE()
)
FROM (
SELECT LastOcc = DATEADD(YEAR, YEAR(GETDATE()) - YEAR(#InputDate), #InputDate)
) s
This seems to do the job
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'2011-06-06'), CONVERT(DATETIME, N'2011-08-22'))
So the basic syntax is
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'yyyy-mm-dd'), CONVERT(DATETIME, N'yyyy-mm-dd '))
Alternatively, you can use GETDATE() instead of the string for today's date
I have used "SELECT DATEDIFF( D, "+myDate+", GETDATE())" in my code, on SQL Server 2005. It works for me. The value myDate of course would be the DateTime input value.
you should try this query:
create table #T (inp_date datetime)
insert #T values ('06-06-1990')
insert #T values ('08-22-1990')
insert #T values ('10-10-1990')
--select * from #T
select inp_date, GETDATE(),
CASE
WHEN DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date) <= GETDATE()
THEN DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date),GETDATE())
ELSE DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE())-1,inp_date),GETDATE())
END
from #T