Eviter les erreurs de conversion de données TSQL
-
03-07-2019 - |
Question
Je pense que le mieux est de poser cette question sous la forme d'un exemple simple. Le bloc SQL suivant provoque une " erreur DB-Library: 20049 Gravité: 4 Message: la conversion de données a entraîné un débordement du message "/ <; em>", mais comment se fait-il?
declare @a numeric(18,6), @b numeric(18,6), @c numeric(18,6)
select @a = 1.000000, @b = 1.000000, @c = 1.000000
select @a/(@b/@c)
go
En quoi est-ce différent de:
select 1.000000/(1.000000/1.000000)
go
qui fonctionne bien?
La solution
J'ai rencontré le même problème la dernière fois que j'ai essayé d'utiliser Sybase (il y a de nombreuses années). En raison de l'état d'esprit de SQL Server, je n'avais pas compris que Sybase tenterait de contraindre les décimales - ce qui, mathématiquement, est ce qu'il devrait faire. :)
Extrait du Manuel Sybase :
Des erreurs de débordement arithmétique se produisent lorsque le nouveau type a trop peu de décimales endroits pour accueillir les résultats.
Et plus bas:
Au cours des conversions implicites en numériques ou types décimaux, perte d'échelle génère une erreur d'échelle. Utilisez le Option arithabort numeric_truncation pour déterminer la gravité d'une telle erreur est considéré. Le réglage par défaut, arithabort numeric_truncation on, avorte la déclaration qui provoque la erreur, mais continue à traiter d'autres déclarations dans la transaction ou lot. Si vous définissez arithabort numeric_truncation off, adaptatif Le serveur tronque les résultats de la requête et poursuit le traitement.
Donc en supposant que la perte de précision est acceptable dans votre scénario , vous souhaitez probablement ce qui suit au début de votre transaction:
SET ARITHABORT NUMERIC_TRUNCATION OFF
Et ensuite à la fin de votre transaction:
SET ARITHABORT NUMERIC_TRUNCATION ON
C'est ce qui a résolu le problème pour moi il y a tant d'années ...
Autres conseils
Ceci n'est que spéculation, mais est-il possible que le SGBD ne considère pas la valeur dynamique de vos variables mais uniquement les valeurs potentielles? Ainsi, un nombre à six décimales divisé par un nombre à six décimales pourrait donner un nombre à douze décimales; dans la division littérale, le SGBD sait qu'il n'y a pas de dépassement de capacité. Vous ne savez toujours pas pourquoi le SGBD s’intéresserait, mais ne devrait-il pas renvoyer le résultat de deux divisions en six décimales avec un maximum de 18 décimales?
Comme vous avez déclaré les variables dans le premier exemple, le résultat devrait correspondre à la même déclaration (c'est-à-dire numérique (18,6)), mais ce n'est pas le cas.
Je dois dire que le premier fonctionnait bien dans SQL2005 (renvoyé 1.000000 [Le même type déclaré]), tandis que le second renvoyait (1.00000000000000000000000 [Une déclaration totalement différente]).
Pas directement lié, mais pourrait éventuellement faire gagner du temps aux erreurs de débordement arithmétique avec Sybase ASE (12.5.0.3).
Je définissais quelques valeurs par défaut dans une table temporaire que je souhaitais mettre à jour ultérieurement, et je suis tombé sur une erreur de débordement arithmétique.
declare @a numeric(6,3)
select 0.000 as thenumber into #test --indirect declare
select @a = ( select thenumber + 100 from #test )
update #test set thenumber = @a
select * from #test
Affiche l'erreur:
Arithmetic overflow during implicit conversion of NUMERIC value '100.000' to a NUMERIC field .
Ce qui dans ma tête devrait fonctionner, mais pas comme la colonne "thenumber" n'a pas été déclarée (ou indirectement comme décimale (4,3)). Vous devez donc déclarer indirectement la colonne de la table temporaire avec une échelle et une précision conformes au format souhaité, comme dans mon cas, 000 000.
select 000.000 as thenumber into #test --this solved it
Espérons que cela fera gagner un peu de temps à quelqu'un:)