J'ai une table appelée INVOICES qui reçoit des entrées d'un script PHP. Il comporte de nombreuses colonnes, mais les deux plus pertinentes sont INVOICE_ID et INVOICE_TYPE. Fondamentalement, le INVOICE_TYPE est un nombre compris entre 0 et 3 , qui désigne différents types de factures.

Jusque-là, tout s'est bien déroulé jusqu'à ce que deux utilisateurs soumettent des factures alors que le serveur a eu un hoquet et écrivent les deux comme étant identiques INVOICE_ID. La raison en est que le script PHP lit le MAX INVOICE_ID du INVOICE_TYPE, puis ajoute 1 , puis insère la nouvelle ligne avec ce INVOICE_ID. En substance, il s'agit d'un primary key par programmation. 99,9% du temps, cela a fonctionné, mais cette fois-là, c'était un problème.

J'ai essayé de trouver des solutions SQL mais je n'en ai pas une connaissance suffisante. J'ai essayé de le faire moi-même dans une requête SQL pour lire le MAX, l'incrémentation et l'insertion, mais lève simplement une exception que vous ne pouvez pas sélectionner et insérer à partir de la même table à la fois.

Ce que je me demande, c'est s'il existe une auto-incrémentation qui pourrait être conditionnelle au INVOICE_TYPE, à incrémenter uniquement si le type correspond. Toute suggestion serait utile à ce stade.

0
Lawrence 8 mai 2020 à 17:09

4 réponses

Un index unique sur les deux colonnes (INVOICE_ID, INVOICE_TYPE) fera échouer l'une de ces requêtes hiccupy.

CREATE UNIQUE INDEX id_type_unique ON INVOICES (INVOICE_ID, INVOICE_TYPE);
INSERT INTO INVOICES (INVOICE_ID, INVOICE_TYPE) VALUES (1, 5);  -- okay
INSERT INTO INVOICES (INVOICE_ID, INVOICE_TYPE) VALUES (1, 5);  -- error
2
AKX 8 mai 2020 à 14:21

La façon dont je l'aime est de créer une table pour gérer toutes les séquences et une procédure stockée que je peux appeler avec le nom de la séquence que j'aime connaître la valeur suivante, quelque chose de similaire à:

COMMENCER LA TRANSACTION;

SELECT valeur INTO result FROM Sequences WHERE nom comme paramSeqName FOR UPDATE;

UPDATE Sequences SET valeur = valeur + 1 WHERE nom comme paramSeqName;

Il y a un bon exemple ici: http: //www.microshell .com / database / mysql / émuler-fonction-nextval-pour-obtenir-séquence-dans-mysql /

0
vuzz 8 mai 2020 à 14:41

Si vous insérez une seule ligne dans une table à la fois, la solution la plus simple consiste à appliquer un index unique sur les deux colonnes.

CREATE UNIQUE INDEX invoice_id_type_unique
ON INVOICES(INVOICE_ID,INVOICE_TYPE);

Mais si vous exécutez plus de requêtes basées sur les mêmes données, vous devez utiliser des transactions pour éviter de modifier / insérer seulement une partie des données.

START TRANSACTION;
SELECT @invoice_id:=MAX(INVOICE_ID) FROM INVOICES WHERE INVOICE_TYPE=1;
INSERT INTO INVOICES (...,@invoice_id,...);
...
... #OTHER QUERIES UPDATING DATA
COMMIT;
0
Tajniak 8 mai 2020 à 15:03

Faites (INVOICE_ID) comme UNIQUE, cela résoudra votre problème, sql ne permettra pas de dupliquer la valeur dans la même colonne.

0
Pushpendra Kumar 8 mai 2020 à 14:23