插入表格并将另一列设置为自动递增的列值
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]
【讨论】:
以上是关于插入表格并将另一列设置为自动递增的列值的主要内容,如果未能解决你的问题,请参考以下文章
对最后一小时分组中的列值求和,然后将所有 5 的总和作为另一列中的总和