J'ai une séquence Oracle définie comme suit:
CREATE SEQUENCE "DALLAS"."X_SEQ"
MINVALUE 0
MAXVALUE 999999999999999999999999999
INCREMENT BY 1 START WITH 0 NOCACHE NOORDER NOCYCLE ;
Il est utilisé dans une procédure stockée pour insérer un enregistrement:
PROCEDURE Insert_Record
(p_name IN VARCHAR2,
p_userid IN INTEGER,
cur_out OUT TYPES_PKG.RefCursor)
IS
v_id NUMBER := 0;
BEGIN
-- Get id value from sequence
SELECT x_seq.nextval
INTO v_id
FROM dual;
-- Line below is X_PKG line 40
INSERT INTO X
(the_id,
name,
update_userid)
VALUES
(v_id,
p_name,
p_userid);
-- Return new id
OPEN cur_out FOR
SELECT v_id the_id
FROM dual;
END;
Parfois, cette procédure renvoie une erreur lorsqu'elle est exécutée à partir du code d'application.
ORA-01400: cannot insert NULL into ("DALLAS"."X"."THE_ID")
ORA-06512: at "DALLAS.X_PKG", line 40
ORA-06512: at line 1
Détails qui peuvent ou non être pertinents:
- Oracle Database 11g Enterprise Edition version 11.2.0.1.0 - Production 64 bits
- La procédure est exécutée via Microsoft.Practices.EnterpriseLibrary - Data.Oracle.OracleDatabase.ExecuteReader (commande DbCommand)
- L'application n'encapsule pas l'appel dans une transaction explicite.
- L'insert échoue par intermittence - moins de 1%
Dans quelles circonstances pourrait x_seq.nextval
être nul?
v_id
n'est référencé que dans la sélection de séquence, l'insertion et le curseur final. Notre prochaine étape a été d'ajouter le code de débogage. Nous devrons peut-être attendre les résultats car cela n'arrive qu'en production et très rarement. Il existe un déclencheur qui s'insère dans une table d'audit. Je l'ai passé au peigne fin sans pistolet fumant. Le problème se produit également occasionnellement dans d'autres tables sans déclencheurs. Merci d'avoir regardé.Réponses:
Je suis presque certain que cela finira par être un artefact de votre code ou du pilote .net que vous utilisez. J'ai créé une démo rapide pour vous en utilisant du SQL pur - PL / SQL et je n'ai jamais obtenu de valeur de séquence perdue. Soit dit en passant, le curseur de référence que vous utilisez est probablement inutile et a probablement un impact sur les performances et la lisibilité du code - ma démo comprend une procédure insert_record2 qui effectue régulièrement plus de 10% plus rapidement - en environ 26 secondes sur mon ordinateur portable contre 36 pour la version du curseur de référence. Je pense au moins aussi que c'est plus facile à comprendre. Vous pouvez évidemment exécuter une version modifiée sur votre base de données de test avec déclencheur d'audit.
la source
:new.the_id
est intact. Je comprends que ma question est longue. Il est résistant à mon google-fu et plusieurs personnes se grattent la tête ici. J'ai juste pensé que quelqu'un pourrait reconnaître le symptôme (et le traitement) avec suffisamment de globes oculaires. Merci d'avoir regardé.Essayez de faire un cas de test. Créez une table fictive et insérez 100 000 enregistrements à l'aide de votre séquence dans la base de données. Je parie que vous n'aurez aucun problème. Essayez ensuite d'insérer la même chose à partir de votre application.
Cela peut-il être dû à d'autres problèmes tels qu'une non-concordance de client Oracle?
Une autre solution qui résoudrait le problème mais pas le problème consiste à ajouter un déclencheur sur la table.
Avant d'insérer sur la table sur Dallas.X SI: the_id est null THEN SELECT x_seq.nextval INTO: the_id FROM dual; FIN SI;
la source
Je n'ai pas encore de privilèges pour faire des commentaires, alors écrivez ceci comme une réponse: puisque vous utilisez la version Oracle> = 11.1, qui autorise les séquences dans les expressions PL / SQL au lieu de SQL, essayez ceci:
Au lieu de cela:
Ou, bien que j'aie entendu des doutes / pièges lors de l'utilisation de ".currval", peut-être omettre l'affectation séparée de v_id et utiliser uniquement ce code?:
Désolé, je n'ai pas d'instance 11g à portée de main pour l'essayer.
la source
select into...
autant en 11 qu'en 9i et 10g. Le seul avantage de 11+ est de pouvoir le référencer explicitement comme vous l'avez souligné.