插入表格并将另一列设置为自动递增的列值

Posted

技术标签:

【中文标题】插入表格并将另一列设置为自动递增的列值【英文标题】:Insert into a table and set another column to autoincremented column value 【发布时间】:2016-03-21 10:02:21 【问题描述】:

假设我有一个简单的表格:

create table foo

    id INTEGER PRIMARY KEY AUTOINCREMENT,
    bar INTEGER

我想插入一个新行,这样id == bar 其中id 的值由数据库选择,也就是自动增量。

类似这样的:

INSERT INTO foo (id, bar) VALUES (NULL, id)

是否可以在一个语句中做到这一点?

它的 SQL 语法是什么?

【问题讨论】:

为什么需要bar 列?如果它总是与id 相同? 它是如何完成的取决于特定的数据库服务器,但我猜它需要一个触发器来执行此操作,在插入行并将 bar 列设置为 id 列中的值后触发跨度> @vkp 我最初想要id==bar,最终bar 可能会被更改。 @qarma 那么输出会是什么? 【参考方案1】:

您不能拥有two auto increment fields。您应该使用单个自动增量字段。鉴于这两个字段对于每一行都将始终具有相同的值,因此无论如何都没有理由必须使用这些字段。

但是您可以只创建触发器,该触发器将在插入行后更新另一个等于自动递增值的字段。并在您不希望它们具有相同值时删除该触发器。

CREATE TRIGGER update_foo AFTER INSERT ON foo 
  BEGIN
    UPDATE foo SET bar = NEW.id ;
  END;

当bar最终改变为与id不同的值时,删除触发器

DROP TRIGGER update_foo

【讨论】:

由于您的触发器处于插入状态,我认为您不需要在 bar 需要更新时将其删除。 @JoshEdwards:我的意思是当你不想让两者的值相同时,删除触发器。 @Y.B. : 更新答案。 1. INSERT : NEW 引用有效 2. UPDATE : NEW 和 OLD 引用有效 3. DELETE : OLD 引用有效【参考方案2】:

INSERT INTO foo (bar) VALUES (id)

【讨论】:

这会为 bar 插入一个值 0。 但是建表脚本必须是这样的:create table foo (ID int IDENTITY(1,1) PRIMARY KEY, bar INTEGER) 我在 mysql 中尝试时为我输入了 0,在 Sqlite 中尝试时根本没有运行 好吧,我的代码是用于 sql server,在 mysql 中你可以使用:create table foo (ID int NOT NULL AUTO_INCREMENT, bar int, PRIMARY KEY (id)) -- 例如 INSERT INTO foo ( bar) 值 (12)【参考方案3】:

正如 cmets 中提到的,我相信这将特定于每个数据库实现,因此了解您正在使用的服务器会很有用。但是,对于 MySQL,您可以执行以下操作:

INSERT INTO foo (bar) 
  SELECT AUTO_INCREMENT 
  FROM information_schema.tables 
  WHERE table_schema = DATABASE() 
    AND TABLE_NAME = 'foo';

或者,由于您可能正在使用 SQLite(基于标签),您可以试试这个:

INSERT INTO foo (bar) 
  SELECT (seq + 1)
  FROM sqlite_sequence
  WHERE name = 'foo';

【讨论】:

这对于竞争交易是否可靠?如sqlite_sequence 被视为交易的一部分?会不会出现id 的值在一个事务中为+1 而在另一个事务中为+2 的情况? 我相信它是可靠的,因为您不会遇到任何重复使用相同 ID 的问题,并且数据库在内部使用 sqlite_sequence,但我建议对其进行测试以验证.不知道您在一笔交易中的 +1 和另一笔交易中的 +2 是什么意思。它总是 +1,因为序列会在插入后更新,所以加一会为您提供匹配的。【参考方案4】:

这不是在一个查询中完成的,但它可以在存储过程中使用。重复该集合以表明它确实根据数据库创建的 ID 进行插入和更新。这是在 SQL Server 2008R2 上完成的

declare @tmpTable TABLE (
    id INT identity(1,1),
    bar INT
    )

    declare @myId INT
    insert @tmpTable (bar) values (0)
    SET @myId = SCOPE_IDENTITY() 
    update @tmpTable SET bar = @myId where id = @myId 

    insert @tmpTable (bar) values (0)
    SET @myId = SCOPE_IDENTITY() 
    update @tmpTable SET bar = @myId where id = @myId 


    insert @tmpTable (bar) values (0)
    SET @myId = SCOPE_IDENTITY() 
    update @tmpTable SET bar = @myId where id = @myId 


    insert @tmpTable (bar) values (0)
    SET @myId = SCOPE_IDENTITY() 
    update @tmpTable SET bar = @myId where id = @myId 

    select * FROM @tmpTable 

输出

id  bar
1   1
2   2
3   3
4   4

【讨论】:

【参考方案5】:

在 SQLite 中你可以

BEGIN TRANSACTION;
  INSERT INTO foo (id, bar) VALUES (NULL, 0);
  UPDATE foo SET bar = id WHERE _ROWID_ = last_insert_rowid();
COMMIT;

确保没有其他语句妨碍您的双语句表达式。

【讨论】:

OT:您是否通过竞争交易对此进行了测试?如在这种情况下,last_insert_rowid() 可靠吗? @qarma 我没有,但根据 SQLite 文档,Insert 会在数据库文件上创建RESERVED 锁定,以确保在我们的事务结束之前根本不会发生其他数据库写入。因此没有其他线程应该能够影响last_insert_rowid()。当然,仍然可能存在各种可能影响last_insert_rowid() 甚至Insert 的情况,例如WITHOUT ROWID 表子句或INSTEAD OF 触发器。恐怕该解决方案必须在特定数据库上进行测试,但原则上 - 这就是事务的用途。【参考方案6】:

您可以将其用作:

INSERT INTO foo (bar) VALUES (last_insert_rowid()+1)

生成的 ID 保存在服务器上的 每个连接的基础。这意味着返回的值 给定客户端的函数是生成的第一个 AUTO_INCREMENT 值 对于影响 AUTO_INCREMENT 列的最新语句 客户。此值不会受到其他客户端的影响,即使它们 生成自己的 AUTO_INCREMENT 值。这种行为确保 每个客户端都可以检索自己的 ID 而无需担心 其他客户端的活动,并且不需要锁或 交易。

【讨论】:

你只是猜测id 也将设置为LAST_INSERT_ID()+1?如果发生竞争交易,这不会失败吗?也就是说,一笔交易将获得+1,另一笔交易将获得+2 您可以通过在两列中添加唯一约束来控制此行为,如果失败则再次运行此查询。第二部分应该通过脚本完成 仅当您当前连接上的最后一次插入也插入 foo 时才有效。如果您在打开连接后没有插入任何内容,或者最后一次插入到不同的(自动增量)表中,您认为会发生什么?!? ***.com/questions/36573707/…【参考方案7】:
insert into [Test].[dbo].[foo] (bar) select MAX(id)+1 from [Test].[dbo].[foo]

【讨论】:

以上是关于插入表格并将另一列设置为自动递增的列值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Petapoco 将自动增量 ID 设置为另一列

如何将一列的列值组合到 MySQL 中的另一列中?

对最后一小时分组中的列值求和,然后将所有 5 的总和作为另一列中的总和

SQL - 在填充另一列时继承派生列值

PySpark - 添加一个递增的数字列,该列根据另一列值的变化重置为 1

Oracle里面想实现自动插入递增的序号