SQL Server:如何限制表包含单行?

问题描述 投票:0回答:13

我想在我的应用程序的配置表中存储一行。我想强制该表只能包含一行。

强制单行约束的最简单方法是什么?

sql-server database-design singleton
13个回答
120
投票

确保其中一列只能包含一个值,然后将其设为主键(或应用唯一性约束)。

CREATE TABLE T1(
    Lock char(1) not null,
    /* Other columns */,
    constraint PK_T1 PRIMARY KEY (Lock),
    constraint CK_T1_Locked CHECK (Lock='X')
)

我在各种数据库中有许多这样的表,主要用于存储配置。知道如果配置项应该是 int,那么您只能从数据库中读取 int,这要好得多。


64
投票

我通常使用达米安的方法,这对我来说一直很有效,但我还补充一件事:

CREATE TABLE T1(
    Lock char(1) not null DEFAULT 'X',
    /* Other columns */,
    constraint PK_T1 PRIMARY KEY (Lock),
    constraint CK_T1_Locked CHECK (Lock='X')
)

添加“DEFAULT 'X'”,您将永远不必处理 Lock 列,并且在第一次加载表时不必记住哪个是锁定值。


19
投票

您可能需要重新考虑这一策略。在类似的情况下,我经常发现保留旧的配置行以获取历史信息是非常宝贵的。

为此,您实际上有一个额外的列

creation_date_time
(插入或更新的日期/时间)和一个插入或插入/更新触发器,它将使用当前日期/时间正确填充它。

然后,为了获取当前配置,您可以使用以下命令:

select * from config_table order by creation_date_time desc fetch first row only

(取决于您的 DBMS 风格)。

这样,您仍然可以维护用于恢复目的的历史记录(如果表变得太大,您可以制定清理程序,但这不太可能),并且您仍然可以使用最新的配置。


5
投票

您可以实现 INSTEAD OF Trigger 以在数据库中强制执行此类业务逻辑。

触发器可以包含逻辑来检查表中是否已存在记录,如果存在,则回滚插入。

现在,退一步看一下更大的图景,我想知道是否有一种替代的、更合适的方式来存储这些信息,例如在配置文件或环境变量中?


3
投票

我知道这已经很老了,但有时最好不要考虑大,而是使用像这样的恒等整数:

Create Table TableWhatever
(
    keycol int primary key not null identity(1,1) 
         check(keycol =1),
    Col2 varchar(7)
)

这样,每次您尝试插入另一行时,检查约束都会引发,阻止您插入任何行,因为身份 p 键不接受除 1 之外的任何值


2
投票

这是我为锁定类型表提出的一种解决方案,该表只能包含一行,保存 Y 或 N(例如应用程序锁定状态)。

创建包含一列的表格。我在一列上放置了检查约束,以便只能在其中放入 Y 或 N。 (或 1 或 0,或其他)

在表中插入一行,状态为“正常”(例如N表示未锁定)

然后在只有 SIGNAL (DB2) 或 RAISERROR (SQL Server) 或 RAISE_APPLICATION_ERROR (Oracle) 的表上创建 INSERT 触发器。这使得应用程序代码可以更新表,但任何 INSERT 都会失败。

DB2 示例:

create table PRICE_LIST_LOCK
(
    LOCKED_YN       char(1)   not null  
        constraint PRICE_LIST_LOCK_YN_CK  check (LOCKED_YN in ('Y', 'N') )
);
--- do this insert when creating the table
insert into PRICE_LIST_LOCK
values ('N');

--- once there is one row in the table, create this trigger
CREATE TRIGGER ONLY_ONE_ROW_IN_PRICE_LIST_LOCK
   NO CASCADE 
   BEFORE INSERT ON PRICE_LIST_LOCK
   FOR EACH ROW
   SIGNAL SQLSTATE '81000'  -- arbitrary user-defined value
     SET MESSAGE_TEXT='Only one row is allowed in this table';

对我有用。


1
投票

我使用名为 IsActive 的位字段作为主键。 所以最多可以有2行,获取有效行的sql是: 从设置中选择 *,其中 IsActive = 1 如果该表名为“设置”。


1
投票

最简单的方法是将 ID 字段定义为值 1(或任何数字,....)的计算列,然后考虑 ID 的唯一索引。

CREATE TABLE [dbo].[SingleRowTable](
  [ID]  AS ((1)),
  [Title] [varchar](50) NOT NULL,
   CONSTRAINT [IX_SingleRowTable] UNIQUE NONCLUSTERED 
   (
      [ID] ASC
   )
) ON [PRIMARY]

0
投票

您可以在表上的插入操作上编写触发器。每当有人尝试在表中插入新行时,请消除插入触发器代码中删除最新行的逻辑。


0
投票

老问题,但是使用小列类型的 IDENTITY(MAX,1) 怎么样?

CREATE TABLE [dbo].[Config](
[ID] [tinyint] IDENTITY(255,1) NOT NULL,
[Config1] [nvarchar](max) NOT NULL,
[Config2] [nvarchar](max) NOT NULL

0
投票
CREATE TABLE T1(
    id ENUM('') NOT NULL PRIMARY KEY,
    /* Other columns */,

)

-2
投票
IF NOT EXISTS ( select * from table )
BEGIN
    ///Your insert statement
END

-2
投票

这里我们还可以创建一个不可见的值,该值在第一次输入数据库后将相同。例如: 学生表: 编号:整数 名字:char 在输入框中,我们必须为 id 列指定相同的值,该值将在第一个条目之后受到限制,而不是由于主键约束而写入锁定 bla bla,因此永远只有一行。 希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.