如何强制 MySQL 将 0 作为有效的自增值

Posted

技术标签:

【中文标题】如何强制 MySQL 将 0 作为有效的自增值【英文标题】:How to force MySQL to take 0 as a valid auto-increment value 【发布时间】:2010-11-11 15:56:55 【问题描述】:

长话短说,我有一个 SQL 文件,我想将其导入为 skel 样式文件,所以这将通过编程重复完成。我可以随心所欲地编辑 SQL 文件,但我不想接触应用程序本身。

此应用程序使用userid = 0 代表匿名用户。它还在数据库中有一个相关的(空白)条目来表示这个“用户”。因此,我的skel.sql 中的行看起来像这样:

INSERT INTO `TABLE_PREFIXusers` VALUES (0, '', '', '', 0, 0, 0, '', '', 0, 0, 0, 0, 0, NULL, '', '', '', NULL);

问题在于uid 是一个auto_increment 字段,从技术上讲,0 是一个无效值。或者至少,如果将其设置为 0,则基本上是在告诉 mysql,“请在此字段中插入下一个 id。”

现在,我想我可以将 INSERT 然后 UPDATE 查询放入我的 SQL 文件中,但是有没有办法告诉 MySQL 是的,我实际上想在这个字段中插入 0

【问题讨论】:

【参考方案1】:

从我得到的答案here:

你可以使用:

SET [GLOBAL|SESSION] sql_mode='NO_AUTO_VALUE_ON_ZERO'

如here 所述,这将阻止 MySQL 将 INSERT/UPDATE ID 0 解释为下一个序列 ID。这种行为将被限制为 NULL。

不过,我认为这是应用程序中非常糟糕的行为。您必须非常小心,以确保始终如一地使用它,尤其是当您选择在以后实施复制时。

【讨论】:

您必须注意的一件事:sql_mode 是一个以逗号分隔的标志列表。如果您使用sql_mode='NO_AUTO_VALUE_ON_ZERO',您可能会无意中禁用其他标志 这个解决方案基本上对我有用,但是我的转储还包括一些地方,它覆盖了 sql 文件中间的sql_mode,然后重置为设置为的变量OLD_SQL_MODE回到脚本末尾。这在我的脚本中间覆盖了我的NO_AUTO_VALUE_ON_ZERO,使其无法正常工作。我的解决方案是创建一个 INIT_OLD_SQL_MODE 的新变量,我曾经在最后重置为,在我将 sql_mode 设置为 NO_AUTO_VALUE_ON_ZERO 后,我设置了一个新变量 OLD_SQL_MODE,这些临时覆盖可以重置为跨度> 【参考方案2】:

检查您的 sql DB 模式:

SELECT @@[GLOBAL|SESSION].sql_mode;

如果为空或未设置,请使用:

SET [GLOBAL|SESSION] sql_mode='NO_AUTO_VALUE_ON_ZERO'

小心!如果您使用 GLOBAL,则不会立即更改,您需要重新启动连接才能应用设置。

因此,例如,如果您要将数据从一个数据库恢复到另一个数据库,并且您不确定是否应用了此设置,请使用 SESSION 立即更改(它会重置关闭连接时)。完成后,插入0值,即使sql_mode改变也不会改变。

要重置此模式(和其他),请使用

SET [GLOBAL|SESSION] sql_mode=''

不建议使用零自动增量值,因为它们在 MySQL 数据库中未设置为默认值。

更多信息请查看mysql dev page topic

更新

对于 MariaDB,使用this comment 中指出的命令

SET sql_mode='NO_AUTO_VALUE_ON_ZERO'

【讨论】:

这在 MariaDB 上不起作用,我不得不使用它:SET sql_mode='NO_AUTO_VALUE_ON_ZERO' @hiddeneyes02 这是2010年的帖子,谢谢你的评论,我会更新答案:) 无效:SELECT @@[GLOBAL|SESSION].sql_mode;确实有效: SELECT @@SESSION.sql_mode;确实有效:SELECT @@GLOBAL.sql_mode;【参考方案3】:

如果你不想处理 mysql 变量,这里有一个有用的 hack:

INSERT INTO `TABLE_PREFIXusers` VALUES (-1, '', '', '', 0, 0, 0, '', '', 0, 0, 0, 0, 0, NULL, '', '', '', NULL);

然后

UPDATE `TABLE_PREFIXusers` SET id = 0 where id = -1;

显然,这假设您使用的是有符号整数,而不是表 id 使用负值。

【讨论】:

显然,如果您使用的是无符号整数,则它不起作用。【参考方案4】:

故障安全方式:

SET @@session.sql_mode = 
    CASE WHEN @@session.sql_mode NOT LIKE '%NO_AUTO_VALUE_ON_ZERO%' 
        THEN CASE WHEN LENGTH(@@session.sql_mode)>0
            THEN CONCAT_WS(',',@@session.sql_mode,'NO_AUTO_VALUE_ON_ZERO')  -- added, wasn't empty
            ELSE 'NO_AUTO_VALUE_ON_ZERO'                                    -- replaced, was empty
        END
        ELSE @@session.sql_mode                                             -- unchanged, already had NO_AUTO_VALUE_ON_ZERO set
    END
检查是否已在 sql_mode 中设置 NO_AUTO_VALUE_ON_ZERO 如果不为空,则添加到 sql_mode 仅设置会话,我建议仅在需要插入 0 的会话上使用它

【讨论】:

以上是关于如何强制 MySQL 将 0 作为有效的自增值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Python 将任何字符串转换为有效的自定义模式?

MySQL--自增列持久化问题

mysql 自增值的维护

MySQL的自增id用尽时的解决方案

MySQL中的自引用表字段

如何强制 Text::CSV 将数字存储为文本?