【发布时间】:2016-05-12 08:46:35
【问题描述】:
这不是 Check constraint on date 的重复,但我可能错过了另一个类似的问题。
在 MS SQL 上,您可以创建以下约束:
ALTER TABLE [X] WITH CHECK ADD CONSTRAINT [CCCHK03_TBX] CHECK
(
[TBX_YEAR] = DATEPART( year, GetDate() )
)
您可以很好地插入记录,但我无法完全测试它的含义,当服务器日期跳到 2017 年时会发生什么?我的印象是它将允许插入 2017 年,但理论上它会使 2016 年的所有记录无效。
这个表是一个只插入的表,所以记录永远不会是可更新的,所以这不是问题。我主要关心的是这是否可能导致服务器稳定性问题?
我似乎找不到与此相关的任何内容,但 MS 必须有理由允许这样的限制。
通常我会建议创建一个插入触发器并对其进行检查,但这让我很好奇。
编辑:目标数据答案的扩展测试:
IF ( OBJECT_ID( 'tempdb..#CheckTest' ) IS NOT NULL )
DROP TABLE #CheckTest
GO
CREATE TABLE #CheckTest ( MN INT )
ALTER TABLE #CheckTest WITH CHECK ADD CONSTRAINT CHK_MN CHECK ( MN = DATEPART( SECOND, GETDATE() ) )
ALTER TABLE #CheckTest CHECK CONSTRAINT CHK_MN
GO
-- Control Test. This will fail with:
--Msg 547, Level 16, State 0, Line 12
--The INSERT statement conflicted with the CHECK constraint "CHK_MN". The conflict occurred in database "tempdb", table "dbo.#CheckTest", column 'MN'.
--The statement has been terminated.
INSERT INTO #CheckTest ( MN )
VALUES ( DATEPART( SECOND, DATEADD( SECOND, 5, GETDATE() ) ) )
-- Add 5 different seconds.
DECLARE @Counter int = 0;
WHILE @Counter < 5
BEGIN
INSERT INTO #CheckTest ( MN )
VALUES ( DATEPART( SECOND, GETDATE() ) )
SET @Counter += 1;
-- Delay for a second.
WAITFOR DELAY '00:00:01';
END
GO
-- Add a different second.
-- Disabling and Enabling a check will work just fine so long as the check already exists.
ALTER TABLE #CheckTest NOCHECK CONSTRAINT CHK_MN;
INSERT INTO #CheckTest ( MN )
VALUES ( DATEPART( SECOND, DATEADD( SECOND, 5, GETDATE() ) ) )
ALTER TABLE #CheckTest CHECK CONSTRAINT CHK_MN;
-- Control Test. This will fail with:
--Msg 547, Level 16, State 0, Line 12
--The INSERT statement conflicted with the CHECK constraint "CHK_MN". The conflict occurred in database "tempdb", table "dbo.#CheckTest", column 'MN'.
--The statement has been terminated.
INSERT INTO #CheckTest ( MN )
VALUES ( DATEPART( SECOND, DATEADD( SECOND, 5, GETDATE() ) ) )
GO
-- Check table contents.
SELECT * FROM #CheckTest;
GO
-- Dropping and recreating the check constraint will result in an error:
--Msg 547, Level 16, State 0, Line 37
--The ALTER TABLE statement conflicted with the CHECK constraint "CHK_MN". The conflict occurred in database "tempdb", table "dbo.#CheckTest", column 'MN'.
ALTER TABLE #CheckTest DROP CONSTRAINT CHK_MN;
ALTER TABLE #CheckTest WITH CHECK ADD CONSTRAINT CHK_MN CHECK ( MN = DATEPART( SECOND, GETDATE() ) )
GO
DROP TABLE #CheckTest
GO
编辑 2:摘要
根据测试和反馈,虽然这确实是一个有趣的练习,而且绝对看起来 100% 完全有效,但我绝对会从“未来证明”的角度建议不要这样做,因为支票永远不会能够被改变。我个人认为基于触发器的约束是最易于维护的。
【问题讨论】:
-
当约束失败时不会有任何系统不稳定。约束用于执行我们的预定义规则
-
我现在在文档中找不到它,但很可能
CHECK约束仅在插入或更新行时才被评估/验证(仅适用于插入或更新的行)。因此,您可以在今天插入 2016 年的行,并在明年插入 2017 年的行,但如果在 2017 年尝试更新在 2016 年创建的行,则更新将失败。如果您不触摸该旧行,它将按原样保留在表格中。 -
@VladimirBaranov 太好了,感谢您的支持,我也是这么看的。如果那是答案,我可以标记它。
标签: tsql sql-server-2012