增加新行的值

发布于 2024-09-06 21:09:03 字数 941 浏览 3 评论 0原文

鉴于 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

分分钟 2024-09-13 21:09:03

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 just SELECT 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

陪你搞怪i 2024-09-13 21:09:03

如果您在插入和选择周围放置一个适当隔离的事务,则没有人可以在两个语句之间更改这些表。

另一种方法是使用存储过程来执行这两个命令并返回结果。

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.

千里故人稀 2024-09-13 21:09:03

我从 MySQL 手册中收集了一些技术。我想我应该在这里分享它们以供记录。

1.表锁定

如果在表上放置锁,则其他并发进程将排队。然后,您不需要任何特殊技巧来避免欺骗:

LOCK TABLES invoice WRITE;

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);

-- Or INSERT INTO ... SELECT

UNLOCK TABLES;

2. LAST_INSERT_ID(expr)

LAST_INSERT_ID() 函数接受一个可选参数。如果设置,它会返回这样的值,并且还会将其存储在当前会话中,因此下次调用 LAST_INSERT_ID() 将返回该值。这是模拟序列的便捷方法:

CREATE TABLE `sequence` (
    `last_value` INT(50) UNSIGNED NOT NULL DEFAULT '1' COMMENT 'Last value used'
);

START TRANSACTION;

UPDATE sequence
SET last_value=LAST_INSERT_ID(last_value+1);

INSERT INTO invoice (invoice_nr, revision)
VALUES (31416, LAST_INSERT_ID());

COMMIT;

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:

LOCK TABLES invoice WRITE;

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);

-- Or INSERT INTO ... SELECT

UNLOCK TABLES;

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:

CREATE TABLE `sequence` (
    `last_value` INT(50) UNSIGNED NOT NULL DEFAULT '1' COMMENT 'Last value used'
);

START TRANSACTION;

UPDATE sequence
SET last_value=LAST_INSERT_ID(last_value+1);

INSERT INTO invoice (invoice_nr, revision)
VALUES (31416, LAST_INSERT_ID());

COMMIT;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文