如何将表中的最大行数限制为仅1


22

我的SQL Server数据库中有一个配置表,该表只能有一行。为了帮助将来的开发人员理解这一点,我想防止添加多行数据。我选择为此使用触发器,如下所示...

ALTER TRIGGER OnlyOneConfigRow
    ON [dbo].[Configuration]
    INSTEAD OF INSERT
AS
BEGIN
    DECLARE @HasZeroRows BIT;
    SELECT  @HasZeroRows = CASE
        WHEN COUNT (Id) = 0 THEN 1
        ELSE 0
    END
    FROM
        [dbo].[Configuration];

    IF EXISTS(SELECT [Id] FROM inserted) AND @HasZeroRows = 0
    BEGIN
        RAISERROR ('You should not add more than one row into the config table. ', 16, 1)    
    END
END

这不会引发错误,但不允许第一行进入。

还有一种更有效/更自我解释的方式来将可插入表中的行数限制为1吗?我是否缺少任何内置的SQL Server功能?


2
就像解释为什么您的原始方法不起作用的原因一样:您使用了代替代替触发器,这意味着您的代码将代替插入语句运行。因此,为了使插入发生,您必须明确地将其包含在触发器中。
Scott M

Answers:


52

这两个约束可以做到:

CREATE TABLE dbo.Configuration
( ConfigurationID TINYINT NOT NULL DEFAULT 1,
  -- the rest of the columns
  CONSTRAINT Configuration_PK 
    PRIMARY KEY (ConfigurationID),
  CONSTRAINT Configuration_OnlyOneRow 
    CHECK (ConfigurationID = 1)
) ;

您既需要PRIMARY KEY(或UNIQUE约束),以便没有两行具有相同的ID值,也需要CHECK约束,因此所有行都具有相同的ID值(任意选择1)。
结合起来,这两个几乎相反的约束将行数限制为零或一。


在一个虚构的DBMS(当前的SQL实现不允许这种构造)上,它允许由0列组成的主键,这也是一种解决方案:

CREATE TABLE dbo.Configuration
( -- no ConfigurationID needed at all
  -- the rest of the columns
  CONSTRAINT Configuration_PK 
    PRIMARY KEY ()                -- 0 columns!
) ;

24

您可以将ID定义为计算为常数的计算列,然后将该列声明为唯一:

CREATE TABLE dbo.Configuration
(
  ID AS CAST(1 AS tinyint),  -- or: AS bit
  ...  -- other columns
  CONSTRAINT UQ_Configuration_ID UNIQUE (ID)
);

9

您也可以使用触发器。

create trigger LimitTable
on YourTableToLimit
after insert
as
    declare @tableCount int
    select @tableCount = Count(*)
    from YourTableToLimit

    if @tableCount > 50
    begin
        rollback
    end
go

1

似乎有些奇怪的要求,但是胡闹:)您可能只对表进行了约束,然后只允许对表进行更新(不允许插入或删除)?

CREATE TABLE dbo.Config (
    ID INT identity(1,1), 
    CONFIGURATION VARCHAR(MAX),
    constraint ck_limitrows CHECK (ID <=1) 
    );

不过,这样做有点hacker,通过存储过程强制执行对配置的更改,然后可以为您处理所有这些逻辑会更好吗?


2
只要确保没有人可以从表中删除。如果有人删除然后尝试重新插入,它将尝试插入标识2,这是不允许的。
Mat

5
这并不禁止其ID值为0或为负。正如@Mat所指出的,如果您删除第一行又插入另一行,它将失败。
ypercubeᵀᴹ

2
至于“奇怪的要求”,我宁愿使用单行表进行配置设置,而不是使用看似更常见的EAV设计。前者的优点是可以使用适当的数据类型创建列,并可以添加适当的约束(更容易)。
肯尼·埃维特

2
也许我以前的评论不太清楚。“这不禁止ID的值为0或负1”的副作用是该表可能以2行或更多行结尾。身份属性并不意味着唯一约束。
ypercubeᵀᴹ

3
为了说明@ypercubeᵀᴹ所说的内容,使用此解决方案,您可以执行INSERT INTO dbo.Config DEFAULT VALUES;一次,例如,但是可以SET IDENTITY_INSERT dbo.Config ON; INSERT INTO dbo.Config (ID) VALUES (0); SET IDENTITY_INSERT dbo.Config OFF; 多次执行,最终将得到一个多行表。
Andriy M
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.