【问题标题】:How to guarantee a table with exactly one row and one column?如何保证一张表只有一行一列?
【发布时间】:2019-09-21 09:29:45
【问题描述】:

使用 PostgreSQL 11.5。我需要允许一个表只允许其中的一行和一列(不是 0 或 2,正好是 1)。我觉得ADD CONSTRAINT 会很有用,但我不知道该怎么做。

我希望能够在需要时更新此行。

使以下内容有效的东西:

 foo
-----
 bar

但不是以下:

 foo | baz
-----+-----
 bar | bin
-----+-----
     | gar

【问题讨论】:

    标签: sql postgresql database-design permissions check-constraints


    【解决方案1】:

    您可以强制表只有一行在您的主键(或任何其他唯一且不可为空的列)上设置 CHECK 约束,如下所示:

    ALTER TABLE <tablename> ADD CONSTRAINT [<name>] CHECK ([pk/unique field] = [constant value]);
    

    无论如何,由于您想要一个可更新的字段,您需要使用一个包含 2 列的表。如果您真的只需要一行(并且仅选择foo 或为此目的创建视图不是一种选择),您还可以在插入和删除时使用触发器(并通过引发异常来拒绝其中的任何操作) .为避免出现空表(不确定是否需要),您还需要在删除时使用此触发器,约束不够强。有关触发器,请参见此处:https://www.postgresql.org/docs/current/triggers.html

    要避免任何进一步的ALTER TABLE 命令(例如添加列)和DROP TABLE,请使用事件触发器。有关更多信息,请查看文档:https://www.postgresql.org/docs/current/event-triggers.html

    关于使用带有触发器的 PL/pgSQL,还可以查看https://www.postgresql.org/docs/current/plpgsql-trigger.html

    【讨论】:

      【解决方案2】:

      这是一个可能对您有所帮助的示例:

      CREATE TABLE singleton (x SMALLINT NOT NULL UNIQUE CHECK (x=1), foo VARCHAR(10) NOT NULL);
      
      INSERT INTO singleton (x, foo) VALUES (1,'one row');
      

      【讨论】:

        【解决方案3】:

        创建一个VIEW 作为超级用户或某个受信任的角色:

        CREATE VIEW onerow AS SELECT 'bar' AS foo;  -- defaults to type text
        GRANT SELECT ON onerow TO public;
        

        创造者就是拥有者。或者:

        ALTER VIEW onerow OWNER TO postgres;   -- or to a trusted role
        

        每个人都可以通过它SELECT 就像在任何其他表格中一样。
        没有人可以在 VIEW 中添加或删除行 - 甚至无法使用 DDL 命令更改任何内容。
        只有 DML 命令可以更改它,并且只有所有者或超级用户可以这样做:

        CREATE OR REPLACE VIEW onerow AS 
        SELECT 'bar1' AS foo;
        

        请记住,最终,一个有动力的超级用户可以做任何事情

        在一个非常繁忙的系统上,CREATE OR REPLACE VIEW 占用的排他锁可能是个问题。这是我能想到的这个解决方案唯一可能出现的问题。


        或者,考虑这个密切相关的答案以允许最多一行:

        您可以这样做并且(作为超级用户):

        ALTER TABLE onerow OWNER TO postgres;
        REVOKE ALL ON onerow FROM public;
        GRANT SELECT ON onerow TO public;
        

        超级用户仍然可以DELETETRUNCATE。您也可以使用TRIGGERRULE 来防止这种情况发生...

        或者您可以为INSERTDELETE 添加通用TRIGGERRETURN NULLRULEDO INSTEAD NOTHING ...


        一个单一的值也可以由函数或“全局变量”提供。见:

        【讨论】:

          猜你喜欢
          • 2018-11-01
          • 2014-05-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-05
          • 1970-01-01
          • 1970-01-01
          • 2022-01-23
          相关资源
          最近更新 更多