Reputation: 5002
I have a table access
whose schema is as below:
create table access (
access_id int primary key identity,
access_name varchar(50) not null,
access_time datetime2 not null default (getdate()),
access_type varchar(20) check (access_type in ('OUTER_PARTY','INNER_PARTY')),
access_message varchar(100) not null,
)
Access types allowed are only OUTER_PARTY and INNER_PARTY
.
What I am trying to achieve is that the INNER_PARTY
entry should be only once per day per login (user), but the OUTER_PARTY
can be recorded any number of times. So I was wondering if its possible to do it directly or if there is an idiom to create this kind of restriction.
I have checked this question: Combining the UNIQUE and CHECK constraints, but was not able to apply it to my situation as it was aiming for a different thing.
Upvotes: 1
Views: 334
Reputation: 239724
A filtered unique index can be added to the table. This index can be based on a computed column which removes the time component from the access_time
column.
create table access (
access_id int primary key identity,
access_name varchar(50) not null,
access_time datetime2 not null default (SYSDATETIME()),
access_type varchar(20) check (access_type in ('OUTER_PARTY','INNER_PARTY')),
access_message varchar(100) not null,
access_date as CAST(access_time as date)
)
go
create unique index IX_access_singleinnerperday on access (access_date,access_name) where access_type='INNER_PARTY'
go
Seems to work:
--these inserts are fine
insert into access (access_name,access_type,access_message)
select 'abc','inner_party','hello' union all
select 'def','outer_party','world'
go
--as are these
insert into access (access_name,access_type,access_message)
select 'abc','outer_party','hello' union all
select 'def','outer_party','world'
go
--but this one fails
insert into access (access_name,access_type,access_message)
select 'abc','inner_party','hello' union all
select 'def','inner_party','world'
go
Upvotes: 6
Reputation: 36146
unfortunately you cant add a "if" on a check constraint. I advise using a trigger:
create trigger myTrigger
on access
instead of insert
as
begin
declare @access_name varchar(50)
declare @access_type varchar(20)
declare @access_time datetime2
select @access_name = access_name, @access_type= access_type, @access_time=access_time from inserted
if exists (select 1 from access where access_name=@access_name and access_type=@access_type and access_time=@access_time) begin
--raise excetion
end else begin
--insert
end
end
you will have to format the @access_time to consider only the date part
Upvotes: 2