【问题标题】:How can I ensure that there is one-and-only-one row in DB table?如何确保数据库表中只有一行?
【发布时间】:2011-01-17 16:03:07
【问题描述】:

我想确保我的名为“myTable”的 MySQL 表只有一行。

所以我需要能够对这一行进行更新,但显然插入和删除应该是不可能的。

我问这个问题是因为这个Stack Overflow answer

谢谢!

【问题讨论】:

    标签: mysql database database-design privileges


    【解决方案1】:
    CREATE TABLE `myTable` (
      `id` enum('1') NOT NULL,
      `MyValue1` int(6) DEFAULT '0',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='The ENUM(''1'') construct as primary key is used to prevent that more than one row can be entered to the table';
    

    【讨论】:

    • 虽然这可能是一个很好的答案,但请考虑添加更多解释,说明为什么这是正确的解决方案以及您到底在做什么 :)
    • 一个更好的解决方案,如果你问我。您无需使用触发器来拦截事件,而是对不希望的状态进行建模。
    • NOT NULL 不是必需的,因为 PRIMARY KEY 列默认具有 NOT NULL 约束
    【解决方案2】:

    最简单的方法是创建一个只有一个合法值的列,然后将其声明为not null unique

    这会强制表格有不超过一行,但仍然允许零行。如果您需要防止删除唯一的行,请使用不同答案中给出的触发器方法。

    create table example( 
        enforce_one_row enum('only') not null unique default 'only',
        ... your columns ....
    );
    

    【讨论】:

      【解决方案3】:

      根据您尝试存储的数据的具体情况,为您提供两个建议,一个或两个可能有效:

      与/或

      【讨论】:

      • 我是触发器的新手...你能给我一个触发器的例子,它会停止对特定表的所有插入、更新和删除吗?
      • 查看stackoverflow.com/questions/2981930/…中指定的解决方法
      • 顺便说一句,请记住,您还可以编写一个 AFTER 触发器来“清理”坏数据。理想情况下,约束首先会阻止数据进入表中,但是当您遇到我上面描述的限制时(并且我承认触发器不能满足所有需求),您可能会采取“清理“事后的方法。此外,考虑到如果您需要确保表中只有一行仅供读者使用,您始终可以在基表之外创建一个视图,以防止显示您不想要的数据 - 您可以获得更大的灵活性方式。
      【解决方案4】:

      试试这个:

      CREATE TABLE foo (x INT NOT NULL PRIMARY KEY CHECK (x = 1), col1 INT NOT NULL, col2 INT NOT NULL);
      

      【讨论】:

      • 似乎正如 MySQL 参考手册所说:“CHECK 子句已被解析,但被所有存储引擎忽略。”
      • benjisail,你是对的。 MySQL 很烂。但它适用于所有其他主要的 DBMS。
      【解决方案5】:

      您可以使用表权限(假设您设置了相关权限以阻止插入/删除,并且您不应再更新权限,但是任何拥有该权限的用户都可以再次覆盖该权限)

      先插入唯一一条记录 然后通过在 table_priv 列中禁用INSERT, UPDATE, DROP 来添加权限

      mysql> desc tables_priv; +--------------+------------------------------------ -------------------------------------------------- ------------------------------------+------+------+ -------------------+--------+ |领域 |类型 |空 |钥匙 |默认 |额外 | +--------------+------------------------------------ -------------------------------------------------- ------------------------------------+------+------+ -------------------+--------+ |主持人 |字符(60) |否 |优先级 | | | |数据库 |字符(64) |否 |优先级 | | | |用户 |字符(16) |否 |优先级 | | | |表名 |字符(64) |否 |优先级 | | | |授予人 |字符(77) |否 |穆尔 | | | |时间戳 |时间戳 |否 | | CURRENT_TIMESTAMP | | |表隐私 | set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view ') |否 | | | | |列隐私 | set('Select','Insert','Update','References') |否 | | | | +--------------+------------------------------------ -------------------------------------------------- ------------------------------------+------+------+ -------------------+--------+ 8 行一组(0.00 秒)

      【讨论】:

        【解决方案6】:

        如果您的数据库设置为“严格”模式,您可以创建如下表:

        创建表foo(id enum('SYSROW') not null,(其他列定义)主键(id));

        【讨论】:

          【解决方案7】:
          如果不存在则创建表 myTable ( ID int 不为空 ) 引擎=innodb; 选择“创建触发器 tbi_myTable”; 如果存在 tbi_myTable,则删除触发器; 分隔符 // 创建触发器 tbi_myTable 在 myTable 上插入之前 对于每一行 开始 if (select count(1) from myTable) > 0 then -- Signal 仅在 5.6 及以上使用另一种方式引发错误:如果小于 5.6 SIGNAL SQLSTATE '50000' SET MESSAGE_TEXT = '不能在 myTable 中只插入一行!'; 万一; 结尾 // 分隔符; 插入 myTable 值 (1); -- 这会产生错误 插入 myTable 值 (2); -- 这将只有一行带有“1” 从我的表中选择 *;

          【讨论】:

            【解决方案8】:

            您可以使用 IF 语句签入 mySQL。

            IF (SELECT count(*) FROM myTable) = 1
                //your SQL code here.
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-10-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多