MySQL相当于Oracle的SEQUENCE.NEXTVAL

时间:2012-01-28 16:48:14

标签: mysql sql database oracle spring

我需要能够生成运行查询,该查询将返回下表中的下一个ID值:

CREATE TABLE animals (
     id MEDIUMINT NOT NULL AUTO_INCREMENT,
     name CHAR(30) NOT NULL,
     PRIMARY KEY (id)
)

在Oracle中,您可以在序列上调用NEXTVAL,它会为您提供下一个序列(注意:无需在表格上插入)。

在Google上搜索后,我发现您可以使用以下查询找到auto_increment的当前值:

SELECT Auto_increment 
FROM information_schema.tables 
WHERE table_name='animals';

问题是我想在每次查询值时增加值。在Oracle中,当您调用nextval时,即使您没有在表中插入行,序列的值也会增加。

有什么方法可以修改上面的查询,以便返回的值总是与上次调用查询时不同?即,每次检查时Auto_increment都会递增,当在查询中使用时,它将使用新值。

我正在使用Spring JDBCTemplate,所以如果可以在一个查询中完成,那就更好了。

7 个答案:

答案 0 :(得分:12)

http://docs.oracle.com/cd/E17952_01/refman-5.5-en/example-auto-increment.html

<强> 3.6.9。使用AUTO_INCREMENT

AUTO_INCREMENT属性可用于为新行生成唯一标识:

CREATE TABLE animals (
     id MEDIUMINT NOT NULL AUTO_INCREMENT,
     name CHAR(30) NOT NULL,
     PRIMARY KEY (id)
);

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

SELECT * FROM animals;
Which returns:

+----+---------+
| id | name    |
+----+---------+
|  1 | dog     |
|  2 | cat     |
|  3 | penguin |
|  4 | lax     |
|  5 | whale   |
|  6 | ostrich |
+----+---------+

没有为AUTO_INCREMENT列指定值,因此MySQL会自动分配序列号。您还可以显式为列分配NULL或0以生成序列号。

您可以使用LAST_INSERT_ID()SQL函数或mysql_insert_id()C API函数检索最新的AUTO_INCREMENT值。这些函数是特定于连接的,因此它们的返回值不受另一个同时执行插入的连接的影响。

使用AUTO_INCREMENT列的最小整数数据类型,该列足够大以容纳您需要的最大序列值。当列达到数据类型的上限时,下一次生成序列号的尝试将失败。如果可能,请使用UNSIGNED属性以允许更大的范围。例如,如果使用TINYINT,则允许的最大序列号为127.对于TINYINT UNSIGNED,最大值为255.请参见第11.2.1节“整数类型(精确值) - INTEGER,INT,SMALLINT,TINYINT,MEDIUMINT,BIGINT “对于所有整数类型的范围。

请注意 对于多行插入,LAST_INSERT_ID()和mysql_insert_id()实际上从第一个插入的行返回AUTO_INCREMENT键。这样可以在复制设置中的其他服务器上正确地再现多行插入。

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

要以除1以外的AUTO_INCREMENT值开始,请使用CREATE TABLE或ALTER TABLE设置该值,如下所示:

的MySQL&GT; ALTER TABLE tbl AUTO_INCREMENT = 100; InnoDB备注

对于InnoDB表,如果在INSERT语句序列的中间修改包含自动增量值的列,请务必小心。例如,如果使用UPDATE语句在自动增量列中放入一个新的较大值,则后续INSERT可能会遇到“重复条目”错误。如果执行DELETE后跟更多INSERT语句,或者执行COMMIT事务,而不是在UPDATE语句之后,则测试是否已存在自动增量值。

MyISAM备注

对于MyISAM表,您可以在多列索引中的辅助列上指定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;
Which returns:

+--------+----+---------+
| 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的更多信息,请点击此处:

如何将AUTO_INCREMENT属性分配给列:第13.1.17节“CREATE TABLE语法”和第13.1.7节“ALTER TABLE语法”。

AUTO_INCREMENT的行为取决于NO_AUTO_VALUE_ON_ZERO SQL模式:第5.1.7节“服务器SQL模式”。

如何使用LAST_INSERT_ID()函数查找包含最新AUTO_INCREMENT值的行:第12.14节“信息函数”。

设置要使用的AUTO_INCREMENT值:第5.1.4节“服务器系统变量”。

AUTO_INCREMENT和复制:第16.4.1.1节“复制和AUTO_INCREMENT”。

与可用于复制的AUTO_INCREMENT(auto_increment_increment和auto_increment_offset)相关的服务器系统变量:第5.1.4节“服务器系统变量”。

http://search.oracle.com/search/search?q=auto_increment&group=Documentation&x=0&y=0

答案 1 :(得分:6)

使用InnoDB的这个示例演示了使用互锁查询实现自己的计数器的方法:

http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

你需要为什么创造差距?要保留ID? 我宁愿“不惜一切代价”修复设计并更新其他模块而不是触及序列。

我不是只显式递增序列,而是通过为每个id插入一个默认行(标记为无效)来分配并返回id。这种方法是一致和便携的。 稍后,您可以使用匹配的序列值更新这些默认行,而不是使用显式序列值强制插入。 这需要更多内存但没有锁。过期行上的垃圾收集可以在这里提供帮助。 “插入或更新”语句可以重新创建垃圾收集行,但我不会这样做。

答案 2 :(得分:4)

您可以添加自己的MySQL功能 - 如http://www.microshell.com/database/mysql/emulating-nextval-function-to-get-sequence-in-mysql/所示 - 允许您执行以下操作:

SELECT nextval('sq_my_sequence') as next_sequence;

答案 3 :(得分:2)

MySQL使用AUTO_INCREMENT来实现此目的。但是有以下差异:

MySQL AUTO_INCREMENT到Oracle SEQUENCE差异

  • AUTO_INCREMENT限制为每个表一列
  • 必须将AUTO_INCREMENT分配给特定的table.column(不允许多表使用)
  • AUTO_INCREMENT被INSERTed作为未指定的列,或值为NULL

如果您希望看到使用MySQL的SEQUENCE实现,可以使用SP。

请参阅以下链接,说明您想要的一切。

http://ronaldbradford.com/blog/sequences-in-mysql-2006-01-26/

答案 4 :(得分:1)

您想要THAT表上的下一个值,以便您可以创建尚未插入的行而不会干扰使用自动增量的其他进程吗?

一些选项:

继续,只需插入行“用完序列”,将它们标记为待定,然后再更新。

在事务中插入并中止事务 - 自动编号序列应该用完并正常在表格中形成“间隙” - 现在可以免费使用该编号。

使用Oracle,序列完全独立于表,因此进程可以使用或不使用序列(并且它们也可以对不同的表使用相同的序列)。在这种情况下,您可以实现一个仅通过某种函数访问的仅序列表,对于需要依赖自动递增的其他进程,删除自动增量并使用从该命令分配的触发器如果没有提供id,则为sequence函数。

答案 5 :(得分:0)

查看MariaDBs SEQUENCE引擎。有了它,你可以像

一样简单地生成序列
SELECT seq FROM seq_1_to_5;
+-----+
| seq |
+-----+
|   1 |
|   2 |
|   3 |
|   4 |
|   5 |
+-----+

详情here: https://mariadb.com/kb/en/mariadb/sequence/

有了这个,你应该可以做类似

的事情
SELECT min(seq) as nextVal FROM seq_1_to_500 
WHERE seq NOT IN (SELECT ID FROM customers)

答案 6 :(得分:0)

1.) create table query
2.) Insert query
3.) Update query
4.) Select query for that table e.g. SELECT next_val FROM hib_sequence;
5.) Before each select update first, like this you can achieve similar

-- CREATE TABLE hib_sequence (next_val INT NOT NULL);
-- UPDATE hib_sequence SET next_val=LAST_INSERT_ID(next_val+1);
-- select last_insert_id();
-- INSERT INTO hib_sequence VALUES (0);

-- select next_val from hib_sequence;