MS SQL Server - Datediff excluding weekends - sql-server

I am trying to find the difference between two dates in SQL but ignoring weekends...
I've tried looking at other answers and keep getting the error:
Msg 4104, Level 16, State 1, Line 7
The multi-part identifier "ste.TransactionDate" could not be bound.
My current code is:
DATEDIFF(WEEKDAY, ste.TransactionDate, ste.SettlementDate) AS DaysToCSD,
and I did change this to
DECLARE #d1 datetime, #d2 datetime
SELECT #d1 = ste.TransactionDate, #d2 = ste.SettlementDate
SELECT DATEDIFF(dd, #d1, #d2) - (DATEDIFF(wk, #d1, #d2) * 2) -
CASE WHEN DATEPART(dw, #d1) = 1 THEN 1 ELSE 0 END +
CASE WHEN DATEPART(dw, #d2) = 1 THEN 1 ELSE 0 END
I am not great at SQL..not a dev...so any help appreciated!

Related

Declaring a scalar value for a date parameter

I am trying to set a value for a 2 parameters in SQL:
#DateLoading
#DateLoading2
I declare them as datetime:
DECLARE #DateLoading AS datetime
DELCARE #DateLoading2 AS datetime
In the WHERE clause I set the parameters as following:
WHERE
o.DateLoading >= #Datetoloading AND
o.DateLoading < #Datetoloading2 AND
I have problem setting the scalar value. I've tried with this code, but the error is the same:
SET #DateLoading = COALESCE(CASE WHEN #DateLoading = 'Current Month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) ELSE NULL END,
CASE WHEN #DateLoading = 'Previous Month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0) ELSE NULL END,
CASE WHEN #DateLoading = 'Previous 7 Days' THEN DATEADD(HOUR, 6, DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()) - 1, 0)) ELSE NULL END,
DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0)
);
SET #DateLoading2 = COALESCE(
CASE WHEN #DateLoading2= 'Current Month' THEN DATEADD(DAY,DATEDIFF(DAY,0,GETDATE()),0) ELSE NULL END,
CASE WHEN #DateLoading2= 'Previous Month' THEN DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),0) ELSE NULL END,
CASE WHEN #DateLoading2= 'Previous 7 Days' THEN DATEADD(HOUR,6,DATEADD(DAY,DATEDIFF(DAY,0,GETDATE()),0)) ELSE NULL END,
GETDATE()
)
Here is the error messages:
Msg 137, Level 15, State 2, Line 6
Must declare the scalar variable "#TimePeriod".
Msg 102, Level 15, State 1, Line 16
Incorrect syntax near 'E'
Yes, you were right. I got rid of [S, [E]... (I wanted them to be alias) but I got rid of them... Also, the second mistake was #TimePeriod... I changed it to #DateLoading... But now, there is only 1 error message:
Conversion failed when converting data and/or time from character string
The client should enter Start Date and End Date so as to receive results. But the code I have for setting the scalar value for these two parameters is totally wrong.

TSQL: How to change date if date falls between current year dates?

I need to change a passed variable date if the date falls under the current year Nov 1st to Dec 31st
How to do this in TSQL?
Example:
Example #1
#ip_batch_date = '2020-12-01T00:00:00'
check #ip_batch_date >=' '2020-11-01T00:00:00' AND #ip_batch_date<='2020-12-31T00:00:00'
Then #ip_batch_date = '2021-01-01T00:00:00'
Example #2
#ip_batch_date = '2021-11-15T00:00:00'
check #ip_batch_date >='2021-11-01T00:00:00' AND #ip_batch_date<='2021-12-31T00:00:00'
Then #ip_batch_date = '2022-01-01T00:00:00'
Assuming you already have a passed in date variable called #ip_batch_date, off the top of my head I would use something like
IF (YEAR(#ip_batch_date) = YEAR(GetDate()) AND MONTH(#ip_batch_date) BETWEEN 11 AND 12)
SET #ip_batch_date = DATEFROMPARTS(YEAR(GetDate())+1,1,1);
If instead of a passed in date, you were writing a query that was going to process lots of rows with a date column in them that you wanted to subject this logic to, it would be best not to have ip_date_column converted by a function, but rather to leave the date column bare and compare it to two constructed dates, like this:
CASE WHEN my_date_column BETWEEN DATEFROMPARTS(YEAR(GetDate()),11,1)
DATEFROMPARTS(YEAR(GetDate()),12,31)
THEN DATEFROMPARTS(YEAR(GetDate())+1,1,1);
ELSE my_date_column
END
Finally, if my_date_column was a datetime or datetime2 column instead of just a date, make sure you you datetimefromparts or datetime2fromparts instead, and add the time in as well to avoid last day boundary issues
If I understood your question correctly:
DECLARE #Date DATETIME
SET #Date = '2020-12-01T00:00:00'
SET #Date = CASE WHEN RIGHT(CONVERT(VARCHAR(8), #Date, 112), 4) >= 1101 THEN DATEADD(yy, DATEDIFF(yy, 0, #Date) + 1, 0) ELSE #Date END
SELECT #Date
-- Output : 2021-01-01 00:00:00.000
SET #Date = '2021-12-01T00:00:00'
SET #Date = CASE WHEN RIGHT(CONVERT(VARCHAR(8), #Date, 112), 4) >= 1101 THEN DATEADD(yy, DATEDIFF(yy, 0, #Date) + 1, 0) ELSE #Date END
SELECT #Date
-- Output : 2022-01-01 00:00:00.000
DECLARE #IP_BATCH_DATE DATETIME= '2020-12-01T00:00:00'
IF #ip_batch_date >= '2020-11-01T00:00:00' AND #ip_batch_date<='2020-12-31T00:00:00'
BEGIN
SELECT datefromparts(YEAR(GETDATE()), 1, 1)
END
ELSE
BEGIN
SELECT #ip_batch_date
END

Using dynamic values in AS portion of an SQL Server query

I'm making a query (and a long, nasty bugger it is) to return dynamically updating values from an SAP system. I've got everything figured out but how to make the column headers what I want. They need to be the name of the previous 11 months and this month (or the 3 letter abbreviation).
Currently, I just have
SELECT ... AS [OCT]
for this month, but in two days it's going to be different, and I'd like to have the query auto-update the column headers each time it is run.
I figured out that I can use the variables I have declared to use in my functions to get the name three letter name of the month:
DECLARE #last_month DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 0, 0)
SELECT CONVERT(char(3), #last_month);
to return the selected month. How do I get this to be usable in the "AS" field?
Here is what I currently have:
DECLARE #last_two_months DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0)
DECLARE #last_month DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 0, 0)
SELECT (a whole mess of things that somehow work) AS [SEPT],
Table.CurrentTotal AS [OCT];
I'd like to replace [OCT] with something that will return OCT as the column header for the next two days and then return NOV for the next month, and similarly changing [SEPT] to something that will return SEP for the next two days, then return OCT for the next month.
Use Dynamic Query
DECLARE #last_month DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 0, 0),
#alias char(3),
#sql nvarchar(max)=''
SELECT #alias= CONVERT(char(3), #last_month);
set #sql = 'SELECT ... as ['+#alias+']..'
--Print #sql
exec sp_executesql #sql
Use the Print Statement to debug the dynamic query

SQL Server datetime data, Out-of-range value error

I am getting the following error from this piece of code
Msg 242, Level 16, State 3, Line 3
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
T-SQL:
datediff(dd, a.ContractStartDate,
cast(case when isdate(
cast(datepart(month, dateadd(mm, 0, a.WarrStartDate)) as varchar(2)) + '/' +
cast('00' + datepart(DAY, a.WarrStartDate) as varchar(2)) + '/' +
cast(datepart(year, dateadd(YEAR, case when a.TRSCustNO = 89555 then 2 else 3 end, a.WarrStartDate)) as varchar(4)))=0
then
cast('00'+datepart(month,dateadd(mm,0,a.WarrStartDate))as varchar(2))+'/'+
cast('00'+datepart(DAY,dateadd(dd,-1,a.WarrStartDate)) as varchar(2)) +'/'+
cast(datepart(year,dateadd(YEAR,case when a.TRSCustNO = 89555 then 2 else 3 end
,a.WarrStartDate))as varchar(4))
else
cast('00'+datepart(month,dateadd(mm,0,a.WarrStartDate))as varchar(2))+'/'+
cast('00'+datepart(DAY,a.WarrStartDate) as varchar(2)) +'/'+
cast(datepart(year,dateadd(YEAR,case when a.TRSCustNO = 89555 then 2 else 3 end
,a.WarrStartDate))as varchar(4)
) end
as datetime)
) as EarnDays
unless I am missing something, this can all be simplified like this. I didn't see a reason to be casting between date and varchar types.
case
when datediff(dd,a.ContractStartDate,
dateadd(year,(case when a.TRSCustNO = 89555 then 2 else 3 end), a.WarrStartDate)
)=0
then
dateadd(year, (case when a.TRSCustNO = 89555 then 2 else 3 end),
dateadd(dd,-1,a.WarrStartDate)
)
else
dateadd(year, (case when a.TRSCustNO = 89555 then 2 else 3 end), a.WarrStartDate)
end as EarnDays
Let me know if I missed the point of it.
If you want to know why you were getting the error, just don't cast it back to a date and look at the output.

How to write a calculation query in SQL?

Using SQL Server 2000
My Query.
SELECT
(Format(IIf(CLng(OutTime) > 180000, CDate('18:00:00'), CDate(Format(OutTime, '00:00:00'))) - IIf(CLng(InTime) < 90000, CDate('09:00:00'), CDate(Format(InTime, '00:00:00'))), 'hh:nn:ss')) As WorkTime,
(Format(IIf(CLng(InTime) < 90000, CDate('09:00:00') - CDate(Format(InTime, '00:00:00')), 0) + IIf(CLng(OutTime) > 180000, CDate(Format(OutTime, '00:00:00')) - CDate('18:00:00'), 0), 'hh:nn:ss')) As OverTime
FROM table
Above query is Access Query, I want to write a same query in sql.
Condition.
I want to Calculate the time after 090000(HH:MM:SS) before 180000 comes in worktime, before
090000 after 180000 comes in overtime.
Intime, Outime data type is varchar in the database
Am new to SQL Server 2000
How to write a SQL query from the above same?
Here is literally translated query to TSQL 2000.
Although, it could be rewritten for better performance:
Select Convert(char(8),
case when DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)>'18:00:00'
Then Cast('18:00:00' as datetime)
Else DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)
End
-
Case when DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) <'09:00:00'
Then Cast('09:00:00' as datetime)
Else DateAdd(Day,-DateDiff(Day, 0, InTime), InTime)
End,
8
) as WorkTime,
Convert(char(8),
Case when DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) <'09:00:00'
Then Cast('09:00:00' as datetime) -
DateAdd(Day,-DateDiff(Day, 0, InTime), InTime)
Else Cast('00:00:00' as datetime)
End
+
case when DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)>'18:00:00'
Then DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime) -
Cast('18:00:00' as datetime)
Else Cast('00:00:00' as datetime)
End,
8
) as OverTime
From Table
Added later:
If InTime and OutTime have time part only (Date part is Jan 1 1900) you can use directly InTime and OutTime. Otherwise you have to extract time part from datetime column, as:
DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)
(this is the fastest way to get time part only)
Instead of:
DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)>'18:00:00'
You can use
Datepart(hh,OutTime)>17
P.S. as your time is stored as string yoiu don't need to get time part only. You can cast them to datetime, or you can write also
cast(left(inTime,2) as int) < 9
As a starter take a look at this website which shows you how to convert Access SQL statements into T-SQL as used by SQL server.
http://weblogs.sqlteam.com/jeffs/archive/2007/03/30/Quick-Access-JET-SQL-to-T-SQL-Cheatsheet.aspx
I don't think there's a very easy and simple way to do this - most notably because of storing time values in VARCHAR - this is really making this tricky.....
Anyway, I used an approach with two functions - one dbo.GetSeconds that converts a string representation of a time value ('103500' -> 10:35:00 hours) to a number of seconds, and then a second one dbo.GetOvertime that detects if there is any overtime.
CREATE FUNCTION dbo.GetSeconds(#input varchar(20))
RETURNS int
AS BEGIN
DECLARE #Hour INT
DECLARE #Minute INT
DECLARE #Second INT
DECLARE #TotalSeconds INT
SET #Hour = CAST(SUBSTRING(#input, 0, LEN(#input)-3) AS INT)
SET #Minute = CAST(LEFT(RIGHT(#input, 4), 2) AS INT)
SET #Second = CAST(RIGHT(#input, 2) AS INT)
SET #TotalSeconds = #Hour * 3600 + #Minute * 60 + #Second
RETURN #TotalSeconds
END
CREATE FUNCTION dbo.GetOvertime(#fromSeconds INT, #toSeconds INT)
RETURNS int
AS BEGIN
DECLARE #Overtime INT
SET #Overtime = 0
IF #fromSeconds < 32400 -- 32400 seconds = 09:00 hours
SET #Overtime = #OverTime + (32400 - #fromSeconds)
IF #toSeconds > 64800 -- 64800 seconds = 18:00 hours
SET #Overtime = #OverTime + (#toSeconds - 64800)
RETURN #Overtime
END
With those two functions in place, I can fairly easily calculate what you're looking for:
SELECT
dbo.GetOvertime(dbo.GetSeconds(InTime), dbo.GetSeconds(OutTime)) 'Overtime',
(dbo.GetSeconds(OutTime) - dbo.GetSeconds(InTime) -
dbo.GetOvertime(dbo.GetSeconds(InTime), dbo.GetSeconds(OutTime))) 'Worktime',
FROM YourTable
It's a bit involved - as I said, if you'd be on SQL Server 2008 and using the TIME data type, things would be a whole lot easier!
Marc
You could use substring and dateadd to convert the '090000' to a real datetime field. Then you can use CASE and DATEDIFF to split work and overtime. The final formatting can be done with CONVERT. Here's an example:
select
case when outtime-intime > '9:00:00' then '09:00:00'
else convert(varchar(30), outtime-intime, 108)
end as WorkTime,
case when outtime-intime <= '9:00:00' then '00:00:00'
else convert(varchar(30), outtime-intime-'9:00:00', 108)
end as OverTime
from (
select
dateadd(hh,cast(substring('090000',1,2) as int),0) +
dateadd(mi,cast(substring('090000',3,2) as int),0) +
dateadd(ss,cast(substring('090000',5,2) as int),0) as InTime,
dateadd(hh,cast(substring('180500',1,2) as int),0) +
dateadd(mi,cast(substring('180500',3,2) as int),0) +
dateadd(ss,cast(substring('180500',5,2) as int),0) as OutTime
) vw
This will print:
09:00:00 00:05:00
Here is code for SQL server 2000. 2005+ could do it without subquery using cross join.
Select DateAdd(mi, (Case When bef<0 Then bef else 0 end + Case When aft<0 Then aft else 0 end), diff) as WorkTome,
DateAdd(mi, (Case When bef>0 Then bef else 0 end + Case When aft>0 Then aft else 0 end), 0) as OverTime
From (
Select outTime-inTime as diff,
DateDiff(mi,t.inTime,'09:00') as bef,
DateDiff(mi,'18:00',t.outTime) as aft
From Table t ) as a
If Your inTime and outTime columns hase date part too, the query is slightly different:
Select DateAdd(mi, (Case When bef<0 Then bef else 0 end + Case When aft<0 Then aft else 0 end), diff) as WorkTome,
DateAdd(mi, (Case When bef>0 Then bef else 0 end + Case When aft>0 Then aft else 0 end), 0) as OverTime
From (
Select outTime-inTime as diff,
DateDiff(mi, DateAdd(Day,-DateDiff(Day, 0, t.inTime), t.inTime),'09:00') as bef,
DateDiff(mi,'18:00',DateAdd(Day,-DateDiff(Day, 0, t.OutTime), t.OutTime)) as aft
From #t t ) as a
I missed type of inTime and outTime.
Here is the version for varchar
Missed that, but you just have to do Cast(inTime as datetime) .
Use the first of previous 2 queries:
Select DateAdd(mi, (Case When bef<0 Then bef else 0 end + Case When aft<0 Then aft else 0 end), diff) as WorkTome,
DateAdd(mi, (Case When bef>0 Then bef else 0 end + Case When aft>0 Then aft else 0 end), 0) as OverTime
From (
Select Cast(t.outTime as datetime)-Cast(t.inTime as datetime) as diff,
DateDiff(mi,Cast(t.outTime as datetime),'09:00') as bef,
DateDiff(mi,'18:00',Cast(t.outTime as datetime)) as aft
From Table t ) as a

Resources