代码之家  ›  专栏  ›  技术社区  ›  Martin

SQL Server:如何约束表以包含单行?

  •  67
  • Martin  · 技术社区  · 15 年前

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

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

    10 回复  |  直到 7 年前
        1
  •  83
  •   Luke Girvin Nathan Bedford    9 年前

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

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

    我在不同的数据库中有许多这样的表,主要用于存储配置。如果配置项应该是一个int,那么只从db中读取一个int就更好了。

        2
  •  46
  •   ACB    15 年前

    我通常使用达米恩的方法,这对我来说一直都很有用,但我还补充了一点:

    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'”,您将不必处理锁列,也不必在第一次加载表时记住哪个是锁值。

        3
  •  14
  •   paxdiablo    15 年前

    你可能想重新考虑一下这个策略。在类似的情况下,我经常发现将旧的配置行放在一旁以获取历史信息是非常宝贵的。

    要做到这一点,您实际上有一个额外的列 creation_date_time (插入或更新的日期/时间)和插入或插入/更新触发器,将用当前日期/时间正确填充。

    然后,为了获得当前的配置,您使用如下内容:

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

    (取决于您的DBMS风格)。

    这样,为了恢复的目的,您仍然可以维护历史记录(如果表太大,您可以建立清理过程,但这不太可能),并且仍然可以使用最新的配置。

        4
  •  4
  •   John Sansom    15 年前

    您可以实现 Trigger 在数据库中强制执行这种类型的业务逻辑。

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

    现在,回顾一下全局,我想知道是否有其他更合适的方法来存储这些信息,例如在配置文件或环境变量中?

        5
  •  2
  •   user3382925    11 年前

    我对名为isactive的主键使用位字段。 所以最多可以有2行,得到有效行的SQL是: 从isactive=1的设置中选择*。 如果表是命名设置。

        6
  •  2
  •   David A Beamer    10 年前

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

    用一列创建表。我在一列上放置了一个检查约束,这样只有y或n可以放入其中。(或1或0或其他)

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

    然后在只有信号(DB2)或raiserror(SQL Server)或raise_application_error(Oracle)的表上创建一个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';
    

    为我工作。

        7
  •  1
  •   Karan    15 年前

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

        8
  •  1
  •   NeutronCode    10 年前

    旧问题,但是如何使用小列类型的标识(max,1)?

    CREATE TABLE [dbo].[Config](
    [ID] [tinyint] IDENTITY(255,1) NOT NULL,
    [Config1] [nvarchar](max) NOT NULL,
    [Config2] [nvarchar](max) NOT NULL
    
        9
  •  0
  •   Sachin Shanbhag    15 年前
    IF NOT EXISTS ( select * from table )
    BEGIN
        ///Your insert statement
    END
    
        10
  •  0
  •   Yishagerew    12 年前

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