How can I validate a decimal interval using SQL Server? - 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

Related

functions from MSSQL to Oracle SQL

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

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

Convert Epoch to DateTime SQL Server (Exceeds Year 2038)

How to convert Epoch to DateTime SQL Server if epoch exceeds the year 2038?
Answer in Convert Epoch to DateTime SQL Server will not work.
Example:
SELECT DATEADD(ss, 2713795200000 / 1000, '19700101')
Thu, 30 Dec 2055 16:00:00 GMT
DATEADD function assumes an INT as an increment to your date, to bypass the limitation of INT you can either reduce the precision of your epoch, or do a slightly complex code to retain the precision of your epoch.
This reduces the precision to minutes:
SELECT DATEADD(MINUTE,#YourEpoch/60/1000, '1/1/1970')
This one splits your epoch to days and milliseconds and then combines them in a datetime
CREATE FUNCTION [dbo].[fn_EpochToDatetime] (#Epoch BIGINT)
RETURNS DATETIME
AS
BEGIN
DECLARE #Days AS INT, #MilliSeconds AS INT
SET #Days = #Epoch / (1000*60*60*24)
SET #MilliSeconds = #Epoch % (1000*60*60*24)
RETURN (SELECT DATEADD(MILLISECOND, #MilliSeconds, DATEADD(DAY, #Days, '1/1/1970')))
END;
However, I'm not quite sure why the 2nd solution is not as precise as I expect it to be.
Building on the response above, the solution provided works but does not protect from trying to convert to a date that is out of bounds for SQL server.
create function dbo.unixTimestampConversion (
#unixTime bigInt
)
returns dateTime2(7)
as
begin
declare
#output dateTime2(7)
, #days int
, #ms int
, #x int = (1000 * 60 * 60 * 24)
;
set #days = #unixTime / #x
;
set #ms = #unixTime % #x
;
if (#unixTime < 32503593600000 and #unixTime > -2208988800000)
begin
set #output = dateAdd (millisecond, #ms, dateAdd (day, #days, '1/1/1970'))
;
end
;
else if (#unixTime <= -2208988800000)
begin
set #output = '1/1/1900'
;
end
;
else if (#unixTime >= 32503593600000)
begin
set #output = '12/31/2999'
;
end
;
return #output
;
end
;
You can assign the epoch time to your datetime directly (I tried this on SQL Server 15.0). Although it considers the number as the number of days since 1900-1-1 00:00:00 so you have to add 2208988800 (the number of seconds in 70 years) and then divide by 86400(number of seconds in a day).
DECLARE #time DATETIME = (2208988800.0 + [your epoch time in seconds])/86400;
However, it seems to be 0.007s or 0.003s behind the given epoch. Also, I'm not sure if this is faster than the DATEADD() function.
create a function to convert epoch to datetime and use them in your query like
below
create FUNCTION [dbo].[from_unixtime] (#Datetime BIGINT)
RETURNS DATETIME
AS
BEGIN
DECLARE #LocalTimeOffset BIGINT
,#AdjustedLocalDatetime BIGINT;
SET #LocalTimeOffset = DATEDIFF(second,GETDATE(),GETUTCDATE())
SET #AdjustedLocalDatetime = #Datetime - #LocalTimeOffset
RETURN (SELECT DATEADD(second,#AdjustedLocalDatetime, CAST('1970-01-01 00:00:00' AS datetime)))
END;
and then use this function in your query

reset auto increment number each year

I have a table with job_no to be auto increment with the last two digit of the year.
Example: in year 2014 the job_no will be like this: 140001, 140002, 140003 and it will keep increment until next year which is 2015, it will reset the count like this: 150001, 150002...
it happened that I knew how to merge date with the numbers, but am still unable to figure out how to let it reset yearly.. I will be so thankful for your help and will be glad for a clear view of explanation and examples...
DECLARE #y INT;
SET #y = YEAR(GETDATE()) % 100; -- or YEAR(#DateOfJob) if you use a variable for that
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
DECLARE #i INT;
SELECT #i = MAX(job_no) FROM dbo.TableName WHERE job_no / 1000 = #y;
SET #i = #y * 1000 + 1 + COALESCE(#i % 1000, 0);
-- if job_no is an IDENTITY column, for some reason:
-- SET IDENTITY_INSERT dbo.TableName ON;
INSERT dbo.TableName(job_no, ...) VALUES(#i, ...);
-- if job_no is an IDENTITY column, for some reason:
-- SET IDENTITY_INSERT dbo.TableName OFF;
COMMIT TRANSACTION;
Set up a SQL agent job to run at midnight on December 31 and run the following snippet of code:
DBCC CHECKIDENT('table_name', RESEED, (YEAR(GETDATE()) % 100) * 10000)
Note that there are the following problems with this approach:
If you put more than 10000 records in the table in a given year then your numbers will run over then end and the year will be wrong
You have two different types of information in this column: the identity value and the year. It is usually better to divide information like that out (i.e., just use an identity column and then also store the date)
You only have the year, not the month or day which might be useful in the future if it isn't right now
You just need to set identity inserts and insert a row with the new starting value that you want to use, this will then start inserting from that value.
It kinda goes against database normal forms though as you have two data items in one field.

Compare SQL server datetime column to year month?

SELECT * FROM TABLE
WHERE YEAR(MDTFlgtStart)=YEAR(GETDATE()) AND MONTH(MDTFlgtStart)=MONTH(GETDATE())
Above code it compares with present year and month with the column year and month.
But do we have any chance we can give year=2012 month =3
or year =2011 month=5
You could declare variables:
DECLARE #YEAR AS INT
DECLARE #MONTH AS INT
SET #YEAR = 2012
SET #MONTH = 3
SELECT *
FROM TABLE
WHERE YEAR(MDTFlgtStart)=#YEAR AND MONTH(MDTFlgtStart)=#MONTH
You can wrap the above in a procedure for re-usability....
You can just use parameters for those values. As a bonus, avoiding functions against the column will help assist a seek if an index exists on the column (of course SELECT * means it will likely end up as a full scan anyway, or a range scan and a bunch of lookups)...
-- these would be input parameters for your stored procedure
DECLARE #y INT = 2011, #m INT = 5;
-- now have a date variable:
DECLARE #dt DATE = DATEADD(MONTH, #m-1, DATEADD(YEAR, #y-1900, 0));
SELECT ... FROM dbo.tablename
WHERE MDTFlgtStart >= #dt
AND MDTFlgtStart < DATEADD(MONTH, 1, #dt);
Also you should stop inviting whoever named these columns to lunch, because I have to assume they're not very nice.

Resources