functions from MSSQL to Oracle SQL - sql-server

Is there a way to use the following function from MSSQL in Oracle SQL Developer
create function fnDays2NextEvent(#birthdate datetime, #today datetime)
returns integer
as
begin
declare #birthday datetime
set #birthday = #birthdate
while #birthday < #today set #birthday = dateadd(yy, 1, #birthday)
return datediff(dd,#today,#birthday)
end;

You need to create the function in Oracle similar to this one.
Like the following:
CREATE OR REPLACE FUNCTION FNDAYS2NEXTEVENT (
BIRTHDATE IN DATE,
TODAY IN DATE
) RETURN INT AS
BEGIN
RETURN BIRTHDATE
+ CEIL(MONTHS_BETWEEN(TODAY, BIRTHDATE) / 12)
* INTERVAL '1' YEAR - TODAY + 1;
END;
/
Then, You will be able to use it.
SQL> SELECT FNDAYS2NEXTEVENT(DATE'1991-07-20',SYSDATE) FROM DUAL;
FNDAYS2NEXTEVENT(DATE'1991-07-20',SYSDATE)
------------------------------------------
161
SQL> SELECT SYSDATE + 161 FROM DUAL;
SYSDATE+1
---------
20-JUL-20
SQL>
I don't know if this is what you require, Do comment in case of any discrepancy in the answer and expectation.
Cheers!!

If you are looking for the oracle equivalent, then try this:
create or replace function fnDays2NextEvent(birthdate date, today date)
return number
is
begin
return trunc(birthdate)- trunc(today) ;
end fnDays2NextEvent;
test
select fnDays2NextEvent(to_date('02/14/2020','MM/DD/YYYY'),sysdate) from dual

the function could look like:
CREATE OR REPLACE function fnDays2NextEvent(birthdate DATE, today DATE)
returns NUMBER
AS
v_bd DATE;
begin
v_bd := birthdate;
while v_bd < today
LOOP
v_bd = ADD_MONTHS(v_bd,12);
END LOOP;
RETURN today - v_bd;
end;
this code is not optimized and is 1 to 1 migration from your code

Related

T-SQL : CREATE FUNCTION must be the only statement in batch [duplicate]

I'm getting this error from the function:
CREATE FUNCTION getLavel(#id int ,#lavel char)
RETURNS date
BEGIN
DECLARE #date date
select #date = (select authorization_date from Authorized WHERE diver_number = #id and #lavel =level_name)
return #date
END
GO
What can be the reason?
Ty very much.
The function needs to be either the only function in the query window OR the only statement in the batch. If there are more statements in the query window, you can make it the only one "in the batch" by surrounding it with GO's.
e.g.
GO
CREATE FUNCTION getLavel(#id int ,#lavel char)
RETURNS date
BEGIN
DECLARE #date date
select #date = (select authorization_date from Authorized WHERE diver_number = #id and #lavel =level_name)
return #date
END
GO
Turn this into an inline table valued function. This will perform better than the scalar function. Also, you should NOT use the default sizes for character datatypes. Do you know what the default length for a char is? Did you know that it can vary based on usage?
CREATE FUNCTION getLavel
(
#id int
, #lavel char --You need to define the length instead of the default length
)
RETURNS table
return
select authorization_date
from Authorized
WHERE diver_number = #id
and #lavel = level_name
GO
You need to add RETURN before the END statement
That should fix your issue, that's what fixed mine. :D
Make sure that this statement is the only the only sql in your query window before you execute it.
Or you can highlight the function declaration and execute
What solved it for me, was that I was trying to create the function inside of a transaction context - that doesn't make sense from a SQL Server point of view. Transactions are for data, not functions.
Take the CREATE FUNCTION statement out of the transaction, then wrap it in GO's
CREATE FUNCTION CalculateAge(#DOB DATE)
RETURNS INT
AS
BEGIN
DECLARE #Age INT
SET #DOB='08/12/1990'
SET #Age =DATEDIFF(YEAR,#DOB,GETDATE()) -
CASE
WHEN (MONTH (#DOB)> MONTH (GETDATE ())) OR
(MONTH (#DOB)= MONTH (GETDATE ()) AND DAY (#DOB) >DAY (GETDATE ()))
THEN 1
ELSE 0
END
SELECT #Age
END
The Error is given to you in only query Page But if you execute the query then it will successfully execute.
CREATE FUNCTION getLavel(#id int ,#lavel char)
RETURNS date
BEGIN
DECLARE #date date
select #date = (select authorization_date from Authorized WHERE diver_number = #id and #lavel = level_name)
return #date
END
GO

Is there an easy way to determine the next business day from a date with weekends and holidays included in the calculation?

I have a future table which shows holidays and weekends along with calendar dates and I want to add a next business day field to that based on Holidays and Weekends.
For example: January 2nd 2020 is a holiday and so is January 1st. January 1st 2020 is a wednesday, so the next business day should be January 3rd. (skips the 2nd, friday is a business day).
Is there an easy function or loop which can do this simply? I only need to do it once so i'm not worried too much about not utilizing a set operation.
I had created what i assumed was the worlds worst case statement, but I realized that solution was just clunky and not supportable.
I don't have the reputation to comment but from what I have gathered... no, there is not a function provided by SQL Server but you can write a simple function like the one done in this post Declare date, then add next business day
Good luck!
Thanks , I just used a derived subquery to allow incorrect dates to populate when there was a holiday to consider, then rolled those up to another layer and added an extra day.
Not the most elegant, but worked for my scenario.
select
a.date
,a.day
,a.firstOfMonth
,a.MonthName
,a.week
,a.dayofWeek
,a.hldyInd
,a.weekendInd
,case when a.Nbdtemp IN ('2020-01-01','2020-01-02','2020-01-20','2020-05-25','2020-07-03','2020-11-26','2020-12-25') then dateadd(day,1,nbdtemp) else Nbdtemp end as NxtBusinessDay
into #final
from
(
select t.*,
case when t.dayofweek not in ('Friday','Saturday') and t.HldyInd = 'N' then DATEADD(day,1,date)
when t.dayofweek = 'Friday' and t.hldyind = 'N' then dateadd(day,3,date)
when t.dayofweek = 'Saturday' and t.hldyind = 'N' then dateadd(day,2,date)
when t.hldyind = 'Y' then dateadd(day,1,date) end as Nbdtemp
from #updtdim t
) as a
The easy way is create Holidays table, and enter each holiday every year. After that, you can easy to give a day and find the next working day.
Here is my function to get how many working days between start and end day. You can easy to modify and get next business day.
CREATE TABLE [dbo].[Holidays](
[Date] [date] NULL,
[Description] [varchar](100) NULL
) ON [PRIMARY]
GO
CREATE FUNCTION [dbo].[GetWorkingDays]
(
#StartDate date,
#EndDate date
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE #ResultVar int = 0;
DECLARE #dt date = #StartDate;
WHILE #EndDate >= #dt BEGIN
IF DATEPART(WEEKDAY,#dt) < 6 BEGIN
IF NOT EXISTS(SELECT Date FROM Holidays WHERE Date=#dt) BEGIN
SET #ResultVar = #ResultVar + 1;
END
END
SET #dt = DATEADD(DAY,1,#dt);
END
RETURN #ResultVar;
END
Try something like this:
create table dbo.HolidayList(Holiday date)
insert into HolidayList(Holiday)values
('2019-07-01T00:00:00.000'),('2019-07-09T00:00:00.000'),('2019-08-01T00:00:00.000'),
('2019-08-02T00:00:00.000'),('2019-08-05T00:00:00.000'),('2019-09-02T00:00:00.000'),
('2019-10-14T00:00:00.000'),('2019-11-11T00:00:00.000'),('2019-12-25T00:00:00.000'),
('2019-12-26T00:00:00.000'),('2020-01-01T00:00:00.000'),('2020-02-10T00:00:00.000'),
('2020-02-17T00:00:00.000'),('2020-03-17T00:00:00.000'),('2020-04-10T00:00:00.000'),
('2020-04-13T00:00:00.000'),('2020-04-23T00:00:00.000'),('2020-05-18T00:00:00.000'),
('2020-05-25T00:00:00.000'),('2020-06-24T00:00:00.000'),('2020-07-01T00:00:00.000'),
('2020-07-09T00:00:00.000'),('2020-07-30T00:00:00.000'),('2020-07-31T00:00:00.000')
go
create function dbo.IsWeekday(#Date date) returns bit
begin
return case when DATEDIFF(day,'0001-01-01T00:00:00.000',#Date)
% 7 < 5 then 1 else 0 end
end
go
create function dbo.IsHoliday(#Date date)returns bit
begin
return case when #Date in(select Holiday from HolidayList) then 1 else 0 end
end
go
create function dbo.IsWorkDay(#Date date)returns bit
begin
return case when dbo.IsWeekday(#Date)=1 and dbo.IsHoliday(#Date)=0 then 1 else 0 end
end
go
create function dbo.WorkdayFollowing(#Date date)returns date
begin
declare #D date = DATEADD(day,1,#date)
while dbo.isworkday(#D)=0
begin
set #D = DATEADD(day,1,#D)
end
return #D
end
go
declare #d date = '2019-06-01T00:00:00.000'
while #d < '2019-09-01T00:00:00.000'
begin
set #d=DATEADD(day,1,#d)
select #d, dbo.workdayfollowing(#d)
end

How to filter result only by month and year?

I use SQL SERVER 2012.
I have stored prcedure:
ALTER PROCEDURE [dbo].[SP_TEST_TLP]
#DateFrom date,
#DateTo date
AS
BEGIN
SET NOCOUNT ON;
select *
from Clients
WHERE DateReview between (#DateFrom) and (#DateTo)
END
As you can see I pass two parameters to stored procedure above and those parameters I use to filter the result in where clause.
My problem is that I need to filter result only by month and year.
For example, if I have passed those parameters:
#DateFrom date = '2016-05-15' ,
#DateTo date = '2016-10-09'
According to stored procedure I will get result between dates above.But I need to get rows from start of the month 05 and end of the month 10 i,e the result should be equivalent to those params:
#DateFrom date = '2016-05-01'
#DateTo date = '2016-10-31'
How can I get the desired result?
You can also use EOMONTH function
select *
from Clients
WHERE DateReview between DATEADD(DAY,1,EOMONTH(#DateFrom,-1) ) and EOMONTH(#DateTO)
Try this :
Here
DATEADD(dd,-(DAY(#DateFrom)-1),#DateFrom) this will give months start date i.e '2016-05-01'
And
DATEADD(dd,-(DAY(DATEADD(mm,1,#DateTo))),DATEADD(mm,1,#DateTo)) will give month end date i.e '2016-10-31'
ALTER PROCEDURE [dbo].[SP_TEST_TLP]
#DateFrom date,
#DateTo date
AS
BEGIN
SET NOCOUNT ON;
SET #DateFrom = DATEADD(dd,-(DAY(#DateFrom)-1),#DateFrom)
SET #DateTo = DATEADD(dd,-(DAY(DATEADD(mm,1,#DateTo))),DATEADD(mm,1,#DateTo))
Updated ---^
select *
from Clients
WHERE DateReview between (#DateFrom) and (#DateTo)
END
Here is one way:
select *
from Clients
where DateReview >= dateadd(day, 1 - day(#DateFrom), #DateFrom) AND
DateReview < dateadd(month, 1, dateadd(day, 1 - day(#DateTo), #DateTo))
This method allows the query to make use of an index on DateReview. You could also do this as:
where year(DateReview) * 100 + month(DateReview)
between year(#DateFrom) * 100 + month(#DateFrom) and
year(#DateTo) * 100 + month(#DateTo)
You can use EOMonth() function
ALTER PROCEDURE [dbo].[SP_TEST_TLP]
#DateFrom date,
#DateTo date
AS
BEGIN
SET NOCOUNT ON;
select *
from Clients
WHERE DateReview between Dateadd(d,1,EOMonth(#DateFrom,-1)) and EOMonnth(#DateTo)
END

Creating and executing the function in SQL Server

Im trying to complete this function that will take an input date and return a date that is a Sunday 3 weeks ago.
For example: If my input date is 5/25/2016, then the result should be 5/1/2016
I have put together most of the function, just stumped as to what to do next.
IF OBJECT_ID (N'dbo.ufnSundayThreeWeeksBack', N'FN') IS NOT NULL
DROP FUNCTION ufnSundayThreeWeeksBack;
GO
CREATE FUNCTION dbo.ufnSundayThreeWeeksBack(#SOMEDATE datetime)
RETURNS date
AS
BEGIN
IF #SOMEDATE IS NULL
RETURN NULL;
DECLARE #result date;
SELECT #result = DATEADD(WEEK, -7, DATEADD(DAY, 1 - DATEPART(WEEKDAY, #SOMEDATE), #SOMEDATE))
RETURN #result;
END;
GO
Try this:
IF OBJECT_ID(N'dbo.ufnSundayThreeWeeksBack', N'FN') IS NOT NULL
DROP FUNCTION ufnSundayThreeWeeksBack;
GO
CREATE FUNCTION dbo.ufnSundayThreeWeeksBack ( #SOMEDATE DATETIME )
RETURNS DATE
AS
BEGIN
DECLARE #DateMinus3Weeks DATE = DATEADD(WEEK, -3, #SOMEDATE);
RETURN DATEADD(DAY, -(DATEPART(WEEKDAY, #DateMinus3Weeks)-1), #DateMinus3Weeks);
END;
GO
Basically subtracting 3 weeks from the given date and then subtracting the weekdaynumber to get to the sunday.

How can I validate a decimal interval using SQL Server?

I'm trying to code a store procedure in order to check if a new interval is currently stored in table.
Example:
I have these values on my table:
startHour = 7.20
endHour = 8.10
I want to find a way to cancel any insert with startHour or endHour that causes conflicts with te previous stored values, like startHour = 7.21, 7.32, 8.09 and so.
I mean, the interval 7.20 - 8.10 is not available.
And yeah, i'm using decimals.
Thanks!
I think you can do something like:
declare #startHour decimal
declare #endHour decimal
IF
0 =
(SELECT
COUNT(*)
FROM HourIntervals
WHERE (startHour <= #startHour AND #startHour < endHour) OR (startHour <= #endHour AND #endHour < endHour))
BEGIN
-- Interval ok, insert your record here
select 1
END
ELSE
BEGIN
-- Interval overlaps, don't insert
select 0
END

Resources