Create Unique Constraint based on Start Date and End Date - sql-server

I created a unique constraint as below which is working fine. But I want to create a constraint where the productNumber between the two dates should be unique
ALTER TABLE [dbo].[Product] ADD CONSTRAINT U_Product UNIQUE ([ProductNumber],[StartDate],[EndDate])
Right now, it is taking the exact value in columns, but I want it between two dates. How can I do this ?

create function dbo.IsProductUnique (#ProductNumber int, #StartDate date, #EndDate date) returns bit as
begin
if exists (
select *
from Product
where ProductNumber = #ProductNumber
and StartDate < #EndDate
and EndDate > #StartDate) return 0
else
return 1 -- Unique
end
go
alter table Product add constraint CK_Product_Unique check (dbo.IsProductUnique(ProductNumber, StartDate, EndDate) = 1)
go

Related

ADD day month year quarter to a table based on a date column in the same table

I have a table that contains a column date, I want to add to the the same table 4 other columns DAY, MONTH, YEAR, QUARTER based on the value of the column date for all the records in the table. How could it be done please ?
Option 1 - computed columns via datepart
ALTER TABLE dbo.MyTable
ADD TheYear = DATEPART(YEAR, DateColumn);
ALTER TABLE dbo.MyTable
ADD TheQuarter = DATEPART(QUARTER, DateColumn);
ALTER TABLE dbo.MyTable
ADD TheMonth = DATEPART(MONTH, DateColumn);
ALTER TABLE dbo.MyTable
ADD TheDay = DATEPART(DAY, DateColumn);
This adds virtual, read-only columns to your table based on the value of your source column. This is likely the easiest, least approach unless you have not supplied all the relevant points.
Option 2 - Add columns
ALTER TABLE dbo.MyTable
ADD TheYear int;
ALTER TABLE dbo.MyTable
ADD TheQuarter tinyint;
ALTER TABLE dbo.MyTable
ADD TheMonth tinyint;
ALTER TABLE dbo.MyTable
ADD TheDay tinyint;
This is likely going to cause you pain as there is nothing ensuring the values stored in those 4 columns has any bearing on the value in your original Date column but it's an approach.
And since you're tagging SSIS, if you are trying to do this in a data flow - don't. Write the query to do it and bring this data into your pipeline
SELECT T.*
, TheYear = DATEPART(YEAR, T.DateColumn);
, TheQuarter = DATEPART(QUARTER, T.DateColumn);
, TheMonth = DATEPART(MONTH, T.DateColumn);
, TheDay = DATEPART(DAY, T.DateColumn);
FROM dbo.MyTable AS T;

how to get dates between two dates('FromDate and ToDate') and if we have the null value In Todate we should change to getdate() In Todate?

I have a Table With PatientID and FromDate and Todate,I want to generate the dates between these two dates and one more main important scenario is,If we have Null in the Todate We have to Convert that Null Into Getdate() and then get the Dates and "This query should be done without using 'CTE' AND 'While'."
Declare #Temp AS TABLE
(
PatientID INT,
FromDate DATE,
ToDate DATE
)
INSERT INTO #Temp VALUES(3,'2014-05-16','2014-05-16')
INSERT INTO #Temp VALUES(3,'2014-05-16','2014-05-22')
INSERT INTO #Temp VALUES(3,'2014-05-22',NULL)
SELECT * FROM #Temp

How to prevent a single date overlap in sql server 2012

I have a table EmployeeLeaves having columns:
EmployeeID int,
LeaveTypeID int,
LeaveDate datetime2,
IsHalfDay bit,
DateCreated datetime2,
Createdby varchar
I request you to help me out with a trigger that prevent same date for the column "LeaveDate". There are no date ranges like "Todate" and "FromDate" in the table.
Thanks in advance.
Please refer the sample demo,
CREATE TABLE EmployeeLeaves
(
EmployeeID INT,
LeaveTypeID INT,
LeaveDate DATETIME2,
IsHalfDay BIT,
DateCreated DATETIME2,
Createdby VARCHAR(50)
)
insert into EmployeeLeaves
values (1,1,'2016-01-01',0,getdate(),'Admin'),
(2,1,'2016-01-01',0,getdate(),'Admin'),
(3,1,'2016-01-01',0,getdate(),'Admin'),
(4,1,'2016-01-01',0,getdate(),'Admin'),
(5,1,'2016-01-01',0,getdate(),'Admin')
SELECT *
FROM EmployeeLeaves
METHOD-1 using Unique Constraint
--Introduce the unique constraint
ALTER TABLE EmployeeLeaves
ADD CONSTRAINT uq_employeeid_leavedate UNIQUE (EmployeeId, LeaveDate)
--Try to create overlap
insert into EmployeeLeaves
values (1,1,'2016-01-01',0,getdate(),'Admin')
--You will get the following error
--Msg 2627, Level 14, State 1, Line 1
--Violation of UNIQUE KEY constraint 'uq_employeeid_leavedate'. Cannot insert duplicate key in object 'dbo.EmployeeLeaves'. The duplicate key value is (1, 2016-01-01 00:00:00.0000000).
--The statement has been terminated.
--Insert proper date
insert into EmployeeLeaves
values (1,1,'2016-01-02',0,getdate(),'Admin')
--Check the result
SELECT *
FROM EmployeeLeaves
METHOD-2 using Instead of trigger
ALTER TRIGGER Trigger_Test
ON EmployeeLeaves
INSTEAD OF INSERT
AS
BEGIN
IF EXISTS(SELECT TOP 1 1
FROM inserted I
INNER JOIN EmployeeLeaves e
ON i.EmployeeID = e.EmployeeID
AND i.LeaveDate = e.LeaveDate)
BEGIN
RAISERROR (N'Overlapping range.',16,1);
ROLLBACK TRANSACTION;
END
ELSE
BEGIN
INSERT INTO EmployeeLeaves
SELECT *
FROM inserted
END;
END
You can add a unique constraint on leave date field or you can check and raise exception using
if exist( select top 1 EmployeeID from table where EmployeeID = #emploeeid and
datediff(day,leavedate,#applydate)=0 and leavetypeid= #leavetypeid)
begin raise_error('leave already exist',1,1) end

How to delete the rows older then 1 month?

I have One Table Login in this table i want to delete rows older then 1 months.
CREATE TABLE [dbo].[Login] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[CurrentTime] VARCHAR(MAX) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
This is my table design.Here I am storing date and time as varchar type.
With using or without using the CurrenTime field how to delete one month older rows
Use DateAdd. Try
DELETE FROM Table1 WHERE Column < DATEADD(MONTH, -1, GETDATE())
or
DELETE FROM Table1 WHERE Column < DATEADD(dd,-30,GETDATE())
To convert your varchar column to date format use
SELECT CONVERT(Datetime, '2015-10-29 15:01:00', 120)
DELETE FROM [dbo].[Login]
WHERE [CurrentTime] < DATEADD(month, -1, GETDATE())
will work.
Try :
DELETE FROM Table1 WHERE DATEDIFF(mm, CAST(COL2 AS DateTime), GETDATE()) > 1

Date range overlapping check constraint

I've a simple table in sql server 2005 with 3 columns: DateStart, DateEnd and Value. I tried to set a "table check constraint" to avoid inserting overlapping records. For instance if in such table there is a record with DateStart = 2012-01-01 (first January) and DateEnd 2012-01-15 (15th January) than Check constraint must avoid inserting a record with DateStart=2012-01-10 (no care DateEnd), a record with DateEnd=2012-01-10 (no care DateStart) or a record with DateStart 2011-12-10 and DateEnd 2012-02-01.
I defined a UDF in such way:
CREATE FUNCTION [dbo].[ufn_checkOverlappingDateRange]
(
#DateStart AS DATETIME
,#DateEnd AS DATETIME
)
RETURNS BIT
AS
BEGIN
DECLARE #retval BIT
/* date range at least one day */
IF (DATEDIFF(day,#DateStart,#DateEnd) < 1)
BEGIN
SET #retval=0
END
ELSE
BEGIN
IF EXISTS
(
SELECT
*
FROM [dbo].[myTable]
WHERE
((DateStart <= #DateStart) AND (DateEnd > #DateStart))
OR
((#DateStart <= DateStart) AND (#DateEnd > DateStart))
)
BEGIN
SET #retval=0
END
ELSE
BEGIN
SET #retval=1
END
END
RETURN #retval
END
Then thought check could be this:
ALTER TABLE [dbo].[myTable] WITH CHECK ADD CONSTRAINT [CK_OverlappingDateRange] CHECK ([dbo].[ufn_checkOverlappingDateRange]([DateStart],[DateEnd])<>(0))
But even with [myTable] empty EXISTS Operator returns true when i insert first record. Where i'm wrog ? Is it possible to set a constraint like this ?
BTW I consider DateStart includes in range and DateEnd excludes from range.
The CHECK is being executed after the row has been inserted, so the range overlaps with itself.
You'll need to amend your WHERE to include something like: #MyTableId <> MyTableId.
BTW, your WHERE expression can be simplified.
Ranges don't overlap if:
end of the one range is before the start of the other
or start of the one range is after the end of the other.
Which could be written in SQL like:
WHERE #DateEnd < DateStart OR DateEnd < #DateStart
Negate that to get the ranges that do overlap...
WHERE NOT (#DateEnd < DateStart OR DateEnd < #DateStart)
...which according to De Morgan's laws is the same as...
WHERE NOT (#DateEnd < DateStart) AND NOT (DateEnd < #DateStart)
...which is the same as:
WHERE #DateEnd >= DateStart AND DateEnd >= #DateStart
So your final WHERE should be:
WHERE
#MyTableId <> MyTableId
AND #DateEnd >= DateStart
AND DateEnd >= #DateStart
[SQL Fiddle]
NOTE: to allow ranges to "touch", use <= in the starting expression, which would produce > in the final expression.
CREATE TABLE [dbo].[TEMPLATE] (
[ID] BIGINT IDENTITY (1, 1) NOT NULL,
[DATE_START] DATETIME NOT NULL,
[DATE_END] DATETIME NOT NULL,
[TEMPLATE_NAME] VARCHAR (50) NOT NULL,
CONSTRAINT [PK_TEMPLATE] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_current_start_and_end_dates_in_sequence] CHECK ([DATE_START]<=[DATE_END])
);
go
CREATE FUNCTION [dbo].[Check_Period]
(
#start DateTime,
#end DateTime
)
RETURNS INT
AS
BEGIN
declare #result INT = 0 ;
set #result = (Select count(*) from [dbo].[TEMPLATE] F where F.DATE_START <= #start and F.DATE_END >= #start );
set #result = #result +
(
Select count(*) from [dbo].[TEMPLATE] F where F.DATE_START <= #end and F.DATE_END >= #end
)
RETURN #result
END
go
ALTER TABLE [dbo].[TEMPLATE]
ADD CONSTRAINT [FK_overlap_period_t]
CHECK ([dbo].[Check_Period]([DATE_START],[DATE_END])=(2));
go
Insert Into [dbo].[TEMPLATE] (DATE_START, DATE_END, TEMPLATE_NAME) values ('2020-01-01','2020-12-31', 'Test1');
-- (1 row(s) affected)
Insert Into [dbo].[TEMPLATE] (DATE_START, DATE_END, TEMPLATE_NAME) values ('2021-01-01','2022-12-31', 'Test2');
-- (1 row(s) affected)
Insert Into [dbo].[TEMPLATE] (DATE_START, DATE_END, TEMPLATE_NAME) values ('2020-01-01','2020-12-31', 'Test3');
-- The INSERT statement conflicted with the CHECK constraint "FK_overlap_period_t".
I'd just like to add onto the Answer of Branko Dimitrijevic the case where the DateEnd is null since I currently have such a scenario.
This can occur when you're keeping punch in logs and the user is still logged in.
WHERE
#MyTableId <> MyTableId
AND #DateEnd >= DateStart
AND DateEnd >= #DateStart
OR #DateEnd >= DateStart
AND DateEnd is null
OR #DateStart >= DateStart
AND DateEnd is null
I don't know how well this query is performance wise, I'm sure there are ways to optimize it.

Resources