我有一个表,用作事件日志,并存储用户的登录状态:“已登录”、“已退出”或“已拒绝”(有时用户可能会根据外部条件被“拒绝”)。
以下是一些示例数据,以便您可以了解表格的外观:
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/