Un problème de fonctionnement étrange dans SQL Server: -100 / -100 * 10 = 0

106
  • Si vous exécutez SELECT -100/-100*10le résultat est 0.
  • Si vous exécutez SELECT (-100/-100)*10le résultat est 10.
  • Si vous exécutez SELECT -100/(-100*10)le résultat est 0.
  • Si vous exécutez SELECT 100/100*10le résultat est 10.

BOL déclare:

Lorsque deux opérateurs dans une expression ont le même niveau de priorité d'opérateur, ils sont évalués de gauche à droite en fonction de leur position dans l'expression.

Et

Level   Operators
  1     ~ (Bitwise NOT)
  2     * (Multiplication), / (Division), % (Modulus)
  3     + (Positive), - (Negative), + (Addition), + (Concatenation), - (Subtraction), & (Bitwise AND), ^ (Bitwise Exclusive OR), | (Bitwise OR)

Est-ce que BOL a tort ou est-ce que je manque quelque chose? Il semble que cela -jette la préséance (attendue).

cuizizhe
la source
7
Quelle est votre question?
Ilyes
14
Pourquoi pensez-vous que vous avez à faire avec des bits, vous travaillez avec des entiers. Et entier / entier = entier. Donc -100 / -1000 est 0
sepupic
5
OK, je suis d'accord, cela -semble provoquer un «mauvais» flux. Si vous essayez, -100/(-100)*10vous obtenez le résultat 10. il semble que le /soit appliqué à la valeur -de l'équation, puis l'équation 100*10est en cours de détermination. Je ne suis pas sûr que ce soit une erreur avec BOL, mais plus que SQL Server ne se comporte pas comme prévu. Cela pourrait valoir la peine de soulever un problème sur sql-docs et de voir quelle est leur réponse; peut-être qu'une note pourrait être ajoutée à la documentation informant de la "fonctionnalité".
Larnu
3
SELECT -100/(-100)*10renvoie également 10. On dirait qu'il -est traité comme l' -opérateur qui ne devrait être appliqué qu'après le 100*10calcul
Panagiotis Kanavos
7
A / -B * Cest A <div> <negate> B <multiply> C. Negate a une priorité inférieure à multiplier, selon la documentation, le résultat est donc A / -(B * C). Vous pouvez le voir plus clairement en utilisant des constantes flottantes: 12e / -13e * 14evs 12e / (-13e) * 14evs. 12e / 13e * 14eLa raison pour laquelle cela nous dérange est que nous nous attendons généralement à ce que le moins unaire fasse partie du littéral, ou du moins ait une priorité très élevée, mais ce n'est pas ainsi que T-SQL travaux.
Jeroen Mostert le

Réponses:

96

Selon la table de priorité, il s'agit du comportement attendu. L'opérateur avec une priorité plus élevée ( /et *) est évalué avant l'opérateur avec une priorité inférieure (unaire -). Donc ça:

-100 / -100 * 10

est évalué comme:

-(100 / -(100 * 10))

Notez que ce comportement est différent de la plupart des langages de programmation où la négation unaire a une priorité plus élevée que la multiplication et la division, par exemple VB , JavaScript .

Salman A
la source
38
Wow, une autre fonctionnalité de gemme dans T-SQL :) Je suppose que je dois vérifier tout mon code maintenant pour rechercher des bogues.
usr
14
oh mec. C'est encore pire que les différents bogues de l'opérateur ternaire PHP bugs.php.net/bug.php?id=61915 . Quelles personnes sensées pensent que les opérateurs unaires doivent avoir une priorité inférieure aux opérateurs binaires?
phuclv
12
La vraie différence peut être de savoir si -est considéré comme un opérateur dans -100. Dans certaines langues, cela fait partie de la syntaxe d'un entier.
Barmar le
7
C'est donc un bogue dans leur préséance d'unaire -.
Kevin le
4
Et le gagnant de la conception contre-intuitive est ...: Microsoft - encore une fois
rexkogitans
34

BOL est correct. -a une priorité inférieure à *, donc

-A * B

est analysé comme

-(A * B)

La multiplication étant ce qu'elle est, vous ne le remarquez généralement pas, sauf lorsque vous mélangez les deux autres opérateurs binaires avec une priorité égale: /et %(et %est rarement utilisé dans des expressions composées comme celle-ci). Alors

C / -A * B

Est analysé comme

C / -(A * B)

expliquer les résultats. Ceci est contre-intuitif car dans la plupart des autres langages, le moins unaire a une priorité plus élevée que *et /, mais pas dans T-SQL, et cela est documenté correctement.

Une belle (?) Façon de l'illustrer:

SELECT -1073741824 * 2

produit un débordement arithmétique, car -(1073741824 * 2)produit 2147483648comme intermédiaire, qui ne rentre pas dans un INT, mais

SELECT (-1073741824) * 2

produit le résultat attendu -2147483648, ce qui fait.

Jeroen Mostert
la source
"moins" est binaire. Unaire -est "négatif". Les gens qui disent des choses comme «moins 10» alors qu'ils veulent dire «moins 10» sont imprécis.
Accumulation le
11
@Acccumulation: l'imprécision n'est pas la mienne. L' -opérateur, lorsqu'il est appliqué à un seul opérande, est appelé MINUSdans les plans de requête SQL. Son équivalent binaire est appelé SUB. Si vous le souhaitez, interprétez «moins unaire» comme un raccourci pour «l'opérateur unaire signifié par le signe moins» - une désignation syntaxique plutôt que sémantique.
Jeroen Mostert
3
"négatif 10" est l'usage américain standard (je crois) mais ce n'est pas standard au Royaume-Uni.
Alchymist
12

Remarquez dans la documentation que (peut-être contre-intuitivement) l'ordre de priorité pour - (Negative)est troisième.

Ainsi, vous obtenez effectivement:

-(100/-(100*10)) = 0

Si vous les placez dans des variables, vous ne verrez pas cela se produire, car il n'y a pas d'opération unaire qui se produit après la multiplication.

Donc, ici A et B sont les mêmes, tandis que C, D, E montrent le résultat que vous voyez (avec E ayant le bracketing complet)

DECLARE @i1 int, @i2 int, @i3 int;

SELECT @i1 = -100,
       @i2 = -100,
       @i3 = 10;

SELECT @i1/@i2*@i3      [A],
       -100/(-100)*10   [B],
       -100/-100*10     [C],
       -100/-(100*10)   [D],
       -(100/-(100*10)) [E];

A - 10
B - 10
C - 0
D - 0
E - 0
Jamie Pollard
la source