Masalah operasi yang aneh di SQL Server: -100 / -100 * 10 = 0

106
  • Jika Anda mengeksekusi SELECT -100/-100*10hasilnya adalah 0.
  • Jika Anda mengeksekusi SELECT (-100/-100)*10hasilnya adalah 10.
  • Jika Anda mengeksekusi SELECT -100/(-100*10)hasilnya adalah 0.
  • Jika Anda mengeksekusi SELECT 100/100*10hasilnya adalah 10.

BOL menyatakan:

Jika dua operator dalam ekspresi memiliki tingkat prioritas operator yang sama, mereka dievaluasi dari kiri ke kanan berdasarkan posisinya dalam ekspresi.

Dan

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

Apakah BOL salah, atau saya melewatkan sesuatu? Tampaknya -membuang prioritas (diharapkan).

cuizizhe
sumber
7
Apa pertanyaanmu?
Ilyes
14
Menurut Anda mengapa Anda harus melakukan dengan bit, Anda bekerja dengan bilangan bulat. Dan integer / integer = integer. Jadi -100 / -1000 adalah 0
sepupic
5
Oke, saya setuju, itu -tampaknya menyebabkan aliran menjadi "salah". Jika Anda mencoba, -100/(-100)*10Anda mendapatkan hasilnya 10. tampaknya nilai /tersebut diterapkan terhadap nilai -dalam persamaan dan kemudian persamaan 100*10tersebut ditentukan. Saya tidak yakin ini adalah kesalahan dengan BOL, tetapi lebih dari itu SQL Server tidak berfungsi seperti yang diharapkan. Mungkin ada baiknya mengangkat masalah di sql-docs dan melihat apa tanggapan mereka di sana; mungkin sebuah catatan bisa ditambahkan ke dokumentasi yang menasihati "fitur".
Larnu
3
SELECT -100/(-100)*10juga mengembalikan 10. Sepertinya -diperlakukan sebagai -operator yang harus diterapkan hanya setelah 100*10dihitung
Panagiotis Kanavos
7
A / -B * Cadalah A <div> <negate> B <multiply> C. Negasi memiliki prioritas yang lebih rendah daripada kalikan, sesuai dokumen, jadi hasilnya adalah A / -(B * C). Anda dapat melihat ini lebih jelas dengan menggunakan konstanta mengambang: 12e / -13e * 14evs. 12e / (-13e) * 14evs. 12e / 13e * 14eAlasan ini membuat kita bingung adalah karena kita umumnya mengharapkan minus unary menjadi bagian dari literal, atau setidaknya memiliki prioritas yang sangat tinggi, tetapi itu bukan cara T-SQL bekerja.
Jeroen Mostert

Jawaban:

96

Menurut tabel prioritas, ini adalah perilaku yang diharapkan. Operator dengan prioritas lebih tinggi ( /dan *) dievaluasi sebelum operator dengan prioritas lebih rendah (unary -). Jadi ini:

-100 / -100 * 10

dievaluasi sebagai:

-(100 / -(100 * 10))

Perhatikan bahwa perilaku ini berbeda dari kebanyakan bahasa pemrograman di mana negasi unary memiliki prioritas lebih tinggi daripada perkalian dan pembagian misalnya VB , JavaScript .

Salman A
sumber
38
Wow, fitur gem lain di T-SQL :) Saya rasa saya harus mengaudit semua kode saya sekarang untuk mencari bug.
usr
14
Oh man. Ini bahkan lebih buruk daripada berbagai bug operator terner PHP bugs.php.net/bug.php?id=61915 . Apa pendapat orang waras bahwa operator unary harus memiliki prioritas yang lebih rendah daripada yang biner?
phuclv
12
Perbedaan nyata mungkin adalah apakah -dianggap sebagai operator di -100. Dalam beberapa bahasa, ini adalah bagian dari sintaks integer.
Barmar
7
Jadi ini adalah bug yang didahulukan dari unary -.
Kevin
4
Dan pemenang desain kontra-intuitif adalah ...: Microsoft - sekali lagi
rexkogitans
34

BOL benar. -memiliki prioritas lebih rendah dari *, jadi

-A * B

diuraikan sebagai

-(A * B)

Perkalian apa adanya, Anda biasanya tidak memperhatikan hal ini, kecuali saat menggabungkan dua operator biner lain dengan prioritas yang sama: /dan %(dan %jarang digunakan dalam ekspresi gabungan seperti ini). Begitu

C / -A * B

Diurai sebagai

C / -(A * B)

menjelaskan hasil. Ini kontra-intuitif karena di sebagian besar bahasa lain, unary minus memiliki prioritas lebih tinggi daripada *dan /, tetapi tidak di T-SQL, dan ini didokumentasikan dengan benar.

Cara yang bagus (?) Untuk mengilustrasikannya:

SELECT -1073741824 * 2

menghasilkan luapan aritmatika, karena -(1073741824 * 2)menghasilkan 2147483648sebagai perantara, yang tidak sesuai dengan INT, tetapi

SELECT (-1073741824) * 2

menghasilkan hasil yang diharapkan -2147483648, yang tidak.

Jeroen Mostert
sumber
"minus" adalah biner. Unary -adalah "negatif". Orang yang mengatakan hal-hal seperti "minus 10" padahal yang mereka maksud adalah "negatif 10" menjadi tidak tepat.
Akumulasi
11
@ Akumulasi: ketidaktepatan bukan milik saya. The -operator, bila diterapkan pada operan tunggal, disebut MINUSdalam rencana query SQL. Mitra binernya disebut SUB. Jika Anda suka, tafsirkan "unary minus" sebagai singkatan untuk "operator unary yang ditandai dengan tanda minus" - sintaksis daripada sebutan semantik.
Jeroen Mostert
3
"negatif 10" adalah penggunaan standar Amerika (saya percaya) tetapi tidak standar di Inggris.
Alchymist
12

Perhatikan dalam dokumentasi bahwa (mungkin berlawanan secara intuitif) urutan prioritas - (Negative)adalah ketiga.

Jadi Anda secara efektif mendapatkan:

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

Jika Anda menempatkannya ke dalam variabel, Anda tidak akan melihat ini terjadi, karena tidak ada operasi unary yang terjadi setelah perkalian.

Jadi di sini A dan B adalah sama, sedangkan C, D, E menunjukkan hasil yang Anda lihat (dengan E memiliki bracketing lengkap)

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
sumber