Transacting MS Access query (using IIF() and DATESERIAL()) into T-SQL - tsql

I'm trying to convert some MS Access queries to T-SQL to use in SSIS (basically converting Access db to SQL server 2008) and I'm having trouble converting an IIF() statement. I tried several approaches and it always resulted in an error.
The query creates a column with dates that are "original Date + 2 years if the condition is met and original Date + 1 if the condition is not met". The first part of the IIF() eliminates the case of the original year being a leap year and so the possibility of generating a non-existing date.
The original IIF() statement is:
IIf((Day(Date)=29 And Month(Date)=2),
IIf(Desc Like "*" & "123" & "*",
DateSerial(Year(Date)+2,Month(Date),Day(Date)-1),
DateSerial(Year(Date)+1,Month(Date),Day(Date)-1)),
IIf(Desc Like "*" & "123" & "*",
DateSerial(Year(Date)+2,Month(Date),Day(Date)),
DateSerial(Year(Date)+1,Month(Date),Day(Date)))) AS Term
So the problem is not only an IIF() statement but also DATESERIAL function. I found the solution for the DATESERIAL() function using CAST() (SQL server 2008 does not have the DATEFROMPARTS() function...).
I tried using CASE() like this:
CASE
WHEN DAY(Date)=29 AND Month(Date)=2 THEN
CASE
WHEN Desc LIKE "%123%" THEN
CAST(CAST(YEAR(Date)+2 AS VARCHAR(4)) + RIGHT('0' + CAST(MONTH(Date) AS VARCHAR(2)), 2) + RIGHT('0' + CAST(DAY(Date)-1 AS VARCHAR(2)), 2) AS DATETIME )
ELSE CAST(CAST(YEAR(Date)+1 AS VARCHAR(4)) + RIGHT('0' + CAST(MONTH(Date) AS VARCHAR(2)), 2) + RIGHT('0' + CAST(DAY(Date)-1 AS VARCHAR(2)), 2) AS DATETIME ) END
ELSE CASE
WHEN Desc LIKE "%123%" THEN
THEN CAST(CAST(YEAR(Date)+2 AS VARCHAR(4)) + RIGHT('0' + CAST(MONTH(Date) AS VARCHAR(2)), 2) + RIGHT('0' + CAST(DAY(Date) AS VARCHAR(2)), 2) AS DATETIME )
ELSE CAST(CAST(YEAR(Date)+1 AS VARCHAR(4)) + RIGHT('0' + CAST(MONTH(Date) AS VARCHAR(2)), 2) + RIGHT('0' + CAST(DAY(Date) AS VARCHAR(2)), 2) AS DATETIME )END END AS Term
I also tried using COAELSCE() but with no better outcome.
I really don't know if I have made some kind of syntax error or where the problem could be.
Thank you in advance for any help.
edit: I'll add error message I'm getting: Incorrect syntax near '...'. The '...' changes as I try different approaches, sometimes its ELSE, THEN etc.

SQL Server's DATEADD may help to simplify things here...
CASE WHEN (<your condition>)
THEN DATEADD(YEAR, 1, [OriginalDate])
ELSE DATEADD(YEAR, 2, [OriginalDate])
END
Should also cope with leap years too.

DateSerial is such a useful function to have around, just create your own.
I got my version from here:
CREATE FUNCTION dbo.DateSerial
(
#year int,
#month int,
#day int
)
RETURNS datetime
AS
BEGIN
DECLARE #date datetime
-- convert date by adding together like yyyymmdd
SET #date = cast(#year * 10000 + 101 AS char(8));
-- Add to date the proper months subtracting 1, since we used 1 as start instead of zero.
SET #date = dateadd(mm , #month - 1 , #date)
-- Add to date the proper days subtracting 1, since we used 1 as start instead of zero.
SET #date = dateadd(dd , #day - 1 , #date);
RETURN #date ;
END;
GO
Here is another way: Date serial in SQL?
Then use the function just as you did in Access.
Edit: just noticed that your outer IIF is to handle leap years. This is not needed when using dateadd().

Related

Add to DATE hour - TSQL

I have a column type time(7).
What i want is to add in time column to date.
i manage to get the only date using GETDATE() function but i fail to add the time part next to date.
Query:
SELECT [Compay]
,[Time]
,CAST(GETDATE() AS DATE) AS Today
,CAST(CAST(GETDATE() AS DATE) AS NVARCHAR) AS Today_AS_Nvarchar
,CAST([Time] AS NVARCHAR) AS Time_AS_Nvarchar
,CAST(CAST(GETDATE() AS DATE) AS NVARCHAR) + ' ' + CAST([Time] AS NVARCHAR) AS Today_Time_AS_Nvarchar
,CONVERT(datetime,CAST(CAST(GETDATE() AS DATE) AS NVARCHAR) + ' ' + CAST([Time] AS NVARCHAR),103)
FROM [Testing_Env].[dbo].[Com_CD_Test]
Error:
Conversion failed when converting date and/or time from character string.
The error arise on CONVERT(datetime,CAST(CAST(GETDATE() AS DATE) AS NVARCHAR) + ' ' + CAST([Time] AS NVARCHAR),103)
is there any easier/orthodox way to achieve it?
You can't add the new date and time data types together like you can the old data types; personally I think this is also better as it stop people treating dates and times like a numerical value.
Assuming you have a date column and a time column you have a few of options. The first is to CAST/CONVERT both to a datetime and then "add" them together. Because the "old" data types work more like numerical values this works, however, you will lose accuracy of your time value if it has a precision of 3 or higher (as datetime is only accurate to 1/300 seconds):
DECLARE #TimeValue time(7) = '17:52:12.1234567',
#DateValue date = '20211016';
SELECT CONVERT(datetime, #DateValue) + CONVERT(datetime, #TimeValue);
If loosing accuracy isn't an option, then you could to use conversion on the date value and use DATEDIFF and DATEADD. For a time(7) you'll want to be using nanoseconds (as microseconds isn't accurate enough). Unfortunately this poses another problem; DATEADD can't handle bigint values (still) and there is no DATEADD_BIG (like there is DATEDIFF_BIG), so this becomes overly complex. You need to first get the difference in milliseconds, and then add the remainder in nanoseconds to still be accurate to 1/1000000 of a second:
DECLARE #TimeValue time(7) = '17:52:12.1234567',
#DateValue date = '20211016';
SELECT DATEADD(NANOSECOND,DATEDIFF_BIG(NANOSECOND,'00:00:00', #TimeValue) % 1000000,DATEADD(MILLISECOND, DATEDIFF_BIG(MILLISECOND,'00:00:00', #TimeValue), CONVERT(datetime2(7),#DateValue)));
Finally, yes, you can convert to values to strings, and then to a datetime2 value; this is probably the easiest methiod. You just need to ensure you use style codes:
DECLARE #TimeValue time(7) = '17:52:12.1234567',
#DateValue date = '20211016';
SELECT CONVERT(datetime2(7),CONVERT(varchar(10), #DateValue, 23) + 'T' + CONVERT(varchar(17), #TimeValue, 114),126);

Casting DATETIME on concatenated date and time

I'm trying to concatenate a column's date to a fixed time of the day and then CAST the whole thing as DATETIME.
The fixed time is 5:30am.
The date column I'm using needs to be adjusted as it shows the end date/time of when something ran; I want to use the start date/time.
The start date/time time is not available as its own column, but I have another column that has the duration the process took in seconds, so I can use DATEADD to roll the end date/time back to the start date/time.
Here's the full statement:
CAST(CONVERT(VARCHAR(10), DATEADD(ss,-ConfTask.[LastExecutedDuration], ConfTask.[LastExecutedDate]), 103) + ' ' + '05:30' as DATETIME)
Here's the error message I'm receiving:
The conversion of a varchar data type to a datetime data type resulted
in an out-of-range value.
I've tried testing these statements to investigate the issue, but they all run OK on their own:
CAST(CONVERT(VARCHAR(10), GETDATE(), 103) + ' ' + '05:30' as DATETIME)
CAST('2017-03-02' + ' ' + '05:30' as DATETIME)
DATEADD(ss,-ConfTask.[LastExecutedDuration], ConfTask.[LastExecutedDate])
I'm a bit stuck on how to get round this issue. Any help would be much appreciated.
Clearly, you must have some unexpected values in the column.
I would suggest finding them using a query such as this:
SELECT LastExecutedDuration, LastExecutedDate
FROM ConfTask
WHERE TRY_CONVERT(datetime,
CONVERT(VARCHAR(10),
DATEADD(second,
-ConfTask.[LastExecutedDuration],
ConfTask.[LastExecutedDate]
)
103
) + ' ' + '05:30')
)
You can also simplify the logic, by just using date functions:
select dateadd(minute,
5 * 60 + 30,
convert(datetime,
convert(date,
dateadd(second,
- ConfTask.LastExecutedDuration
ConfTask.LastExecutedDate
)
)
)
)
This worked:
CONVERT(DATETIME, CONVERT(CHAR(8), DATEADD(ss,-ConfTask.[LastExecutedDuration], ConfTask.[LastExecutedDate]), 112)) + ' ' + CONVERT(CHAR(8), '05:30:00', 108)

How to find out Number of Workdays between two dates in HANA?

How to find out Number of Workdays(Monday to Friday) between two dates in SAP HANA ? We do not have to consider holidays.
We cant use WORKDAYS_BETWEEN() as we do not have TFACS table.
Here is how you can so ist in sql:
Calculate the number of whole weeks, multiply by 5
Add the remaining days: subtract weekday start date from weekday end date, correct for weekends (least...), Correct for carry-over (+5)
The second part can be simplified a little so that you don't have to write the subtraction twice.
Here an example with start date '2015-12-04' and end date '2015-12-19):
SELECT ROUND( DAYS_BETWEEN (TO_DATE ('2015-12-04', 'YYYY-MM-DD'), TO_DATE('2015-12-19', 'YYYY-MM-DD')) / 7, 0, ROUND_DOWN) * 5
+ ( case
when WEEKDAY (TO_DATE('2015-12-19', 'YYYY-MM-DD') ) - WEEKDAY (TO_DATE('2015-12-04', 'YYYY-MM-DD')) >= 0
then least( WEEKDAY (TO_DATE('2015-12-19', 'YYYY-MM-DD')), 5) - least( WEEKDAY (TO_DATE('2015-12-04', 'YYYY-MM-DD')), 5)
else
least( WEEKDAY (TO_DATE('2015-12-19', 'YYYY-MM-DD')), 5) - least( WEEKDAY (TO_DATE('2015-12-04', 'YYYY-MM-DD')), 5) + 5
end )
"Workdays" FROM DUMMY;
--> 11
I preferred to create a user defined function here to use in HANA SQLScript codes as follows
Create Function CalculateWorkDays (startdate date, enddate date)
returns cnt integer
LANGUAGE SQLSCRIPT AS
begin
declare i int;
cnt := 0;
i := 0;
while :i <= days_between(:startdate, :enddate)
do
if WEEKDAY( ADD_DAYS(:startdate,:i) ) < 5
then
cnt := :cnt + 1;
end if;
i := :i + 1;
end while;
end;
Please note that the above code block seems to contain an unnecessary loop.
On the other hand, if you have additional tables like department holidays, or personal holidays, etc. It might be useful to check these tables in the WHILE loop. Please refer to following SQL tutorial Calculate the Count of Working Days Between Two Dates where I created a similar SQL function checking custom work calendars or holiday calendars.
Here is how you call the function as sample
select CalculateWorkDays('20170101', '20170131') as i from dummy;
I hope it helps,

Distinct Time from Table SQL

I have table Proccesses that consist of Date Time Field.
Proccesses ( Id as int , RunDate as DateTime)
I need to run Distinct by RunDate as Time Without seconds
For Example
ID RunDate
1 2011-12-13 12:36:26.483
2 2011-12-12 12:37:22.421
3 2011-12-11 12:36:44.421
I need to receive in output
Output
12:01
12:03
In order to retrieve it I using following SQL and it's working
SELECT DISTINCT DATENAME(hour, RunDateTime) + ':' +
DATENAME(mi, RunDateTime) AS d
from Proccesses
The problem that if minutes is less than 10 for example 8
I receiving single digit "8" , and I want to receive two digit 08
For example I receive 12:8 , and I need to receive 12:08
try
SELECT DISTINCT
RIGHT ('00' + CAST(DATENAME(hour, RunDateTime) AS VARCHAR(2)), 2) + ':' +
RIGHT ('00' + CAST(DATENAME(mi, RunDateTime) AS VARCHAR(2)), 2)
from Proccesses
Alternatively you can use CONVERT as suggested by #JoeStefanelli and handle the string result accordingly.
CONVERT style 108 will return hh:mm:ss. Using CHAR(5) for the data type will return just the hh:mm portion.
SELECT DISTINCT CONVERT(CHAR(5), RunDateTime, 108) AS d
FROM Processes
SELECT RIGHT(CONVERT(VARCHAR,RunDateTime),7)
You could strip of the AM/PM if you want to.

How do I format a date in a SQL Where clause?

I have a .NET 2010 app that bangs against a SQL db. On the app side, a user can search on Begin date and End Date. Bot of these are just Month + Year. I then format them so they are complete dates. So when they go to the stored proc they'll look like this...
Begin Date: 1/1/2011
End Date: 5/31/2011
But the date in the db is broken up into 3 int fields, Month,Day & Year, ...of which Day may or may not be filled in (0 if not). It would be ok for this to always default to one when running this query. So if the values in the db were Month=3, Day=0 Year=2011 I would like the sql statement to render as
Where FORMATTEDDATEHERE between '1/1/2011' and '5/31/2011'
I just can't figure out how to format sql fields in a where clause.
Did you try something like
WHERE CONVERT(DATETIME,
CONVERT(VARCHAR(4), [c_year]) + '/'
+ CONVERT(VARCHAR(2), [c_month]) + '/'
+ CONVERT(VARCHAR(2), [c_day]))
BETWEEN '2011/1/1' AND '2011/5/31'
Hope it helps
you could build the date using datadd functions within the WHERE clause EG.
SELECT ...
WHERE DATEADD(Day, field_days-1, DATEADD(Month, field_months-1, DATEADD(Year, field_years-1900, 0))) BETWEEN '1/1/2011' AND '5/31/2011'
Just replace field_days, field_months, field_years with the int fields on the table for days, months and year. This will return all records within the date range.
Is this what you require?
WHERE CAST(Year AS varchar) + RIGHT(100 + Month, 2) +
RIGHT(100 + COALESCE(NULLIF(Day, 0), 1), 2) BETWEEN ...