我准备编写几个MySQL表来处理发票。
我的计划是将其分为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(因为大量使用外键约束)
答案 0 :(得分:0)
您所要做的就是将您的桌子更改为使用MyISAM引擎。但请注意,MyISAM不支持事务和外键。
无论如何,这是一个如何工作的例子(引用manual):
对于MyISAM和BDB表,您可以在多列索引的辅助列上指定AUTO_INCREMENT。在这种情况下,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列开头的索引生成序列值(如果有)。例如,如果animals表包含索引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
第三种可能性当然是在数据库外计算它。我会留给你:)。
答案 1 :(得分:-1)
为此您无法使用auto_increment列。在每次插入之前,您应该查询实际发票的最大值(行)+ 1。