2010-02-22 56 views
1

我有一个表,用作事件日志并存储用户登录状态'In','Out'或'Rejected'(有时候我的用户是'根据外部标准被拒绝)。SQL Server检查Contraint并检查登录/注销状态

下面是一些示例数据,因此你可以得到的表是什么样子的想法:

Table MyTable 
PersonID - State  - DateTime 
// data sample 
156  - 'Out'  - 02-14-2010 13:04:15 
156  - 'In'  - 02-21-2010 09:01:13 
16  - 'In'  - 02-21-2010 09:05:01 
58  - 'Rejected' - 02-21-2010 11:04:58 
156  - 'Out'  - 02-21-2010 11:10:02 

下面是一些pseduo检查约束代码概述我想做什么:

CHECK(
     CASE 
      WHEN (
       [State] = 'In' AND 
       (Select TOP 1 State FROM MyTable WHERE [email protected]_ToUpdate)!='In' ORDER BY DateTime DESC) 
      ) 
      THEN 'T' 
      WHEN (
       [State] = 'Out' AND 
       (Select TOP 1 State FROM MyTable WHERE [email protected]_ToUpdate)!='Out' ORDER BY DateTime DESC) 
      ) 
      THEN 'T' 
      WHEN (
       [State] = 'Rejected' AND 
       (Select TOP 1 State FROM MyTable WHERE [email protected]_ToUpdate)!='In' ORDER BY DateTime DESC) 
      ) 
      THEN 'T' 
      ELSE 'F' 
     END = 'T' 
) 

基本上是:

  • 一个人可以,如果他们最后的状态签名IN“在”
  • 一个人可以注册OUT,如果他们最后的状态是“出”
  • 一个人可以是拒绝的,如果他们最后的状态是“在”

我不知道检查约束是否是最好的方法来做到这一点,或者如果我的数据库设计将允许这个级别的约束;请让我知道,如果我走了我的心(和好心建议用于存储数据和/或确保数据的完整性更合适的方法)

注:我使用的是SQL-Server 2008的

回答

2

下面是一个示例触发器。它假设你只打算每次插入1行(这可能是这种情况),并且我还没有对索引等产生困扰。

我添加了一个子句,当状态是'Out '所以它忽略'被拒绝'的状态 - 这是为了防止多个Out。它非常基本,但你明白了。

if object_id('dbo.MyTable') is not null  
    drop table dbo.MyTable; 

create table dbo.MyTable (
    PersonID int not null, 
    [State] varchar(20) not null, 
    [DateTime] datetime not null default(getdate()) 
    ); 

if object_id('dbo.ins_MyTable_status_validation') is not null drop trigger dbo.ins_MyTable_status_validation; 
go 
create trigger dbo.ins_MyTable_status_validation 
    on dbo.MyTable 
    instead of insert 
as 
begin 
    set nocount on; 

    -- assuming you're only inserting 1 row at a time (which makes sense for an event log) 
    if (select count(*) from inserted) > 1 begin 
     print 'Multiple rows inserted - raise some kind of error and die' 
     return 
    end 

    declare @personid_toupdate int, 
      @state varchar(20); 

    select @personid_toupdate = personid, 
      @state = [state] 
    from inserted; 

    if case 
     when (
      @state = 'In' and 
      isnull((select top 1 [State] from dbo.MyTable where personid = @personid_toupdate order by [datetime] desc), 'Blah') != 'In' 
      ) 
      then 'T' 
     when (
      @state = 'Out' and 
      isnull((select top 1 [State] from dbo.MyTable where personid = @personid_toupdate and [State] != 'Rejected' order by [datetime] desc), 'Blah') != 'Out' 
      ) 
      then 'T' 
     when (
      @state = 'Rejected' and 
      isnull((select top 1 [State] from dbo.MyTable where personid = @personid_toupdate order by [datetime] desc), 'Blah') != 'In' 
      ) 
      then 'T' 
      else 'F' 
     end = 'T' 
    begin 
     -- data is valid, perform the insert 
     insert dbo.MyTable (PersonID, [State]) 
     select PersonID, [State] 
     from inserted; 
    end 
    else 
    begin 
     -- data is invalid, return an error (something a little more informative than this perhaps) 
     raiserror('bad data...', 16, 1) 
    end 
end 
go 

-- test various combinations to verify constraints 
insert dbo.MyTable (PersonID, [State]) values (1, 'In') 
insert dbo.MyTable (PersonID, [State]) values (1, 'Out') 
insert dbo.MyTable (PersonID, [State]) values (1, 'Rejected') 

select * from dbo.MyTable 
1

你必须使用触发器。

您可以在检查约束中使用udf来隐藏表访问。但是不要。

+0

+1,不要使用udf check约束! – 2010-02-22 18:24:42