2013-10-14 25 views
2

我即将编写几个MySQL表来处理发票。2个auto_increment字段,其中1个重置

我的计划是打入3代主要表这样的:

create table invoice 
(
    id auto_increment, 
    client (foreign key), 
    created (date), 
    *etc*... 
) 

create table products 
(
    id auto_increment 
    *product info*... 
) 

create table invoice_products 
(
    invoice_id (references invoice.id) 
    row (resetting auto_increment) <--THIS!!! 
    product_id(references products.id) 
    product_quantity INT 
    primary key (invoice_id,row) 
) 

的困境是,创建一个新的发票时,invoice.id被auto_incremented,这是因为它应该是。我想要的是invoice_products.row从每个新发票的1开始。 因此,对于每个新发票,行auto_increment将从1开始,但如果将新行添加到现有发票ID,行ID将从其停止的位置继续。

有关如何完成此任务的任何建议?

(我希望代码的短版是足以让你明白的窘境)

预先感谢任何建议!

编辑:澄清:数据库中的所有表都InnoDB的

+1

我认为你正在尝试混合*数据库设计*和*演示*。只需在检索发票行后添加行号,否? –

+0

MyISAM引擎可以做到这一点 - 完全符合您的设计('主键(invoice_id,row)')。如果您使用InnoDB,则必须在代码中执行(SQL或应用程序)。 –

+0

@GuillaumePoussel:唯一的困难就是无法检查一致性。并且没有可靠的方法来引用发票上的特定行。有可能一张发票有几行相同的产品,甚至相同的数量。 – user2879867

回答

0

你所要做的就是将你的表改为使用MyISAM引擎。但请注意,MyISAM不支持事务和外键。

不管怎么说,这是一个例子,将如何工作(引述manual):

对于MyISAM,你可以在多列索引中的次级柱指定AUTO_INCREMENT BDB表。在这种情况下,AUTO_INCREMENT列的生成值计算为MAX(auto_increment_column)+ 1 WHERE prefix = given-prefix。当您想要将数据放入有序组时,这非常有用。

CREATE TABLE animals (
    grp ENUM('fish','mammal','bird') NOT NULL, 
    id MEDIUMINT NOT NULL AUTO_INCREMENT, 
    name CHAR(30) NOT NULL, 
    PRIMARY KEY (grp,id) 
) ENGINE=MyISAM; 

INSERT INTO animals (grp,name) VALUES 
    ('mammal','dog'),('mammal','cat'), 
    ('bird','penguin'),('fish','lax'),('mammal','whale'), 
    ('bird','ostrich'); 

SELECT * FROM animals ORDER BY grp,id; 

将返回:

+--------+----+---------+ 
| grp | id | name | 
+--------+----+---------+ 
| fish | 1 | lax  | 
| mammal | 1 | dog  | 
| mammal | 2 | cat  | 
| mammal | 3 | whale | 
| bird | 1 | penguin | 
| bird | 2 | ostrich | 
+--------+----+---------+ 

在这种情况下(当AUTO_INCREMENT列是多列索引的一部分),如果你删除AUTO_INCREMENT值重用任何组中具有最大AUTO_INCREMENT值的行。即使对于MyISAM表,这种情况也会发生,AUTO_INCREMENT值通常不会被重用。

如果AUTO_INCREMENT列是多个索引的一部分,MySQL将使用以AUTO_INCREMENT列开头的索引(如果有的话)生成序列值。例如,如果动物表包含索引PRIMARY KEY(grp,id)和INDEX(id),则MySQL将忽略用于生成序列值的PRIMARY KEY。结果,表格将包含一个单一序列,而不是每个grp值的序列。

正如您所看到的,您的主键和auto_increment设置已经正确。只需更改为MyISAM。


如果你不想使用MyISAM,你也可以在选择时进行计算。

SELECT 
ip.*, 
@row := IF(@prev_inv != invoice_id, 1, @row + 1) AS `row`, 
@prev_inv := invoice_id 
FROM invoice_products ip 
, (SELECT @row:=1, @prev_inv:=NULL) vars 
ORDER BY invoice_id 

第三种可能性当然是在数据库之外计算它。我会离开你:)

+0

谢谢!这是我正在寻找的。我唯一担心的是数据库中的所有其他表都是innodb,因为有可能使用外键约束。由于该解决方案似乎不适用于innodb,我可能会去通过PHP客户端手动插入行号。我将把它留给MySQL来检查invoice_id和row_id是否唯一 - > UNIQUE(invoice_id,row_id),以防止在一张发票上多次输入相同的行号。会给你一个投票,但没有代表:) – user2879867

-1

对于这种(由于大量使用外键约束),你不能使用一个AUTO_INCREMENT列。您应该在每次插入前查询实际发票的最大(行)+1。

+0

这不仅是性能上不理想的,还必须处理并发性问题。如果在检索最大(行)和插入之间还有另一个插入操作?另外,在数据库中根本不应该这样做。 – fancyPants

+0

在sql server中有这个表提示。我不知道这是否对mysql有帮助。但是在其他dbms中有一个非自动增量id是很常见的。 – Jonysuise

+0

不适用于MySQL ... – fancyPants

相关问题