【问题标题】:How to add constraint to sql table so that table has exactly one row如何向sql表添加约束,使表只有一行
【发布时间】:2015-04-03 18:48:48
【问题描述】:

初始创建参数表并在Postgres中添加一行。

此表应始终只有一行,否则使用此表的 SQL 查询将产生不正确的结果。不允许DELETEINSERT 加入此表,仅允许UPDATE

如何给这个表添加单行约束?
也许DELETEINSERT 触发器可以引发异常还是有更简单的方法?

【问题讨论】:

    标签: sql postgresql database-design


    【解决方案1】:

    以下将创建一个表,您只能在其中插入一行。 id 列的任何更新都将导致错误,任何插入的值与 42 不同的值都会导致错误。实际的 id 值实际上并不重要(除非您需要某些特殊含义)。

    create table singleton
    (
       id integer not null primary key default 42,
       parameter_1 text,
       parameter_2 text,
       constraint only_one_row check (id = 42)
    );
    
    insert into singleton values (default);
    

    为了防止删除,您可以使用规则:

    create or replace rule ignore_delete
      AS on delete to singleton
         do instead nothing;
    

    如果您想让insert 静默“失败”,您也可以使用规则使insert 什么也不做。如果没有该规则,insert 将产生错误。如果您还希望 delete 也生成错误,则需要创建一个仅引发异常的触发器。


    编辑

    如果您希望为插入或删除引发错误,则需要一个触发器:

    create table singleton
    (
       id integer not null primary key,
       parameter_1  text,
       parameter_2  text
    );
    
    insert into singleton (id) values (42);
    
    create or replace function raise_error()
      returns trigger
    as
    $body$
    begin
      RAISE EXCEPTION 'No changes allowed';
    end;
    $body$
    language plpgsql;
    
    
    create trigger singleton_trg 
      before insert or delete on singleton
      for each statement execute procedure raise_error();
    

    请注意,您必须在创建触发器之前插入单行,否则您无法插入该行。

    这仅对超级用户或表的所有者部分有效。两者都有权删除或禁用触发器。但这就是超级用户的本性——他可以做任何事情。

    【讨论】:

    • 主键可以在运行时更改。此表上的任何删除和插入命令都应导致异常。如何更改答案以满足这些条件?
    • @Andrus:如果表中只有一行,那么您为什么要更改主键的值?鉴于这些要求,您将需要一个简单地引发异常的插入和删除触发器。
    • 公司名作为主键。公司名称可以更改。如何创建这样的约束触发器?
    • 如果你只有一家公司,为什么需要存储它的价值?
    • 好吧,每个数据库实例可能只有一家公司,但那里可能有很多数据库实例。但是话虽如此,为什么公司名称必须是主键?如果只有一条记录,则主键没有用处。当您阅读该表时,您不需要 WHERE 子句。没有它,您将获得 1 条记录。顺便说一句,任何类型的名称通常都会产生错误的主键。太长,通常不能保证唯一,而且经常会出现拼写不明确等问题。
    【解决方案2】:

    要使任何表成为单例,只需添加此列:

    just_me bool NOT NULL DEFAULT TRUE UNIQUE CHECK (just_me)
    

    这仅允许一行。另外添加触发器@a_horse provided

    但出于此目的,我会宁愿使用函数而不是表格。更简单,更便宜。

    CREATE OR REPLACE FUNCTION one_row()
      RETURNS TABLE (company_id int, company text) LANGUAGE sql IMMUTABLE AS
    $$SELECT 123, 'The Company'$$
    ALTER FUNCTION one_row() OWNER TO postgres;
    

    将所有者设置为应允许更改的用户。

    没有其他人改变它 - 当然除了超级用户。超级用户可以做任何事情。

    您可以像使用表格一样使用此功能:

    SELECT * FROM one_row();
    

    如果你需要一个“表”,创建一个视图(内部实际上是一个特殊的表):

    CREATE VIEW one_row AS SELECT * FROM one_row();
    

    【讨论】:

    • 我正在考虑一个视图,它也只执行select 42, 'foo',但这与“应允许更新”的要求相矛盾
    • “更新”可能会替换为CREATE OR REPLACE VIEWCREATE OR REPLACE FUNCTION。也许 OP 只是不知道替代方案。
    【解决方案3】:

    我猜你不会在你的应用程序中使用 PostgreSQL root 用户,所以你可以简单地限制你的应用程序用户在UPDATE 上对该表的权限。

    INSERTDELETE 将导致 Insufficient privilege 异常。

    【讨论】:

    • 这也适用于超级用户。此表上的任何删除和插入命令也应该在超级用户中引起异常。如何实现?
    猜你喜欢
    • 1970-01-01
    • 2014-05-11
    • 1970-01-01
    • 2022-10-04
    • 2017-09-04
    • 2013-03-08
    • 1970-01-01
    • 2021-05-19
    相关资源
    最近更新 更多