Làm cách nào để tránh sự phân chia của các lỗi bằng 0 lỗi trong SQL?


363

Tôi có thông báo lỗi này:

Msg 8134, Cấp 16, Trạng thái 1, Dòng 1 Chia không có lỗi.

Cách tốt nhất để viết mã SQL là gì để tôi sẽ không bao giờ gặp lại thông báo lỗi này nữa?

Tôi có thể làm một trong những điều sau đây:

  • Thêm một mệnh đề where để ước số của tôi không bao giờ bằng 0

Hoặc là

  • Tôi có thể thêm một tuyên bố trường hợp, để có một điều trị đặc biệt cho số không.

Là cách tốt nhất để sử dụng một NULLIFmệnh đề?

Có cách nào tốt hơn, hoặc làm thế nào điều này có thể được thi hành?


7
Có lẽ một số xác nhận dữ liệu theo thứ tự.
Anthony

Câu trả lời:


645

Để tránh lỗi "Chia cho 0", chúng tôi đã lập trình nó như sau:

Select Case when divisor=0 then null
Else dividend / divisor
End ,,,

Nhưng đây là một cách tốt hơn để làm điều đó:

Select dividend / NULLIF(divisor, 0) ...

Bây giờ vấn đề duy nhất là nhớ bit Null If, nếu tôi sử dụng phím "/".


13
Cách thức thực hiện tốt hơn nhiều "Chọn cổ tức / nullif (số chia, 0) ..." sẽ phá vỡ nếu số chia là NULL.
Anderson

8
@Anderson Điều đó không đúng chút nào. Bạn có chắc chắn bạn đã không vô tình sử dụng IsNullthay vì NullIf? Hãy tự thử! SELECT Value,1/NullIf(Value,0)FROM(VALUES(0),(5.0),(NULL))x(Value);Trừ khi "phá vỡ" bạn có nghĩa là trả về một NULL? Bạn có thể chuyển đổi nó thành bất cứ điều gì bạn muốn với IsNullhoặc Coalesce.
ErikE

1
@ErikE, đó là sự thật ... hãy thử chạy ... chọn 1 / nullif (null, 0) ... bạn nhận được "Loại đối số đầu tiên cho NULLIF không thể là hằng số NULL vì loại đối số đầu tiên có được biết đến." Xử lý việc này bằng cách sử dụng "coalesce (FieldName, 0)" ... ví dụ: chọn 1 / nullif (coalesce (null, 0), 0)
John Joseph

1
@JohnJoseph Tôi không thể biết bạn có đồng ý với tôi hay tranh cãi với tôi không.
ErikE

1
@JohnJoseph Nhìn kỹ hơn vào lỗi bạn gặp phải. Đúng, SELECT 1 / NULLIF(NULL, 0)thất bại, nhưng đó là vì NULLIF()cần biết kiểu dữ liệu của đối số đầu tiên. Ví dụ thay đổi này hoạt động tốt : SELECT 1 / NULLIF(CAST(NULL AS INT), 0). Trong cuộc sống thực, bạn sẽ cung cấp một cột bảng NULLIF()thay vì một NULLhằng số. Vì các cột bảng đã biết các kiểu dữ liệu, điều này cũng hoạt động tốt : SELECT 1 / NULLIF(SomeNullableColumn, 0) FROM SomeTable.
MarredCheese

180

Trong trường hợp bạn muốn trả về 0, trong trường hợp độ lệch bằng 0 sẽ xảy ra, bạn có thể sử dụng:

SELECT COALESCE(dividend / NULLIF(divisor,0), 0) FROM sometable

Với mọi ước số bằng 0, bạn sẽ nhận được số 0 trong tập kết quả.


9
Một số điểm chuẩn cho thấy COALESCE chậm hơn một chút so với ISNULL. Tuy nhiên, COALESCE nằm trong các tiêu chuẩn nên dễ mang theo hơn.
Paul Chernoch

37
Nếu người khác không ngay lập tức hiểu lý do tại sao điều này hoạt động, NULLIF (d, 0) sẽ trả về NULL nếu d bằng 0. Trong SQL, chia cho NULL trả về NULL. Coalesce thay thế kết quả NULL bằng 0.
GuiSim

16
@QueryGeorge Trong khi tôi đồng ý với lập luận của bạn, xin lưu ý rằng có những trường hợp người ta quan tâm nhiều hơn những gì đúng về mặt thống kê hơn là đúng về mặt toán học. Trong một số trường hợp khi sử dụng các hàm thống kê, 0 hoặc thậm chí 1 là kết quả chấp nhận được khi ước số bằng 0.
Athafoud

10
Ai đó có thể giải thích cho tôi tại sao điều này là xấu? Nếu tôi đang cố gắng tìm ra một phần trăm và số chia là 0 thì tôi chắc chắn muốn kết quả là 0 phần trăm.
Todd Sharp

10
Tôi nghĩ rằng @George và @ James / Wilson về cơ bản hiểu sai câu hỏi đang được hỏi. Chắc chắn có những ứng dụng kinh doanh trong đó trả về "0" là phù hợp, ngay cả khi nó không đúng về mặt kỹ thuật theo quan điểm toán học.
Sean Branchaw

66

Đây dường như là cách khắc phục tốt nhất cho tình huống của tôi khi cố gắng giải quyết chia cho số 0, điều này xảy ra trong dữ liệu của tôi.

Giả sử bạn muốn tính tỷ lệ nữ nam cho các câu lạc bộ khác nhau, nhưng bạn phát hiện ra rằng truy vấn sau không thành công và đưa ra lỗi chia cho 0 khi cố gắng tính tỷ lệ cho Câu lạc bộ Chúa tể của những chiếc nhẫn không có phụ nữ :

SELECT club_id, males, females, males/females AS ratio
  FROM school_clubs;

Bạn có thể sử dụng hàm NULLIFđể tránh chia cho số không. NULLIFso sánh hai biểu thức và trả về null nếu chúng bằng nhau hoặc biểu thức đầu tiên khác.

Viết lại truy vấn dưới dạng:

SELECT club_id, males, females, males/NULLIF(females, 0) AS ratio
  FROM school_clubs;

Bất kỳ số nào được chia NULLcho NULL, và không có lỗi được tạo ra.


6
Đúng vậy, đó là CÁCH TỐT HƠN so với câu trả lời khác đã nhận được rất nhiều sự ủng hộ. Trong giải pháp của bạn, bạn có ít nhất một NULL, điều đó cho thấy rằng bạn không thể cung cấp kết quả chính xác. Nhưng nếu bạn chuyển đổi kết quả từ NULL thành Zero, thì bạn chỉ cần nhận được kết quả sai và sai.
Cảnh sát SQL

8
Nhân tiện, nếu bạn muốn tính tỷ lệ nam / nữ, thì tôi khuyên bạn nên so sánh nó với tổng số, như thế này : select males/(males+females), females/(males+females). Điều này sẽ cung cấp cho bạn tỷ lệ phân bổ nam và nữ trong một câu lạc bộ, như 31% nam, 69% nữ.
Cảnh sát SQL

44

Bạn cũng có thể làm điều này khi bắt đầu truy vấn:

SET ARITHABORT OFF 
SET ANSI_WARNINGS OFF

Vì vậy, nếu bạn có một cái gì đó như 100/0nó sẽ trả về NULL. Tôi chỉ thực hiện điều này cho các truy vấn đơn giản, vì vậy tôi không biết nó sẽ ảnh hưởng đến những truy vấn dài hơn / phức tạp như thế nào.


1
Làm việc cho tôi. Trong trường hợp của tôi, tôi phải sử dụng phép chia chia tại mệnh đề WHERE. Tôi chắc chắn không có bộ chia số 0, bởi vì khi tôi nhận xét WHERE, không có giá trị 0 nào trong kết quả. Nhưng bằng cách nào đó, trình tối ưu hóa truy vấn sẽ chia cho 0 trong khi lọc. THIẾT LẬP TẮT ARITHABORT TẮT và ANSI_WARNING TẮT làm việc đó - sau 2 ngày chiến đấu với số chia cho số 0 tại mệnh đề WHERE. Cám ơn!
huhu78

2
Điều này "cảm thấy" rất bẩn nhưng tôi thích nó! Cần nó trong một truy vấn không tổng hợp và sử dụng câu lệnh CASE không phải là một tùy chọn vì sau đó tôi phải thêm cột đó vào GROUP BY, điều này đã thay đổi hoàn toàn kết quả. Làm cho truy vấn ban đầu trở thành một lựa chọn phụ và sau đó thực hiện NHÓM THEO trên truy vấn bên ngoài cũng thay đổi kết quả vì có sự phân chia liên quan.
Andrew Steitz

1
OK, vì vậy tôi vẫn thích "giải pháp" này nhưng giống như nhiều bạn có lẽ cảm thấy, tôi cảm thấy phải có một cách "sạch" hơn. Nếu tôi quên bật lại các cảnh báo thì sao? Hoặc ai đó đã giấu mã của tôi (điều đó không bao giờ xảy ra, phải không?) Và không nghĩ về các cảnh báo? Dù sao, đã thấy câu trả lời khác về NULLIF (). Tôi biết về NULLIF () nhưng không nhận ra việc chia cho NULL trả về NULL (Tôi nghĩ đó sẽ là một lỗi). Vì vậy, ... tôi đã làm như sau: ISNULL ((SUM (foo) / NULLIF (SUM (bar), 0)), 0) AS Average
Andrew Steitz

2
Tôi không biết giải pháp này. Tôi không chắc chắn tôi thích nó, nhưng nó có thể hữu ích để biết, một ngày nào đó. Cảm ơn rât nhiều.
Henrik Staun Poulsen 17/12/13

1
Đây là giải pháp dễ nhất, nhưng lưu ý rằng nó sẽ làm giảm hiệu suất. Từ docs.microsoft.com/en-us/sql/t-sql/statements/ trên : "Đặt ARITHABORT thành TẮT có thể tác động tiêu cực đến tối ưu hóa truy vấn dẫn đến các vấn đề về hiệu suất."
mono blaine

36

Ít nhất bạn có thể ngăn truy vấn không bị lỗi và trả về NULLnếu có phép chia cho 0:

SELECT a / NULLIF(b, 0) FROM t 

Tuy nhiên, tôi KHÔNG BAO GIỜ chuyển đổi nó thành Zero bằng cách coalescenó được hiển thị trong câu trả lời khác có nhiều upvote. Điều này là hoàn toàn sai theo nghĩa toán học, và thậm chí còn nguy hiểm vì ứng dụng của bạn có thể sẽ trả về kết quả sai và sai.


32

EDIT: Gần đây tôi đang nhận được rất nhiều ý kiến ​​trái chiều về vấn đề này ... vì vậy tôi nghĩ rằng tôi chỉ cần thêm một lưu ý rằng câu trả lời này đã được viết trước khi câu hỏi được chỉnh sửa gần đây nhất, trong đó trả về null được tô sáng như một tùy chọn .. .những gì có vẻ rất chấp nhận được. Một số câu trả lời của tôi đã được giải quyết cho những lo ngại như của Edwardo, trong các bình luận, người dường như đang ủng hộ việc trả lại 0. Đây là trường hợp tôi đã chống lại.

TRẢ LỜI: Tôi nghĩ có một vấn đề tiềm ẩn ở đây, đó là phép chia cho 0 là không hợp pháp. Đó là một dấu hiệu cho thấy một cái gì đó sai về cơ bản. Nếu bạn chia cho số 0, bạn đang cố gắng làm điều gì đó không có ý nghĩa về mặt toán học, do đó, không có câu trả lời số nào bạn có thể nhận được sẽ hợp lệ. (Sử dụng null trong trường hợp này là hợp lý, vì nó không phải là giá trị sẽ được sử dụng trong các phép tính toán học sau này).

Vì vậy, Edwardo hỏi trong các ý kiến ​​"điều gì sẽ xảy ra nếu người dùng đặt số 0?", Và anh ta ủng hộ rằng việc lấy lại 0 sẽ không sao. Nếu người dùng đặt số 0 vào số tiền và bạn muốn trả về 0 khi họ làm điều đó, thì bạn nên đặt mã ở cấp quy tắc kinh doanh để bắt giá trị đó và trả về 0 ... không có trường hợp đặc biệt nào khi chia cho 0 = 0.

Đó là một sự khác biệt tinh tế, nhưng nó rất quan trọng ... bởi vì lần sau ai đó gọi hàm của bạn và hy vọng nó sẽ làm đúng, và nó làm một điều gì đó thú vị không đúng về mặt toán học, nhưng chỉ xử lý trường hợp cạnh cụ thể là nó có cơ hội tốt để cắn một ai đó sau này. Bạn không thực sự chia cho 0 ... bạn chỉ đang trả lời một câu trả lời xấu cho một câu hỏi xấu.

Hãy tưởng tượng tôi đang mã hóa một cái gì đó, và tôi làm hỏng nó lên. Tôi nên đọc giá trị tỷ lệ đo bức xạ, nhưng trong trường hợp cạnh lạ mà tôi không lường trước được, tôi đã đọc bằng 0. Sau đó tôi thả giá trị của mình vào hàm của bạn ... bạn trả về cho tôi 0! Hurrah, không bức xạ! Ngoại trừ nó thực sự ở đó và chỉ là tôi đã vượt qua một giá trị xấu ... nhưng tôi không biết. Tôi muốn phân chia để ném lỗi vì đó là cờ rằng có gì đó không đúng.


15
Tôi không đồng ý. Quy tắc kinh doanh của bạn sẽ không bao giờ kết thúc việc làm toán bất hợp pháp. Nếu bạn cuối cùng làm một cái gì đó như thế này rất có thể mô hình dữ liệu của bạn là sai. Bất cứ khi nào bạn gặp phải một số chia cho 0, bạn nên suy ngẫm nếu dữ liệu nên là NULL thay vì 0.
Remus Rusanu

32
Tôi không thể tin rằng mình đã bị hạ thấp bởi một người hỏi rằng tôi đã từng "làm bất kỳ chương trình thực sự nào chưa?" bởi vì tôi đang nói phải làm điều đó đúng hơn là lười biếng. thở dài
Beska

11
Tôi xin lỗi, tôi không có ý xúc phạm bạn. Nhưng câu hỏi hoàn toàn hợp lệ trong rất nhiều ứng dụng LOB phổ biến và việc trả lời nó bằng "chia cho 0 là không hợp pháp" không làm tăng giá trị IMHO.
Eduardo Molteni

2
@JackDoumund Phải. Đây là trường hợp bạn muốn các quy tắc kinh doanh xử lý một trường hợp đặc biệt theo cách đặc biệt ... nhưng nó không nên là phép toán cơ bản trả về một khoảng trống. Nó phải là quy tắc kinh doanh. Câu trả lời được chấp nhận trả về null, đó là một cách ổn để xử lý nó. Ném một ngoại lệ cũng sẽ ổn thôi. Phát hiện ra nó và xử lý trước khi nó đi đến SQL sẽ là lý tưởng. Cung cấp một số loại chức năng mà những thứ khác có thể gọi mà trả về giá trị toán học không chính xác không phải là cách để thực hiện, vì trường hợp đặc biệt đó có thể không áp dụng cho những người gọi khác.
Beska

4
@JackDoumund Vâng, đó là một bản tóm tắt tốt, mà tôi đồng ý. Ban đầu câu hỏi dường như được đặt ra là "tôi có thể làm gì để chỉ che giấu lỗi này." Kể từ đó, nó đã phát triển. Trả lại một null, câu trả lời cuối cùng anh ta đưa ra, có vẻ như là một phản hồi hợp lý. (Tôi đã ủng hộ mạnh mẽ việc không trả về số 0 hoặc một số số khác.)
Beska

28
SELECT Dividend / ISNULL(NULLIF(Divisor,0), 1) AS Result from table

Bằng cách bắt số 0 bằng nullif (), sau đó null kết quả bằng isnull () bạn có thể tránh được phép chia của mình bằng sai số 0.


3
Do độ dài của nó, câu trả lời của bạn đã được đề nghị xóa. Lưu ý rằng luôn luôn tốt hơn để thêm một lời giải thích nhỏ về bất cứ điều gì bạn đang đề xuất - ngay cả khi nó có vẻ rất đơn giản;)
Trinimon

10

Thay thế "chia cho 0" bằng 0 là điều gây tranh cãi - nhưng đó cũng không phải là lựa chọn duy nhất. Trong một số trường hợp thay thế bằng 1 là (hợp lý) thích hợp. Tôi thường thấy mình sử dụng

 ISNULL(Numerator/NULLIF(Divisor,0),1)

khi tôi nhìn vào sự thay đổi về điểm số / số đếm và muốn mặc định là 1 nếu tôi không có dữ liệu. Ví dụ

NewScore = OldScore *  ISNULL(NewSampleScore/NULLIF(OldSampleScore,0),1) 

Thường xuyên hơn không, tôi thực sự đã tính tỷ lệ này ở một nơi khác (không phải vì nó có thể đưa ra một số yếu tố điều chỉnh rất lớn cho mẫu số thấp. Trong trường hợp này, tôi thường kiểm soát OldSampleScore lớn hơn ngưỡng; Nhưng đôi khi 'hack' là thích hợp.


1
@N Mason; vâng, đôi khi 1 là một lựa chọn. Nhưng làm thế nào để bạn nhớ phần ISNULL, khi bạn gõ dấu gạch chéo ngược?
Henrik Staun Poulsen

1
Xin lỗi Henrik - Tôi không chắc là tôi hiểu câu hỏi.
N Mason

6

Tôi đã viết một hàm một lúc trước để xử lý nó cho các thủ tục được lưu trữ của tôi :

print 'Creating safeDivide Stored Proc ...'
go

if exists (select * from dbo.sysobjects where  name = 'safeDivide') drop function safeDivide;
go

create function dbo.safeDivide( @Numerator decimal(38,19), @divisor decimal(39,19))
   returns decimal(38,19)
begin
 -- **************************************************************************
 --  Procedure: safeDivide()
 --     Author: Ron Savage, Central, ex: 1282
 --       Date: 06/22/2004
 --
 --  Description:
 --  This function divides the first argument by the second argument after
 --  checking for NULL or 0 divisors to avoid "divide by zero" errors.
 -- Change History:
 --
 -- Date        Init. Description
 -- 05/14/2009  RS    Updated to handle really freaking big numbers, just in
 --                   case. :-)
 -- 05/14/2009  RS    Updated to handle negative divisors.
 -- **************************************************************************
   declare @p_product    decimal(38,19);

   select @p_product = null;

   if ( @divisor is not null and @divisor <> 0 and @Numerator is not null )
      select @p_product = @Numerator / @divisor;

   return(@p_product)
end
go

2
Xin chào Ron, giải pháp Nice, ngoại trừ nó có loại dữ liệu hạn chế (4 chữ số thập phân) và @divisors của chúng tôi cũng có thể âm. Và làm thế nào để bạn thực thi nó sử dụng? TIA Henrik Staun Poulsen
Henrik Staun Poulsen

1
Tôi đã xử lý nó khá nhanh để xử lý một tình huống cụ thể tại thời điểm đó. Ứng dụng dành cho nhà phát triển, vì vậy việc thực thi không quá khó ngoại trừ bộ nhớ của tôi. :-)
Ron Savage

5
Mặc dù tuyên bố in, nó không phải là một Proc được lưu trữ, đó là một UDF vô hướng. Điều này sẽ giết bạn trong MS-SQL nếu đó là một phần của truy vấn.
Mark Sowul

4
Tôi đồng ý với khẳng định của Mark Sowul rằng chức năng vô hướng sẽ gây đau. Đây là một gợi ý khủng khiếp trong T-SQL, đừng làm điều đó! Chức năng vô hướng là kẻ hủy diệt hiệu suất! Hàm có giá trị trong bảng là các hàm người dùng tốt duy nhất trong SQL Server (có thể ngoại trừ các hàm CLR có thể hoạt động tốt).
Davos

4
  1. Thêm một ràng buộc KIỂM TRA mà buộc Divisorphải khác không
  2. Thêm trình xác nhận vào biểu mẫu để người dùng không thể nhập giá trị 0 vào trường này.

1
Tôi bắt đầu thích các ràng buộc KIỂM TRA ngày càng nhiều.
Henrik Staun Poulsen

4

Để cập nhật SQL:

update Table1 set Col1 = Col2 / ISNULL(NULLIF(Col3,0),1)

3
xin chào Vijay, vâng, điều đó sẽ hiệu quả, nhưng ... tôi sẽ cẩn thận về phần ISNULL, nơi cuối cùng bạn chia cho NULL. Tôi muốn báo hiệu cho người dùng rằng kết quả là không xác định vì số chia là 0.
Henrik Staun Poulsen

2
Nó đã cứu tôi trong subQuery phức tạp, Cảm ơn.
QMaster

3

Không có thiết lập toàn cầu kỳ diệu 'tắt phân chia bằng 0 ngoại lệ'. Thao tác phải ném, vì ý nghĩa toán học của x / 0 khác với nghĩa NULL, vì vậy nó không thể trả về NULL. Tôi giả sử bạn đang quan tâm đến điều hiển nhiên và các truy vấn của bạn có các điều kiện nên loại bỏ các bản ghi với ước số 0 và không bao giờ đánh giá sự phân chia. 'Gotcha' thông thường hơn hầu hết các nhà phát triển mong đợi SQL hoạt động giống như các ngôn ngữ thủ tục và cung cấp ngắn mạch toán tử logic, nhưng KHÔNG . Tôi khuyên bạn nên đọc bài viết này: http://www.sqlmag.com/Articles/ArticleID/9148/pg/2/2.html


4
Có một "cài đặt toàn cầu kỳ diệu" như vậy; TẮT ARITHABORT TẮT.
David Manheim

3

Đây là một tình huống mà bạn có thể chia cho số không. Quy tắc kinh doanh là để tính vòng quay hàng tồn kho, bạn lấy chi phí của hàng hóa được bán trong một khoảng thời gian, hàng năm. Sau khi bạn có số hàng năm, bạn chia cho khoảng không quảng cáo trung bình trong khoảng thời gian đó.

Tôi đang xem xét tính toán số lượt hàng tồn kho xảy ra trong khoảng thời gian ba tháng. Tôi đã tính toán rằng tôi có Giá vốn hàng bán trong thời gian ba tháng là $ 1.000. Tỷ lệ bán hàng hàng năm là 4.000 đô la (1.000 đô la / 3) * 12. Khoảng không quảng cáo ban đầu là 0. Khoảng không quảng cáo kết thúc là 0. Khoảng không quảng cáo trung bình của tôi hiện là 0. Tôi có doanh số $ 4000 mỗi năm và không có hàng tồn kho. Điều này mang lại một số lượng vô hạn của lượt. Điều này có nghĩa là tất cả hàng tồn kho của tôi đang được khách hàng chuyển đổi và mua.

Đây là một quy tắc kinh doanh về cách tính vòng quay hàng tồn kho.


3
Vâng, sau đó bạn có một số lượt vô hạn . Vì vậy, trong trường hợp này, nếu bạn có số chia cho 0, thì bạn nên hiển thị nội dung như '#INF'.
Cảnh sát SQL

1
"Khoảng không quảng cáo ban đầu là 0. Khoảng không quảng cáo kết thúc là 0. Khoảng không quảng cáo trung bình của tôi hiện là 0." Tính toán của bạn là một ước tính. Tại một số thời điểm hàng tồn kho là tích cực hoặc bạn không thể vận chuyển / bán bất cứ thứ gì. Nếu bạn không hài lòng với kết quả +, hãy sử dụng ước tính tốt hơn về hàng tồn kho trung bình.
Tom Blodget

2
CREATE FUNCTION dbo.Divide(@Numerator Real, @Denominator Real)
RETURNS Real AS
/*
Purpose:      Handle Division by Zero errors
Description:  User Defined Scalar Function
Parameter(s): @Numerator and @Denominator

Test it:

SELECT 'Numerator = 0' Division, dbo.fn_CORP_Divide(0,16) Results
UNION ALL
SELECT 'Denominator = 0', dbo.fn_CORP_Divide(16,0)
UNION ALL
SELECT 'Numerator is NULL', dbo.fn_CORP_Divide(NULL,16)
UNION ALL
SELECT 'Denominator is NULL', dbo.fn_CORP_Divide(16,NULL)
UNION ALL
SELECT 'Numerator & Denominator is NULL', dbo.fn_CORP_Divide(NULL,NULL)
UNION ALL
SELECT 'Numerator & Denominator = 0', dbo.fn_CORP_Divide(0,0)
UNION ALL
SELECT '16 / 4', dbo.fn_CORP_Divide(16,4)
UNION ALL
SELECT '16 / 3', dbo.fn_CORP_Divide(16,3)

*/
BEGIN
    RETURN
        CASE WHEN @Denominator = 0 THEN
            NULL
        ELSE
            @Numerator / @Denominator
        END
END
GO

Tôi không thích giải pháp của bạn, vì sử dụng UDF buộc truy vấn phải chạy trong chế độ luồng đơn. Tôi thích thiết lập thử nghiệm của bạn. Tôi muốn có điều đó trong tất cả các UDF của chúng tôi.
Henrik Staun Poulsen

Đối với tôi giải pháp này là hoàn hảo và thanh lịch
Payedimistic

@Payedimistic; vâng, UDFs dẫn đến mã rất thanh lịch. Nhưng nó không hoạt động tốt. Đây là "con trỏ trên thuốc ngủ". :-) Thật khó để nhớ viết dbo. Sống thay vì "/" thông thường
Henrik Staun Poulsen

1

Lọc dữ liệu bằng cách sử dụng mệnh đề where để bạn không nhận được 0 giá trị.


1

Đôi khi, 0 có thể không phù hợp, nhưng đôi khi 1 cũng không phù hợp. Đôi khi một bước nhảy từ 0 đến 100.000.000 được mô tả là thay đổi 1 hoặc 100 phần trăm cũng có thể gây hiểu nhầm. 100.000.000 phần trăm có thể phù hợp trong kịch bản đó. Nó phụ thuộc vào loại kết luận bạn dự định rút ra dựa trên tỷ lệ phần trăm hoặc tỷ lệ.

Ví dụ: một mặt hàng bán rất nhỏ chuyển từ 2-4 được bán và một mặt hàng bán rất lớn thay đổi từ 1.000.000 sang 2.000.000 được bán có thể có nghĩa là những điều rất khác nhau đối với một nhà phân tích hoặc quản lý, nhưng cả hai đều đạt 100% hoặc 1 thay đổi.

Có thể dễ dàng cô lập các giá trị NULL hơn là quét qua một loạt các hàng 0% hoặc 100% trộn với dữ liệu hợp pháp. Thông thường, số 0 trong mẫu số có thể chỉ ra lỗi hoặc giá trị bị thiếu và bạn có thể không muốn chỉ điền vào một giá trị tùy ý chỉ để làm cho tập dữ liệu của bạn trông gọn gàng.

CASE
     WHEN [Denominator] = 0
     THEN NULL --or any value or sub case
     ELSE [Numerator]/[Denominator]
END as DivisionProblem

1
Tôi thấy rằng vấn đề là phải nhớ làm một cái gì đó bất cứ khi nào bạn muốn làm một bộ phận. Nếu bạn không nhớ thêm CASE hoặc NULLIF, bạn sẽ nhận được một trường hợp hỗ trợ trong x tuần, vào sáng thứ Hai. Tôi ghét điều đó.
Henrik Staun Poulsen

1

Đây là cách tôi sửa nó:

IIF (ValueA! = 0, Tổng / ValueA, 0)

Nó có thể được gói trong một bản cập nhật:

SET Pct = IIF (ValueA! = 0, Tổng / ValueA, 0)

Hoặc trong một lựa chọn:

CHỌN IIF (ValueA! = 0, Total / ValueA, 0) NHƯ Pct TỪ Tablename;

Suy nghĩ?


Tôi và những người khác thấy rằng thay thế "không xác định" bằng số 0 là một sửa chữa nguy hiểm. Tôi rất thích NULL. Nhưng điều khó khăn là phải nhớ thêm iif hoặc nullif trên tất cả các bộ phận!
Henrik Staun Poulsen 16/07/19

0

Bạn có thể xử lý lỗi một cách thích hợp khi nó lan truyền trở lại chương trình gọi (hoặc bỏ qua nếu đó là điều bạn muốn). Trong C #, bất kỳ lỗi nào xảy ra trong SQL sẽ đưa ra một ngoại lệ mà tôi có thể bắt và sau đó xử lý trong mã của mình, giống như bất kỳ lỗi nào khác.

Tôi đồng ý với Beska ở chỗ bạn không muốn che giấu lỗi. Bạn có thể không phải đối phó với một lò phản ứng hạt nhân nhưng nói chung các lỗi ẩn là thực hành lập trình xấu. Đây là một trong những lý do hầu hết các ngôn ngữ lập trình hiện đại thực hiện xử lý ngoại lệ có cấu trúc để tách rời giá trị trả về thực tế với mã lỗi / mã trạng thái. Điều này đặc biệt đúng khi bạn đang làm toán. Vấn đề lớn nhất là bạn không thể phân biệt giữa 0 được tính toán chính xác hoặc 0 do lỗi. Thay vào đó, bất kỳ giá trị nào được trả về là giá trị được tính toán và nếu có lỗi xảy ra, một ngoại lệ sẽ bị ném. Điều này tất nhiên sẽ khác nhau tùy thuộc vào cách bạn đang truy cập cơ sở dữ liệu và ngôn ngữ bạn đang sử dụng nhưng bạn sẽ luôn có thể nhận được thông báo lỗi mà bạn có thể xử lý.

try
{
    Database.ComputePercentage();
}
catch (SqlException e)
{
    // now you can handle the exception or at least log that the exception was thrown if you choose not to handle it
    // Exception Details: System.Data.SqlClient.SqlException: Divide by zero error encountered.
}

1
Tôi nghĩ rằng tất cả chúng ta đều đồng ý rằng việc che giấu lỗi bằng 0 không phải là một giải pháp. Những gì tôi đề xuất là viết mã của chúng tôi sao cho mỗi "/" được theo sau bởi "NULLIF". Bằng cách này, báo cáo / lò phản ứng hạt nhân của tôi không bị bỏ lại một mình, nhưng đang hiển thị "NULL" thay vì lỗi đáng tiếc đó Msg 8134. Vì lý do, nếu tôi cần một quy trình khác khi số chia là 0, thì Beska và tôi đồng ý. Chúng ta cần mã đó. Nó chỉ khó thực hiện mỗi khi bạn viết "/". "/ NULLIF" không phải là không thể làm mọi lúc.
Henrik Staun Poulsen

0

Sử dụng NULLIF(exp,0)nhưng theo cách này -NULLIF(ISNULL(exp,0),0)

NULLIF(exp,0)nghỉ nếu exp là nullnhưng NULLIF(ISNULL(exp,0),0)sẽ không phá vỡ


1
Tôi không thể nhận NULLIF (exp, 0), nếu 0 là Zero, không phải o. Thử; KHAI THÁC @i INT CHỌN 1 / NULLIF (@i, 0) để xem bạn có thể phá vỡ nó không.
Henrik Staun Poulsen
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.