Uno strano problema di funzionamento in SQL Server: -100 / -100 * 10 = 0


106
  • Se esegui SELECT -100/-100*10il risultato è 0.
  • Se esegui SELECT (-100/-100)*10il risultato è 10.
  • Se esegui SELECT -100/(-100*10)il risultato è 0.
  • Se esegui SELECT 100/100*10il risultato è 10.

BOL afferma:

Quando due operatori in un'espressione hanno lo stesso livello di precedenza degli operatori, vengono valutati da sinistra a destra in base alla loro posizione nell'espressione.

E

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

BOL ha torto o mi sto perdendo qualcosa? Sembra che -stia eliminando la (attesa) precedenza.


7
Qual'è la tua domanda?
Ilyes

14
Perché pensi di avere a che fare con i bit, stai lavorando con i numeri interi. E intero / intero = intero. Quindi -100 / -1000 è 0
sepupico

5
OK, sono d'accordo, -sembra che questo stia facendo andare "storto" il flusso. Se ci provi -100/(-100)*10ottieni il risultato 10. sembra che /si stia applicando il contro al valore -nell'equazione e poi l'equazione 100*10venga determinata. Non sono sicuro che questo sia un errore con BOL, ma soprattutto SQL Server non si comporta come previsto. Potrebbe valere la pena sollevare un problema su sql-docs e vedere quale sia la loro risposta; forse una nota potrebbe essere aggiunta alla documentazione che consiglia la "funzionalità".
Larnu

3
SELECT -100/(-100)*10restituisce anche 10. Sembra che -sia trattato come l' -operatore che dovrebbe essere applicato solo dopo 100*10essere stato calcolato
Panagiotis Kanavos

7
A / -B * Cè A <div> <negate> B <multiply> C. Negate ha una precedenza inferiore rispetto a moltiplicare, per i documenti, quindi il risultato è A / -(B * C). Puoi vederlo più chiaramente usando costanti fluttuanti: 12e / -13e * 14evs 12e / (-13e) * 14evs. 12e / 13e * 14eIl motivo per cui questo ci sconcerta è perché generalmente ci aspettiamo che il meno unario diventi parte del letterale, o almeno abbia una precedenza molto alta, ma non è così che T-SQL lavori.
Jeroen Mostert

Risposte:


96

Secondo la tabella delle precedenza, questo è il comportamento previsto. L'operatore con precedenza maggiore ( /e *) viene valutato prima dell'operatore con precedenza inferiore (unario -). Così questo:

-100 / -100 * 10

è valutato come:

-(100 / -(100 * 10))

Si noti che questo comportamento è diverso dalla maggior parte dei linguaggi di programmazione in cui la negazione unaria ha una precedenza maggiore rispetto alla moltiplicazione e alla divisione, ad esempio VB , JavaScript .


38
Wow, un'altra caratteristica gemma in T-SQL :) Suppongo di dover controllare tutto il mio codice ora per cercare bug.
usr

14
Oddio. Questo è anche peggio dei vari bug dell'operatore ternario PHP bugs.php.net/bug.php?id=61915 . Quali persone sane pensano che gli operatori unari debbano avere una precedenza inferiore rispetto a quelli binari?
phuclv

12
La vera differenza potrebbe essere se -è considerato un operatore in -100. In alcune lingue fa parte della sintassi di un numero intero.
Barmar

7
Quindi è un bug nella loro precedenza di unario -.
Kevin il

4
E il vincitore del design contro-intuitivo è ...: Microsoft - ancora una volta
rexkogitans

34

BOL ha ragione. -ha una precedenza inferiore a *, quindi

-A * B

viene analizzato come

-(A * B)

Essendo la moltiplicazione quello che è, in genere non lo noti, tranne quando mescoli gli altri due operatori binari con uguale precedenza: /e %(ed %è usato raramente in espressioni composte come questa). Così

C / -A * B

Viene analizzato come

C / -(A * B)

spiegare i risultati. Questo è controintuitivo perché nella maggior parte degli altri linguaggi il segno meno unario ha una precedenza maggiore di *e /, ma non in T-SQL, e questo è documentato correttamente.

Un modo carino (?) Per illustrarlo:

SELECT -1073741824 * 2

produce un overflow aritmetico, perché -(1073741824 * 2)produce 2147483648come intermedio, che non si adatta a un INT, ma

SELECT (-1073741824) * 2

produce il risultato atteso -2147483648, che fa.


"meno" è binario. Unario -è "negativo". Le persone che dicono cose come "meno 10" quando intendono "negativo 10" sono imprecise.
Accumulo

11
@Acccumulation: l'imprecisione non è mia. L' -operatore, quando applicato a un singolo operando, viene chiamato MINUSnei piani di query SQL. Viene chiamata la sua controparte binaria SUB. Se ti piace, interpreta "meno unario" come abbreviazione per "l'operatore unario indicato dal segno meno" - una designazione sintattica piuttosto che semantica.
Jeroen Mostert

3
"negativo 10" è l'uso standard americano (credo) ma non è standard nel Regno Unito.
Alchymist

12

Si noti nella documentazione che (forse controintuitivamente) l'ordine di precedenza per - (Negative)è terzo.

Quindi ottieni effettivamente:

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

Se li inserisci in variabili, non vedrai che ciò accadrà, poiché non vi è alcuna operazione unaria che si verifica dopo la moltiplicazione.

Quindi qui A e B sono uguali, mentre C, D, E mostrano il risultato che stai vedendo (con E che ha il bracketing completo)

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.