增加新行的值
鉴于 Web 应用程序中的此表设计:
CREATE TABLE `invoice` (
`invoice_nr` int(10) unsigned NOT NULL AUTO_INCREMENT,
`revision` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`invoice_nr`,`revision`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci
插入新发票修订并取回分配的修订号的最方便、最可靠的方法是什么?
第一个明显的方法让我觉得在共享环境中不可靠:
SELECT MAX(revision)+1 AS next_revision -- E.g. 2
FROM invoice
WHERE invoice_nr = 31416;
INSERT INTO invoice (invoice_nr, revision)
VALUES (31416, 2);
这种替代方案看起来稍微更好(我不知道它是否实际上更好):
INSERT INTO invoice (invoice_nr, revision)
SELECT 31416, MAX(revision)+1
FROM invoice
WHERE invoice_nr = 31416;
...但我不知道修订号,除非我运行一个新查询:
SELECT MAX(revision) AS last_revision
FROM invoice
WHERE invoice_nr = 31416;
有推荐的方法吗?
应用程序在 PHP 上运行,具有良好的旧 mysql 扩展 -mysql_query()
等。
Given this table design in a web application:
CREATE TABLE `invoice` (
`invoice_nr` int(10) unsigned NOT NULL AUTO_INCREMENT,
`revision` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`invoice_nr`,`revision`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci
What's the most handy and reliable way to insert a new invoice revision and get back the assigned revision number?
The first obvious approach strikes me as unreliable in a shared environment:
SELECT MAX(revision)+1 AS next_revision -- E.g. 2
FROM invoice
WHERE invoice_nr = 31416;
INSERT INTO invoice (invoice_nr, revision)
VALUES (31416, 2);
This alternative looks slightly better (I don't know if it's actually better):
INSERT INTO invoice (invoice_nr, revision)
SELECT 31416, MAX(revision)+1
FROM invoice
WHERE invoice_nr = 31416;
... but I can't know the revision number unless I run a new query:
SELECT MAX(revision) AS last_revision
FROM invoice
WHERE invoice_nr = 31416;
Is there a recommended method?
App runs on PHP with good old mysql extension--mysql_query()
et al.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Mysql 有一个名为
last_insert_id()
的函数,它返回最后一个自动生成的 ID。因此,您可以在插入数据后直接SELECT last_insert_id()
。PHP 有一个内置函数来执行此操作,称为 mysql_insert_id() 。
更多信息请参见: http://www.php.net /manual/en/function.mysql-insert-id.php
虽然这都是正确的并且通常很有用,但实际上并不是这里要寻找的内容。我的做法是生成表格。第一个称为带有自动增量字段的发票,第二个称为invoice_revisions。这应该与添加了视野字段的发票表具有相同的格式。
然后,当您更新发票表时,首先执行以下操作:
INSERT INTOinvoice_revision SELECT i.*,IFNULL(max(ir.revision),0)+1 AS revision FROMinvoice i LEFT JOINinvoice_revision ir on ir.invoice_nr = i .invoice_nr WHERE i.invoice_nr = ?
然后照常更新您的发票表。这样,您就可以在发票表中获得最新数据,并在invoice_revisions 表中获得所有先前版本的列表。
请注意,如果您使用 Myisam 表,请在该表中的 auto_increment 处设置修订版:
http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html
Mysql has a function called
last_insert_id()
that returns the last auto generated ID. So you can justSELECT last_insert_id()
straight after inserting your data.PHP has a built in function for doing this called
mysql_insert_id()
.More on that here: http://www.php.net/manual/en/function.mysql-insert-id.php
Whilst that's all true and generally useful it's not actually what's being looked for here. How I'd do this is generate to tables. One called invoice with you auto increment field and a second called invoice_revisions. This should have the same format as the invoice table with the added vision field.
Then when you update your invoice table you first do:
INSERT INTO invoice_revision SELECT i.*,IFNULL(max(ir.revision),0)+1 AS revision FROM invoice i LEFT JOIN invoice_revision ir on ir.invoice_nr = i.invoice_nr WHERE i.invoice_nr = ?
Then update your invoice table as normal. This way you have your up to date data in the invoice table and the list of all the previous versions in the invoice_revisions table.
Note if you are using Myisam tables you and set the revision at the auto_increment in that table:
http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html
如果您在插入和选择周围放置一个适当隔离的事务,则没有人可以在两个语句之间更改这些表。
另一种方法是使用存储过程来执行这两个命令并返回结果。
if you put a properly isolated transaction around your insert and select nobody may alter these tables between both statements.
another approach is to use a stored procedure to execute both commands and return the result.
我从 MySQL 手册中收集了一些技术。我想我应该在这里分享它们以供记录。
1.表锁定
如果在表上放置锁,则其他并发进程将排队。然后,您不需要任何特殊技巧来避免欺骗:
2. LAST_INSERT_ID(expr)
LAST_INSERT_ID() 函数接受一个可选参数。如果设置,它会返回这样的值,并且还会将其存储在当前会话中,因此下次调用 LAST_INSERT_ID() 将返回该值。这是模拟序列的便捷方法:
I've gathered a couple of techniques from the MySQL manual. I thought I should share them here for the records.
1. Table locking
If you place a lock on the table, other simultaneous processes will be queued. Then, you don't need any special trick to avoid dupes:
2. LAST_INSERT_ID(expr)
The LAST_INSERT_ID() function accepts an optional parameter. If set, it returns such value and it also stores it for the current session so next call to LAST_INSERT_ID() will return that value. This is a handy way to emulate sequences: