你能限制数据库表中的行数吗?

4
我们有一个数据库(SQL Server 2005),我们希望将其纳入源代码控制。作为其中的一部分,我们将创建一个版本表来存储数据库的当前版本号。是否有一种方法可以限制该表仅保留一行?或者在表中存储版本号是个坏主意吗?
最终采用了以下方案:
CREATE TABLE [dbo].[DatabaseVersion]
    (
        [MajorVersionNumber] [int]  NOT NULL,
        [MinorVersionNumber] [int]  NOT NULL,
        [RevisionNumber] [int]  NOT NULL
    )
GO

Insert DataBaseVersion (MajorVersionNumber,  MinorVersionNumber,  RevisionNumber) values (0, 0, 0)
GO

CREATE TRIGGER DataBaseVersion_Prevent_Delete
ON DataBaseVersion INSTEAD OF DELETE
AS
BEGIN
    RAISERROR ('DatabaseVersion must always have one Row. (source = INSTEAD OF DELETE)', 16, 1) 
END
GO

CREATE TRIGGER DataBaseVersion_Prevent_Insert
ON DataBaseVersion INSTEAD OF INSERT
AS
BEGIN
    RAISERROR ('DatabaseVersion must always have one Row. (source = INSTEAD OF INSERT)', 16, 1) 
END
GO

与其引发错误,插入操作可以悄无声息地变为更新操作。 - Sean Reilly
7个回答

7

使用触发器。


触发器也是我的第一想法。在插入时,检查条目是否存在,如果存在则直接失败,或者最好使用存储过程执行更新操作。 - Adam
我最终采用了这种方法。也许你可以在你的回答中加入更多的细节呢?那会很有帮助的。 - Ej.

6

将表格概括为“设置”,并将其变成键/值对

CREATE TABLE Settings (Key nvarchar(max), Value nvarchar(max))

然后在 Key 上创建一个唯一索引。

CREATE UNIQUE INDEX SettingsIDX ON Settings (Key)

这将创建一个包含唯一键值对的表,其中之一可以是“版本”。

INSERT INTO Settings (Key, Value) VALUES ('Version','1');

我自己做过这个,但这不是我的首选:1)nvarchar(max)似乎对于键来说有点大。2)该值没有类型。 - Joel Coehoorn
设置表通常非常小,因此大小并不是问题。我使用文本字段来表示版本号,因为它允许像“1.0.0.4”这样的内容...而且我从未需要将版本号相乘... - WOPR

2
您可以使用Joe Celko的默认+主键+检查技术:
create table database_version (

  lock char(1) primary key default 'x' check (lock='x'),
  major_version_number int NOT NULL,
  minor_version_number int NOT NULL,
  revision_number int NOT NULL
);

点击进入SQL Fiddle练习


1

根据您对其他回复的评论,似乎:

  1. 您不希望用户仅修改值。
  2. 您只想返回一个值。
  3. 该值是静态和脚本化的。

因此,我建议您编写一个返回静态值的函数。由于您必须在更新版本号时编写脚本更新,因此当您更新数据库时,您将简单地删除并重新创建函数。

这样做的好处是可以从视图或过程中使用,并且由于函数的返回值是只读的,因此它不能被修改(除非修改函数)。

编辑:您也不必担心保持表限制为一行的复杂解决方案。

这只是一个建议。


1
是的,我同意,这也是一个不错的解决方案。虽然我认为无论是将表格限制为一行还是使用函数都同样好。也许从语义上讲,我更喜欢表格,因为版本号感觉像是数据而不是功能(但这只是一个小小的想法)。 - Ej.

1

为数据库保留版本号是完全有意义的。然而,我更喜欢有一个版本表,可以包含多行,其中包括版本号、更新时间和执行升级的用户字段。

这样,您就知道已运行哪些升级脚本,并且可以轻松查看它们是否按顺序运行。

当您想要读取当前版本号时,只需读取最近的记录即可。

如果您只存储一条记录,则无法知道是否漏掉了某个脚本。如果您想变得真正聪明,可以在升级脚本中放置检查,以确保它们不会运行,除非数据库的先前版本正确。


1

完全不需要。您只需向该表添加另一列(日期、ID或其他),然后按照该列降序排序查询,并将结果限制为1行:

SELECT v.version FROM version v ORDER by v.date DESC LIMIT 1;

这样,您甚至可以获得每个版本达到的历史记录。

编辑:

由于SQL Server不支持LIMIT语句,因此上述SQL查询在SQL Server上无法工作。人们必须规避这种缺陷,可能如"All Things SQL Server"博客条目中所述。


我之前不知道这件事。谢谢。 - Ole
SELECT TOP 1 v.version FROM version v ORDER by v.date DESC - recursive

0
通过在数据库初始化脚本中创建一个允许的原始行,并在该脚本中删除所有登录的插入权限(只允许更新),来实现此目的。
您可能还想禁止删除操作...

1
我不喜欢这个解决方案,因为它依赖于有效的权限管理才能正确地执行逻辑。表格应该强制执行。 - WOPR
我的推理是,如果表格强制执行它,则对于所有用户(即使是SA等),这都是普遍的。如果管理员添加了一个用户并且搞砸了权限,它仍然可以工作。如果有些用户被允许添加重复项而另一些不允许(在我看来),您的方法可能更好。 - WOPR
如果您将此数据库部署到另一台服务器上,则必须记得正确设置用户帐户(否则可能会失败)。像Kieran建议的“设置”表更加灵活,可以打开更有效的资源使用方式。一个只有1行的表格,不如将其XML化。 - Adam
我猜如果你不熟悉这项技术,那么它对你来说可能会很奇怪... 我个人经常使用权限,并且发现它们在某些情况下很直观和相当适用 - 就像这种情况。而且我不是将它们应用于用户,而是应用于应用程序登录... 而这些是脚本化的。 - Charles Bretana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接