Add table level Contraint that checks for date overlap in Sql Server 2005 - sql-server-2005

I have a table in Sql Server where i have Columns : UserId, RoleId, FromDate and Todate.
I want to write a contraint that check same RoleId and UserId are not present for the same date.
Thanks In Advance....

If you don't have time portion or the time portion is the same in all records you can use UNIQUE constraint:
ALTER TABLE yourSchema.yourTable
ADD CONSTRAINT uniqueConstraint1 UNIQUE (RoleId, UserId, FromDate);
This way combination of date, RoleId and UserId can occur only once in table, other attempts to insert the same combination will fail.
Note that this will work if your date field has values for time portion that are the same in every record (for instance 0) or the data type of the field is DATE (which eliminates the time portion).
If your date field has time portion that varies among records, try one of this approaches:
A) Add computed column of definition
ALTER TABLE yourSchema.yourTable
ADD constraintCheckDate AS CAST(FromDate AS DATE)
and add UNIQUE constraint of definition
ALTER TABLE yourSchema.yourTable
ADD CONSTRAINT uniqueConstraint1 UNIQUE (RoleId, UserId, constraintCheckDate)
B) Use trigger to validate data before inserting it, data will be entered only if it doesn't already exist:
CREATE TRIGGER trig1 ON yourSchema.yourTable
INSTEAD OF INSERT
AS
BEGIN
IF NOT EXISTS
(
SELECT *
FROM yourSchema.yourTable t
JOIN inserted i ON
CAST(t.FromDate AS DATE) = CAST(i.FromDate AS DATE)
AND t.RoleId = i.RoleId
AND t.UserId = i.UserId
)
INSERT yourTable(RoleId, UserId, FromDate, ToDate)
SELECT RoleId, UserId, FromDate, ToDate
FROM inserted
ELSE
RAISERROR('Error', 16, 0)
END
GO

Related

sql unique constraint with time window

I have a table where records have a (begin, end) time window of existence (for things like employement duration, birth and death, rent duration, ...)
begin IS NULL or end IS NULL if there is no bound.
CREATE TABLE mytable(
id int primary key,
value int, --UNIQUE at any point in time
begin datetime NULL,
end datetime NULL
);
I want column value to be unique at any point in time.
INSERT INTO mytable VALUES(1, 1, '2021-07-23', '2021-07-24'),(2, 1, '2021-07-25', NULL);
Is OK
Whereas
INSERT INTO mytable VALUES(1, 1, '2021-07-23', '2021-07-30'),(2, 1, '2021-07-25', NULL);
Is not OK, because both records have value=1 and overlapping time windows.
Is there a way to enforce such a constraint in SQL ?
You can't do this on the table, no, as there's nothing to make UNIQUE on.
What you could do, however, is use a VIEW to enforce it.
Firstly, let's create your table. I assume the columns datetime, should actually be begin and end; I recommend against these names as they are reserved keywords. As such I am calling them DateBegin and DateEnd. I am also assuming that they are date only (no time portion) values and so define them as a date not a datetime:
CREATE TABLE dbo.mytable(ID int primary key,
Value int,
[BeginDate] date NULL,
[EndEnd] date NULL);
And we'll INSERT your first 2 rows, as they are "ok":
INSERT INTO dbo.mytable (ID, Value, BeginDate, EndDate)
VALUES(1, 1, '20210723', '20210724'),
(2, 1, '20210725', NULL);
Now we need to make a VIEW, but we need one row per date. As such you'll want to create a Calendar Table. I'm not going to cover how to create one here, but there are literally 100's of articles, such as there on SQL Server Central: Bones of SQL - The Calendar Table, Calendar Tables in T-SQL.
Once you have your Calendar table, you can create the VIEW below, which JOINs the data in your table to the calendar table. We're going to make it so that the VIEW just returns the columns value and the date. WE're also going to schemabind it; this means we'll be able to add an UNIQUE INDEX to it:
CREATE VIEW dbo.MyView
WITH SCHEMABINDING
AS
SELECT MT.[Value],
CT.CalendarDate
FROM dbo.MyTable MT
JOIN dbo.CalendarTable CT ON MT.BeginDate <= CT.CalendarDate --I assume, despite your schema, MT.BeginDate can't be NULL
AND (MT.EndDate >= CT.CalendarDate OR MT.EndDate IS NULL);
Now we have a VIEW that has a row for each date, and for each value. This means we can now create our UNIQUE INDEX:
CREATE UNIQUE CLUSTERED INDEX MyIndex ON dbo.MyView ([Value], CalendarDate);
Now if we try to INSERT a row that is on the same date and value, we'll get an error:
INSERT INTO dbo.MyTable (ID, Value, BeginDate, EndDate)
VALUES(3, 1, '20210720', '20210723');
Cannot insert duplicate key row in object 'dbo.MyView' with unique index 'MyIndex'. The duplicate key value is (1, 2021-07-23).

Prevent a user logging in twice in a database table

I have a table with these columns:
user ID, login time, logout time
When a user logs in if that user already has a row with a login time but no logout time then he relogs in using that row, otherwise it creates a new. The problem is sometimes the stored procedure runs twice and I get two entries.
Is there a constraint I can use for this situation to prevent it from being possible?
Try the following
CREATE TABLE UserLog(
ID int NOT NULL IDENTITY PRIMARY KEY,
UserID int NOT NULL,
LoginTime datetime NOT NULL DEFAULT SYSDATETIME(),
LogountTime datetime
)
-- unique index with where clause
CREATE UNIQUE INDEX UK_UserLog_UserID ON UserLog(UserID) WHERE LogountTime IS NULL
GO
INSERT UserLog(UserID)
VALUES(1)
-- Cannot insert duplicate key row in object 'dbo.UserLog' with unique index 'UK_UserLog_UserID'. The duplicate key value is (1).
INSERT UserLog(UserID)
VALUES(1)
UPDATE UserLog
SET
LogountTime=SYSDATETIME()
WHERE UserID=1
AND LogountTime IS NULL
INSERT UserLog(UserID)
VALUES(1)
SELECT *
FROM UserLog

sql current date constraint

I need to add a constraint to one table in my database. The table name is Experience. And there is a column named ToDate. Every time the select statement executes like following.
select ToDate from Experience
It should return current date.
So every time select statement executes, the ToDate column get updated with current date.
I know I can do this with some type of sql trigger but is there a way to do it by sql constraint.
like
alter table add constraint...
Any help will be appreciated.
Thanks
You can use a computed column. That's specified like colname as <expression>:
create table t1(id int, dt as getdate());
insert t1 values (1);
select * from t1;
To add contraint ...
create table tbl (id int identity, dt datetime, colval varchar(10))
ALTER TABLE dbo.tbl
ADD CONSTRAINT col_dt_def
DEFAULT GETDATE() FOR dt;
Example of inserting to the table ..
insert into dbo.tbl(colval)
select 'somevalue'
select * from dbo.tbl
The result will be ..
id dt colval
1 2014-08-19 13:31:57.577 somevalue
You cannot use a constraint, because a constraint is basically a rule on what can go in the table, how the table can relate to others, etc. It has no bearing on the data in the table once it goes into the table. Now if I am understanding you correctly, you want to update the ToDate column whenever you select that column. Now you can't use a trigger either as mentioned here and here. They suggest a stored procedure where you would use an update followed by an insert. This is probably my preferred SQL method to go with if you have to use it repeated, which you seem to have to do. Though Andomar's answer is probably better.
Try this link code make help full
http://www.sqlatoms.com/queries/how-to-use-the-getdate-function-in-sql-server-3/
CREATE TABLE ProductOrders
(
OrderId int NOT NULL PRIMARY KEY IDENTITY,
ProductName nvarchar(50) NOT NULL,
OrderDate datetime NOT NULL DEFAULT GETDATE()
)

Inserting one table's primary key into another table

I have two tables in SQL Server, Appointment and AppointmentDetails.
Appointment table has two columns AppId and CusId.
AppointmentDetail table has AppId, ApDay, Intime, OutTime, EmpId.
Appointment table has AppId as its primary key, and it is set to auto increment.
AppointmentDetails table has primary key on (AppId, ApDay).
My problem how get and insert the primary key of the Appointment table to AppointmentDetails table when I am inserting data into Appointment table???
Here's one method of doing it (with corrected spellings for table names though I accept these are sometimes beyond your control):
DECLARE #insertedId INT;
BEGIN TRANSACTION
INSERT INTO Appointment(CusId) VALUES(#cusId);
SET #insertedId = SCOPE_IDENTITY();
COMMIT
BEGIN TRANSACTION
INSERT INTO
AppointmentDetails
SELECT
AppId = #insertedId
,ApDay = #apDay
,Intime = #inTime
,OutTime = #outTime
,EmpId = #empId
FROM
Appointment
COMMIT
Alternatively you could use a trigger, but they're just evil!
I think they asking how can they return the new key that was generated to then insert it into the details table.
Check this post out if using JDBC but the idea is the same for all languages: How to get the insert ID in JDBC?

Calculated columns in mysql on INSERT statements

Let's say that I want to have a table that logs the date and the number of columns in some other table (or really any sort of math / string concat etc).
CREATE TABLE `log` (
`id` INTEGER NOT NULL AUTO_INCREMENT ,
`date` DATETIME NOT NULL ,
`count` INTEGER NOT NULL ,
PRIMARY KEY (`id`)
);
Is it possible to have the count column calculated for me whenever I do an insert?
e.g. do something like:
INSERT INTO log (date='foo');
and have count calculated by mysql.
Obviously I could do it myself by doing a query to get the count and inserting it, but this would be better.
Triggers are the best tool for annotating data when a table is changed by insert, update or delete.
To automatically set the date column of a new row in the log with the current date, you'd create a trigger that looked something like this:
create trigger log_date before insert on log
for each row begin
set new.date = current_date()
end;
You definitly have to declare what to insert. This should be possible by using the INSERT ... SELECT statement.
INSERT INTO log (date, count)
SELECT DATE() as date, count(id) as count
from foo;
Which should insert a new row into the log table, containing todays date and the number of rows in the foo table. (Assuming the foo table has an id column.. Use the primary key or another indexed column)
Why don't you use information_schema.TABLES?