MySQL:在插入过程中重用自动增量

MySQL:在插入过程中重用自动增量,mysql,Mysql,我正在设计一个comments MySQL数据库,我的comments表包含以下字段: id主键,自动递增 threadint,非空 内容 除了根注释外,对同一注释的所有回复必须共享相同的线程。这在用户回复评论时很简单,但在发布新的根评论时又如何呢?我想我应该为根注释设置thread=id 问题是,我不知道如何编写一个查询,在填充线程时,在同一个查询中重用刚刚创建的id值。这可能吗 我试过了 INSERT INTO `comments` VALUES (NULL, LAST_INSERT_I

我正在设计一个comments MySQL数据库,我的comments表包含以下字段:

  • id
    主键,自动递增
  • thread
    int,非空
  • 内容
除了根注释外,对同一注释的所有回复必须共享相同的
线程。这在用户回复评论时很简单,但在发布新的根评论时又如何呢?我想我应该为根注释设置
thread=id

问题是,我不知道如何编写一个查询,在填充
线程时,在同一个查询中重用刚刚创建的
id
值。这可能吗

我试过了

INSERT INTO `comments`
VALUES (NULL, LAST_INSERT_ID(), 'hi there')

这将为我提供上一次插入的id,而不是当前的id。我必须使用2个查询吗?

您只需将
线程设置为
NULL
,表示注释是根注释,而不是附加到线程。

感谢Michael的回答,我开始;基本上,事件处理程序在发生某些事情时运行一些代码。迈克尔的扳机对我不起作用,但以下是有效的:

USE `my_db_name`;
DELIMITER $$CREATE TRIGGER comments_bi 
BEFORE INSERT ON `comments`
FOR EACH ROW
BEGIN
  DECLARE nextID INT DEFAULT 0;

  SELECT AUTO_INCREMENT INTO nextID FROM information_schema.tables
  WHERE table_name = 'comments' AND table_schema = DATABASE();

  IF NEW.`thread` IS NULL OR NEW.`thread` = 0 THEN
    SET NEW.`thread` = nextID;
  END IF;

END $$
DELIMITER ;
一个大警告:由于此触发器需要访问
信息\u架构
,因此只有
根帐户才能定义它

谢谢你的灵感

我必须使用2个查询吗

对。正如您所发现的,在BEFORE INSERT触发器中尚未生成id值。但不能在插入后触发器中更改新的.thread值

您不能依赖于读取信息模式,因为您可能导致竞争条件

您只需执行插入,然后立即执行:

UPDATE comments SET thread=id WHERE id=LAST_INSERT_ID() AND thread IS NULL;
如果是根注释

另请参见我过去对类似主题的回答:


你说的是mysql\u insert\u id()吗?你的问题不清楚。当前查询没有ID,因为尚未插入该行。您只能获取上次插入时生成的ID。您可以尝试通过从表中选择MAX(ID)+1来确定ID是什么,但这实际上是不准确的,自动递增计数器保存在别处。@sumit是MySQL函数还是PHP函数?如果我在查询中使用它,我会得到一个错误。如果它是一个PHP函数,它将不会有帮助,因为PHP在向MySQL发送查询时无法知道插入ID,因为此时还没有创建插入IDtime@Havenard我想您已经理解了这个问题。我希望创建的
id
能够自动用于
线程
,除非我还指定了一个
线程
值。我知道我可以在两个查询中完成。我的问题是:我能一次完成吗?
mysql\u insert\u id()
是一个PHP/C函数,它可能适用于其他语言,并且有与MySQLi和其他库相同的版本。这就是我以前的设计。通过添加这个
thread=null
corner案例,它使得其他查询更加复杂;例如,如果我想按线程对所有评论进行分组,并按postTime排序,这就不再简单了。如果我想通过线程统计所有的投票(评论可以被投票向上或向下),等等。。。所以这一次我希望有一个更简单的实现,我不推荐这个解决方案,因为它很容易受到比赛条件的影响。两个并发插入可以同时从信息模式中读取,并尝试使用相同的值;我现在有两个问题。嘿,比尔,谢谢你抽出时间。你的建议如何不受比赛条件的影响?换句话说,在前一个插入和触发的
更新
之间是否存在另一个
插入
?是的,可能存在并发插入,但每个插入将生成其自己的唯一id。该部分没有风险。然后每个线程都有自己的id值。请记住,LAST_INSERT_ID()只返回同一会话中生成的最新ID值。因此,两个并发会话可以生成各自的id值,而不会相互影响;这就解释了为什么我会从我的PHP代码中运行查询,但是在我的DB管理软件中,
LAST\u INSERT\u ID()
的结果不会改变。因为我毕竟运行了两个查询,所以我捕获了第一个查询返回的insert ID值,并在第二个查询中使用它,而不是调用
LAST\u insert\u ID()
@Michael sqlbot,我相信是前者。存储引擎负责生成AI值。生成AI值需要一种表锁来防止竞争条件,即使在InnoDB的情况下也是如此。最好将AI值的分配延迟到触发器运行之后,以防触发器导致信号中止。分配一个不会被使用的值是没有意义的。@michaelsqlbot,是的,很长一段时间以来,自动递增机制都不是标准SQL的一部分。我想也许在2006年,语言中终于有了一个自动递增语法的定义(尽管目前还没有品牌的SQL数据库符合这个定义),但SQL标准并没有定义实现细节。