web-dev-qa-db-fra.com

Valeur d'incrémentation MySQL

Existe-t-il un moyen de faire un incrément de valeur avec chaque insert si vous avez plusieurs insertions? (Je ne parle pas de la clé primaire qui incrémente automatiquement)

Disons que j'ai une structure comme celle-ci:

|ID_PRODUCT|ID_CATEGORY|NAME|POSITION|

J'ai donc des identifiants de produits individuels, chaque produit appartient à une catégorie et a une position différente dans cette catégorie. Je veux faire quelque chose comme ça:

INSERT INTO products
( SELECT id_product, id_category, name, MY_POSITION++
  FROM db2.products WHERE id_category = xxx )

Il devrait donc y avoir une variable MY_POSITION qui commence par 1 et incrémente chaque insertion.

Ce serait vraiment facile de faire tout cela simplement avec un langage de script comme php ou python, mais je veux m'améliorer avec SQL :)

29
user945967

Oui: utilisez une variable définie par l'utilisateur :

SET @position := 0; -- Define a variable
INSERT INTO products
SELECT id_product, id_category, name, (@position := @position + 1)
FROM db2.products
WHERE id_category = xxx;

Le résultat de l'incrémentation à @position est la valeur utilisée pour l'insertion.


Éditer:

Vous pouvez ignorer la déclaration de la variable en gérant la valeur initiale en ligne:

...
SELECT ..., (@position := ifnull(@position, 0) + 1)
...

Cela peut être particulièrement utile lors de l'exécution de la requête à l'aide d'un pilote qui n'autorise pas plusieurs commandes (séparées par des points-virgules).

64
Bohemian

Vous devrez ORDER BY id_category et utiliser deux variables utilisateur afin de pouvoir suivre l'id de la catégorie précédente -

SET @position := 0;
SET @prev_cat := 0;

INSERT INTO products
SELECT id_product, id_category, name, position
FROM (
    SELECT
        id_product,
        id_category,
        name,
        IF(@prev_cat = id_category, @position := @position + 1, @position := 1) AS position,
        @prev_cat := id_category
    FROM db2.products
    ORDER BY id_category ASC, id_product ASC
) AS tmp;

Cela vous permettra de faire toutes les catégories dans une seule requête au lieu de catégorie par catégorie.

5
nnichols

Simplement pour ajouter à la réponse @Bohemians - je voulais que le compteur se réinitialise de temps en temps et cela peut être fait comme ceci:

SELECT *,(@position := IF (@position >= 15,1,@position + 1))

Où 15 est évidemment le nombre maximum avant réinitialisation.

3
Antony

Essayez de définir une valeur à l'aide d'une sous-requête comme celle-ci

 (SELECT MAX(position) FROM products AS T2)+1

Ou

(SELECT MAX(position) FROM products AS T2 WHERE id_category = 'product category')+1
2
Oriesok Vlassky