Sự cố hoạt động lạ trong SQL Server: -100 / -100 * 10 = 0


106
  • Nếu bạn thực hiện SELECT -100/-100*10kết quả là 0.
  • Nếu bạn thực hiện SELECT (-100/-100)*10kết quả là 10.
  • Nếu bạn thực hiện SELECT -100/(-100*10)kết quả là 0.
  • Nếu bạn thực hiện SELECT 100/100*10kết quả là 10.

BOL nói:

Khi hai toán tử trong một biểu thức có cùng mức ưu tiên của toán tử, chúng được đánh giá từ trái sang phải dựa trên vị trí của chúng trong biểu thức.

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

Có phải BOL sai, hoặc tôi đang thiếu một cái gì đó? Có vẻ như -đang loại bỏ quyền ưu tiên (dự kiến).


7
Câu hỏi của bạn là gì?
Ilyes

14
Tại sao bạn nghĩ rằng bạn phải làm với bit, bạn đang làm việc với số nguyên. Và số nguyên / số nguyên = số nguyên. So -100 / -1000 là 0
Sepupic

5
OK, tôi đồng ý, điều -đó dường như đang làm cho luồng đi "sai". Nếu bạn cố gắng -100/(-100)*10bạn sẽ nhận được kết quả 10. có vẻ như /đang được áp dụng đối với giá trị -trong phương trình và sau đó phương trình 100*10đang được xác định. Tôi không chắc đây là lỗi với BOL, nhưng nhiều hơn nữa là SQL Server không hoạt động như mong đợi. Có thể đáng để nêu vấn đề trên sql-docs và xem phản hồi của họ ở đó là gì; có lẽ một ghi chú có thể được thêm vào tài liệu tư vấn về "tính năng".
Larnu

3
SELECT -100/(-100)*10cũng trả về 10. Dường như -được coi là các -nhà điều hành cần được áp dụng sau khi 100*10được tính
Panagiotis Kanavos

7
A / -B * CA <div> <negate> B <multiply> C. Negate có quyền ưu tiên thấp hơn nhân, theo tài liệu, vì vậy kết quả là A / -(B * C). Bạn có thể thấy điều này rõ ràng hơn bằng cách sử dụng hằng số nổi: 12e / -13e * 14eso 12e / (-13e) * 14evới 12e / 13e * 14e. Lý do điều này khiến chúng ta khó chịu là vì chúng ta thường mong đợi trừ một bậc sẽ trở thành một phần của nghĩa đen, hoặc ít nhất là có mức độ ưu tiên rất cao, nhưng đó không phải là cách T-SQL làm.
Jeroen Mostert

Câu trả lời:


96

Theo bảng ưu tiên, đây hành vi được mong đợi. Toán tử có mức độ ưu tiên cao hơn ( /*) được đánh giá trước toán tử có mức độ ưu tiên thấp hơn (một bậc -). Vì vậy, điều này:

-100 / -100 * 10

được đánh giá là:

-(100 / -(100 * 10))

Lưu ý rằng hành vi này khác với hầu hết các ngôn ngữ lập trình trong đó phủ định một ngôi có mức độ ưu tiên cao hơn phép nhân và chia, ví dụ VB , JavaScript .


38
Chà, một tính năng đá quý khác trong T-SQL :) Tôi đoán tôi phải kiểm tra tất cả mã của mình bây giờ để tìm kiếm lỗi.
usr

14
trời ơi. Điều này thậm chí còn tồi tệ hơn các lỗi toán tử bậc ba PHP khác nhau bug.php.net/bug.php?id=61915 . Những người lành mạnh nghĩ rằng các toán tử một ngôi phải có quyền ưu tiên thấp hơn so với các toán tử nhị phân?
phuclv

12
Sự khác biệt thực sự có thể được -coi là một nhà điều hành trong -100. Trong một số ngôn ngữ, nó là một phần của cú pháp số nguyên.
Barmar

7
Vì vậy, đó là một lỗi trong ưu tiên của họ -.
Kevin

4
Và người chiến thắng trong thiết kế phản trực quan là ...: Microsoft - một lần nữa
rexkogitans

34

BOL là chính xác. -có mức độ ưu tiên thấp hơn *, vì vậy

-A * B

được phân tích cú pháp là

-(A * B)

Phép nhân là gì, bạn thường không nhận thấy điều này, ngoại trừ khi trộn hai toán tử nhị phân khác có mức độ ưu tiên bằng nhau: /%(và %hiếm khi được sử dụng trong các biểu thức ghép như thế này). Vì thế

C / -A * B

Được phân tích cú pháp là

C / -(A * B)

giải thích kết quả. Điều này là phản trực quan vì trong hầu hết các ngôn ngữ khác, trừ một bậc có mức độ ưu tiên cao hơn */, nhưng không phải trong T-SQL và điều này được ghi lại một cách chính xác.

Một cách tốt đẹp (?) Để minh họa nó:

SELECT -1073741824 * 2

tạo ra tràn số học, bởi vì -(1073741824 * 2)tạo ra 2147483648như một trung gian, không phù hợp với một INT, nhưng

SELECT (-1073741824) * 2

tạo ra kết quả mong đợi -2147483648.


"trừ" là nhị phân. Unary -là "âm". Những người nói những điều như "âm 10" khi chúng có nghĩa là "âm 10" là không chính xác.
Tích lũy

11
@Acccumulation: không chính xác không phải của tôi. Các -nhà điều hành, khi áp dụng cho một toán hạng duy nhất, được gọi là MINUStrong kế hoạch truy vấn SQL. Đối tác nhị phân của nó được gọi SUB. Nếu bạn muốn, hãy giải thích "số trừ một ngôi" là viết tắt của "toán tử một ngôi được ký hiệu bằng dấu trừ" - một cú pháp chứ không phải một chỉ định ngữ nghĩa.
Jeroen Mostert

3
"âm 10" là cách sử dụng tiêu chuẩn của người Mỹ (tôi tin) nhưng nó không phải là tiêu chuẩn ở Anh.
Alchymist

12

Lưu ý trong tài liệu rằng (có lẽ phản trực giác) thứ tự ưu tiên - (Negative)là thứ ba.

Vì vậy, bạn nhận được một cách hiệu quả:

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

Nếu bạn đặt chúng vào các biến, bạn sẽ không thấy điều này xảy ra, vì không có phép toán một ngôi nào xảy ra sau phép nhân.

Vì vậy, ở đây A và B giống nhau, trong khi C, D, E hiển thị kết quả bạn đang thấy (với E có toàn bộ dấu ngoặc kép)

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.