是否可以将Unique约束与Check约束相关联?

时间:2012-03-22 10:58:23

标签: sql-server sql-server-2008 tsql unique-constraint check-constraints

我有一个表access,其架构如下:

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,
)

允许的访问类型仅为OUTER_PARTY and INNER_PARTY

我想要实现的是INNER_PARTY条目每次登录(用户)每天只应该一次,但OUTER_PARTY可以记录任意次。所以我想知道是否有可能直接这样做,或者是否有成语来制造这种限制。

我已经检查了这个问题:Combining the UNIQUE and CHECK constraints,但无法将其应用于我的情况,因为它的目标是另一回事。

2 个答案:

答案 0 :(得分:6)

可以将过滤的唯一索引添加到表中。此索引可以基于计算列,该列从access_time列中删除时间组件。

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

似乎工作:

--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

答案 1 :(得分:2)

遗憾的是,您无法在检查约束上添加“if”。我建议使用触发器:

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 

您必须格式化@access_time才能仅考虑日期部分