web-dev-qa-db-fra.com

Equivalent MySQL de SEQUENCE.NEXTVAL d'Oracle

J'ai besoin de pouvoir générer une requête qui renverra la prochaine valeur d'ID dans le tableau suivant:

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

Dans Oracle, vous pouvez appeler NEXTVAL sur une séquence et cela vous donne la séquence suivante (remarque: sans avoir à insérer d'insertion dans la table). 

Après avoir cherché sur Google, j'ai découvert que vous pouvez trouver la valeur actuelle de auto_increment à l'aide de la requête suivante:

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

Le problème est que je voudrais que la valeur soit incrémentée chaque fois que la valeur est interrogée. Dans Oracle, lorsque vous appelez nextval, la valeur de la séquence est incrémentée même si vous n'insérez pas de ligne dans une table. 

Est-il possible de modifier la requête ci-dessus de sorte que la valeur renvoyée soit toujours différente de la dernière fois où la requête a été appelée? Autrement dit, Auto_increment est incrémenté chaque fois qu'il est vérifié et utilisé dans une requête, il utilise une nouvelle valeur. 

J'utilise Spring JDBCTemplate, donc mieux vaut le faire en une requête. 

12
ziggy

Cet exemple avec InnoDB illustre un moyen d'implémenter votre propre compteur en utilisant des requêtes verrouillées:

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

De quoi avez-vous besoin pour créer un fossé? Pour réserver des identifiants? .__ Je préférerais "arranger" à tout prix la conception et mettre à jour les autres modules au lieu de toucher une séquence.

Au lieu de simplement incrémenter explicitement la séquence, je l'impliquerais en insérant une ligne par défaut (marquée non valide) pour chaque identifiant à allouer et à renvoyer l'identifiant. Cette approche est cohérente et portable. Plus tard, au lieu de forcer les insertions en utilisant une valeur de séquence explicite, vous pouvez mettre à jour ces lignes par défaut en utilisant leurs valeurs de séquence correspondantes . Le ramassage des ordures sur les lignes expirées peut aider ici. Les instructions 'insert or update' peuvent recréer des lignes vides, mais je ne le ferais pas.

5
Sam

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

3.6.9. Utilisation de AUTO_INCREMENT

L'attribut AUTO_INCREMENT peut être utilisé pour générer une identité unique pour les nouvelles lignes:

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 |
+----+---------+

Aucune valeur n'ayant été spécifiée pour la colonne AUTO_INCREMENT, MySQL a attribué automatiquement les numéros de séquence. Vous pouvez également attribuer explicitement NULL ou 0 à la colonne pour générer des numéros de séquence.

Vous pouvez récupérer la valeur AUTO_INCREMENT la plus récente à l'aide de la fonction SQL LAST_INSERT_ID () ou de la fonction API C mysql_insert_id (). Ces fonctions étant spécifiques à la connexion, leurs valeurs de retour ne sont pas affectées par une autre connexion qui effectue également des insertions.

Utilisez le type de données entier le plus petit pour la colonne AUTO_INCREMENT, suffisamment grand pour contenir la valeur de séquence maximale requise. Lorsque la colonne atteint la limite supérieure du type de données, la prochaine tentative de génération d'un numéro de séquence échoue. Utilisez si possible l'attribut UNSIGNED pour permettre une plus grande plage. Par exemple, si vous utilisez TINYINT, le numéro de séquence maximal autorisé est 127. Pour TINYINT UNSIGNED, le nombre maximal est 255. Reportez-vous à la Section 11.2.1, «Types d’entiers (valeur exacte) - INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT ”Pour les plages de tous les types entiers.

Note Pour une insertion de plusieurs lignes, LAST_INSERT_ID () et mysql_insert_id () renvoient en fait la clé AUTO_INCREMENT à partir de la première des lignes insérées. Cela permet de reproduire correctement les insertions à plusieurs lignes sur d'autres serveurs dans une configuration de réplication.

Si la colonne AUTO_INCREMENT fait partie de plusieurs index, MySQL génère des valeurs de séquence en utilisant l'index qui commence par la colonne AUTO_INCREMENT, le cas échéant. Par exemple, si la table des animaux contient les index PRIMARY KEY (grp, id) et INDEX (id), MySQL ignore la clé PRIMARY KEY pour la génération de valeurs de séquence. En conséquence, la table contiendrait une seule séquence, pas une séquence par valeur de grp.

Pour commencer avec une valeur AUTO_INCREMENT différente de 1, définissez cette valeur avec CREATE TABLE ou ALTER TABLE, comme suit:

mysql> ALTER TABLE tbl AUTO_INCREMENT = 100; InnoDB Notes

Pour les tables InnoDB, faites attention si vous modifiez la colonne contenant la valeur d'incrémentation automatique au milieu d'une séquence d'instructions INSERT. Par exemple, si vous utilisez une instruction UPDATE pour définir une nouvelle valeur plus grande dans la colonne d'auto-incrémentation, une instruction INSERT ultérieure peut rencontrer une erreur «Entrée en double». Le test indiquant si une valeur d'auto-incrémentation est déjà présente est exécuté si vous effectuez une opération DELETE suivie de plusieurs instructions INSERT ou lorsque vous COMMITZ la transaction, mais pas après une instruction UPDATE.

Notes MyISAM

Pour les tables MyISAM, vous pouvez spécifier AUTO_INCREMENT sur une colonne secondaire dans un index à plusieurs colonnes. Dans ce cas, la valeur générée pour la colonne AUTO_INCREMENT est calculée sous la forme MAX (auto_increment_column) + 1 préfixe WHERE = préfixe-donné. Ceci est utile lorsque vous souhaitez placer des données dans des groupes ordonnés.

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 |
+--------+----+---------+

Dans ce cas (lorsque la colonne AUTO_INCREMENT fait partie d'un index à plusieurs colonnes), les valeurs AUTO_INCREMENT sont réutilisées si vous supprimez la ligne avec la plus grande valeur AUTO_INCREMENT dans un groupe. Cela se produit même pour les tables MyISAM, pour lesquelles les valeurs AUTO_INCREMENT ne sont normalement pas réutilisées.

Lectures complémentaires

Plus d'informations sur AUTO_INCREMENT est disponible ici:

Comment affecter l'attribut AUTO_INCREMENT à une colonne: Section 13.1.17, «Syntaxe CREATE TABLE» et Section 13.1.7, «Syntaxe ALTER TABLE».

Comment AUTO_INCREMENT se comporte en fonction du mode SQL NO_AUTO_VALUE_ON_ZERO: Section 5.1.7, «Modes SQL du serveur».

Comment utiliser la fonction LAST_INSERT_ID () pour rechercher la ligne contenant la valeur AUTO_INCREMENT la plus récente: Section 12.14, «Fonctions d’information».

Définition de la valeur AUTO_INCREMENT à utiliser: Section 5.1.4, «Variables système du serveur».

AUTO_INCREMENT et réplication: Section 16.4.1.1, «Réplication et AUTO_INCREMENT».

Variables système serveur liées à AUTO_INCREMENT (auto_increment_increment et auto_increment_offset) pouvant être utilisées pour la réplication: Section 5.1.4, «Variables système du serveur».

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

11
Ivan M.

Vous pouvez ajouter votre propre fonction MySQL - comme indiqué à http://www.microshell.com/database/mysql/emulating-nextval-function-to-get-sequence-in-mysql/ - vous permettant de le faire quelque chose comme ça:

SELECT nextval('sq_my_sequence') as next_sequence;
4
ziesemer

MySQL utilise AUTO_INCREMENT qui sert les objectifs. Mais il existe des différences ci-dessous:

MySQL AUTO_INCREMENT à Oracle SEQUENCE Différences

  • AUTO_INCREMENT est limité à une colonne par table
  • AUTO_INCREMENT doit être assigné à une table.column spécifique (n'autorisant pas l'utilisation de plusieurs tables)
  • AUTO_INCREMENT est INSERT sous la forme d'une colonne non spécifiée ou d'une valeur NULL

si vous souhaitez voir une implémentation de SEQUENCE avec MySQL, vous pouvez le faire avec SP.

Le lien ci-dessous explique tout ce que vous voulez.

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

2
user319198

Vous voulez que la prochaine valeur de THIS table vous permette de créer des lignes qui ne sont pas encore insérées sans perturber les autres processus utilisant l'incrémentation automatique?

Quelques options:

Allez-y et insérez simplement les lignes pour "utiliser la séquence", marquez-les comme étant en attente, puis mettez-les à jour ultérieurement.

Insérez dans une transaction et annulez-la - la séquence de numérotation automatique doit s'épuiser et créer normalement un "espace" dans le tableau - ce numéro est désormais libre d'utilisation.

Avec Oracle, la séquence est complètement indépendante de la table, les processus peuvent donc utiliser la séquence ou non (et ils peuvent également utiliser la même séquence pour différentes tables). Dans cet ordre d'idées, vous pouvez implémenter une table contenant uniquement une séquence à laquelle vous accédez via une sorte de fonction. Pour les autres processus qui doivent s'appuyer sur l'incrémentation automatique, supprimez l'incrémentation automatique et utilisez un déclencheur affectant le même processus. fonction de séquence si aucun identifiant n'est fourni.

1
Cade Roux
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;
0
Sumit

Jetez un coup d'œil à MariaDBs SEQUENCE Engine. Avec elle, vous pouvez générer des séquences aussi faciles que

SELECT seq FROM seq_1_to_5;
+-----+
| seq |
+-----+
|   1 |
|   2 |
|   3 |
|   4 |
|   5 |
+-----+

Détails ici: https://mariadb.com/kb/en/mariadb/sequence/

Avec cela, vous devriez pouvoir faire quelque chose comme

SELECT min(seq) as nextVal FROM seq_1_to_500 
WHERE seq NOT IN (SELECT ID FROM customers)
0
Benvorth