SQL Server 检查约束并检查登录/注销状态

标签 sql sql-server constraints check-constraints

我有一个表,用作事件日志,并存储用户的登录状态:“已登录”、“已退出”或“已拒绝”(有时用户可能会根据外部条件被“拒绝”)。

以下是一些示例数据,以便您可以了解表格的外观:

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

这是一些伪检查约束代码,概述了我想要做的事情:

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

基本上:

  • 如果某人的最后状态不是“In”,则可以IN签名
  • 如果某人的最后状态不是“退出”,则可以退出
  • 如果某人的最后状态不是“在”,则可能会被拒绝

我不知道检查约束是否是执行此操作的最佳方法,或者我的数据库设计是否允许这种级别的约束;如果我疯了,请告诉我(并请建议一种更合适的方法来存储数据和/或确保数据完整性)

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

最佳答案

这是一个示例触发器。它假设您一次只会插入 1 行(这里可能就是这种情况),并且我没有考虑索引等。

我为状态为“Out”时添加了一个子句,因此它会忽略“Rejected”状态 - 这是为了防止出现多个 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

关于SQL Server 检查约束并检查登录/注销状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2312995/

相关文章:

SQL查询选择具有非聚合值和聚合函数表达式的列

sql - 在postgresql中安排选择查询?

sql - 如何通过按位运算符操作执行 SQL JOIN?

mysql - 使用复合主键作为外键

swift - 以编程方式在 ScrollView 中获取 UIImageView 时遇到问题

mysql - 使用 CONSTRAINT 与 FOREIGN KEY 对齐

mysql - SQL唯一varchar区分大小写问题

SQL 按查询中指定的顺序排序

php - Codeigniter 请求 sql 但我的代码返回错误

python - 巧妙缩进 SQL 语句的算法(Python 实现会很好)