Bagaimana cara menghindari kesalahan "divide by zero" di SQL?

363

Saya punya pesan kesalahan ini:

Msg 8134, Level 16, State 1, Line 1 Divide by zero error found.

Apa cara terbaik untuk menulis kode SQL sehingga saya tidak akan pernah melihat pesan kesalahan ini lagi?

Saya dapat melakukan salah satu dari yang berikut:

  • Tambahkan klausa dimana sehingga pembagi saya tidak pernah nol

Atau

  • Saya bisa menambahkan pernyataan kasus, sehingga ada perlakuan khusus untuk nol.

Apakah cara terbaik untuk menggunakan NULLIFklausa?

Apakah ada cara yang lebih baik, atau bagaimana ini bisa ditegakkan?

Henrik Staun Poulsen
sumber
7
Mungkin beberapa validasi data dilakukan.
Anthony

Jawaban:

645

Untuk menghindari kesalahan "Division by zero", kami telah memprogramnya seperti ini:

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

Tapi di sini ada cara yang lebih baik untuk melakukannya:

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

Sekarang satu-satunya masalah adalah untuk mengingat bit NullIf, jika saya menggunakan kunci "/".

Henrik Staun Poulsen
sumber
13
Cara yang jauh lebih baik untuk melakukannya "Pilih dividen / nullif (pembagi, 0) ..." istirahat jika pembagi adalah NULL.
Anderson
8
@Anderson Itu tidak benar sama sekali. Apakah Anda yakin Anda tidak sengaja menggunakan IsNullbukan NullIf? Cobalah sendiri! SELECT Value,1/NullIf(Value,0)FROM(VALUES(0),(5.0),(NULL))x(Value);Kecuali dengan "break" yang Anda maksud mengembalikan NULL? Anda dapat mengonversinya menjadi apa pun yang Anda inginkan dengan IsNullatau Coalesce.
ErikE
1
@ErikE, memang benar ... coba jalankan ... pilih 1 / nullif (null, 0) ... Anda mendapatkan "Jenis argumen pertama ke NULLIF tidak bisa menjadi konstanta NULL karena jenis argumen pertama memiliki untuk diketahui." Tangani ini dengan menggunakan "coalesce (FieldName, 0)" ... mis. Pilih 1 / nullif (coalesce (null, 0), 0)
John Joseph
1
@JohnJoseph Saya tidak tahu apakah Anda setuju dengan saya atau berdebat dengan saya.
ErikE
2
@JohnJoseph Lihatlah lebih dekat pada kesalahan yang Anda dapatkan. Ya, SELECT 1 / NULLIF(NULL, 0)gagal, tapi itu karena NULLIF()perlu tahu tipe data dari argumen pertama. Contoh diubah ini bekerja dengan baik: SELECT 1 / NULLIF(CAST(NULL AS INT), 0). Dalam kehidupan nyata, Anda akan memasok kolom tabel NULLIF()daripada NULLkonstanta. Sejak kolom tabel memiliki tipe data yang diketahui, ini juga berfungsi dengan baik: SELECT 1 / NULLIF(SomeNullableColumn, 0) FROM SomeTable.
MarredCheese
180

Jika Anda ingin mengembalikan nol, jika terjadi devisi nol, Anda dapat menggunakan:

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

Untuk setiap pembagi yang nol, Anda akan mendapatkan nol di set hasil.

Tobias Domhan
sumber
9
Beberapa tolok ukur mengungkapkan bahwa COALESCE sedikit lebih lambat daripada ISNULL. Namun, COALESCE ada dalam standar sehingga lebih portabel.
Paul Chernoch
37
Jika orang lain tidak langsung mengerti mengapa ini berhasil, NULLIF (d, 0) akan mengembalikan NULL jika d adalah 0. Dalam SQL, pembagian dengan NULL mengembalikan NULL. The Coalesce menggantikan NULL yang dihasilkan oleh 0.
GuiSim
16
@ SQLGeorge Sementara saya setuju dengan argumen Anda, harap dicatat bahwa ada beberapa kasus yang lebih peduli pada statistik yang benar daripada benar secara matematis. Dalam beberapa kasus ketika menggunakan fungsi statistik, 0 atau bahkan 1 adalah hasil yang dapat diterima ketika pembagi adalah nol.
Athafoud
10
Adakah yang bisa menjelaskan mengapa ini buruk? Jika saya mencoba untuk mencari tahu persen dan pembagi adalah nol, saya pasti ingin hasilnya menjadi nol persen.
Todd Sharp
10
Saya berpikir bahwa @George dan @ James / Wilson pada dasarnya salah memahami pertanyaan yang diajukan. Tentu saja ada aplikasi bisnis di mana mengembalikan "0" sesuai, bahkan jika itu tidak benar secara teknis dari sudut pandang matematika.
Sean Branchaw
66

Ini tampaknya menjadi perbaikan terbaik untuk situasi saya ketika mencoba mengatasi pembagian dengan nol, yang memang terjadi pada data saya.

Misalkan Anda ingin menghitung rasio pria-wanita untuk berbagai klub sekolah, tetapi Anda menemukan bahwa kueri berikut gagal dan mengeluarkan kesalahan dibagi-oleh-nol ketika mencoba menghitung rasio untuk Klub Lord of the Rings, yang tidak memiliki wanita :

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

Anda dapat menggunakan fungsi ini NULLIFuntuk menghindari pembagian dengan nol. NULLIFmembandingkan dua ekspresi dan mengembalikan nol jika sama atau ekspresi pertama sebaliknya.

Tulis ulang kueri sebagai:

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

Setiap angka dibagi dengan NULLmemberi NULL, dan tidak ada kesalahan yang dihasilkan.

jujur
sumber
6
Ya memang, itu WAY LEBIH BAIK daripada jawaban lain yang telah mendapat begitu banyak upvotes. Dalam solusi Anda, Anda memiliki setidaknya NULL, yang menunjukkan bahwa Anda tidak dapat memberikan hasil yang benar. Tetapi jika Anda mengonversi hasil dari NULL ke Nol, maka Anda hanya mendapatkan hasil yang salah dan menyesatkan.
SQL Police
8
By the way, jika Anda ingin menghitung pria / wanita rasio, maka saya sarankan untuk lebih membandingkannya dengan total, seperti ini: select males/(males+females), females/(males+females). Ini akan memberi Anda distribusi persentase pria dan wanita di sebuah klub, seperti 31% pria, 69% wanita.
SQL Police
44

Anda juga dapat melakukan ini di awal kueri:

SET ARITHABORT OFF 
SET ANSI_WARNINGS OFF

Jadi jika Anda memiliki sesuatu seperti 100/0itu akan mengembalikan NULL. Saya hanya melakukan ini untuk pertanyaan sederhana, jadi saya tidak tahu bagaimana itu akan mempengaruhi yang lebih lama / kompleks.

Taz
sumber
1
Bekerja untukku. Dalam kasus saya, saya harus menggunakan operasi pembagian di klausa WHERE. Saya yakin tidak ada pembagi nol, karena ketika saya berkomentar WHERE out, tidak ada nilai nol pada hasil. Tapi entah bagaimana pengoptimal permintaan melakukan pembagian dengan nol saat memfilter. SET ARITHABORT OFF SET dan ANSI_WARNINGS MATI berfungsi - setelah 2 hari berjuang dengan membagi dengan nol pada klausa WHERE. Terima kasih!
huhu78
2
Ini "terasa" sangat kotor tapi aku menyukainya! Membutuhkannya dalam kueri yang melakukan agregasi dan menggunakan pernyataan KASUS bukan pilihan karena saya harus menambahkan kolom itu ke GROUP BY yang benar-benar mengubah hasil. Membuat kueri awal menjadi subselect dan kemudian melakukan GROUP BY pada kueri luar juga mengubah hasil karena ada divisi yang terlibat.
Andrew Steitz
1
OK, jadi saya masih suka "solusi" ini tetapi seperti banyak dari Anda mungkin merasa, saya merasa harus ada cara "bersih". Bagaimana jika saya lupa mengaktifkan kembali peringatan? Atau seseorang menyamar kode saya (itu tidak pernah terjadi, kan?) Dan tidak memikirkan peringatan? Lagi pula, lihat jawaban lain tentang NULLIF (). Saya tahu tentang NULLIF () tetapi tidak menyadari pembagian dengan NULL mengembalikan NULL (saya pikir itu akan menjadi kesalahan). Jadi ... Saya pergi dengan yang berikut ini: ISNULL ((SUM (foo) / NULLIF (SUM (bar), 0)), 0) AS Avg
Andrew Steitz
2
Saya tidak tahu solusi ini. Saya tidak yakin saya menyukainya, tetapi mungkin berguna untuk mengetahui, suatu hari nanti. Terima kasih banyak.
Henrik Staun Poulsen
1
Ini adalah solusi termudah, tetapi perhatikan bahwa itu akan merusak kinerja. Dari docs.microsoft.com/en-us/sql/t-sql/statements/… : "Mengatur ARITHABORT ke OFF dapat berdampak negatif pada pengoptimalan kueri yang mengarah ke masalah kinerja."
mono blaine
36

Anda setidaknya dapat menghentikan permintaan agar tidak putus dengan kesalahan dan kembali NULLjika ada pembagian dengan nol:

SELECT a / NULLIF(b, 0) FROM t 

Namun, saya TIDAK AKAN PERNAH mengonversi ini menjadi Nol dengan coalesceseperti ditunjukkan dalam jawaban lain yang mendapat banyak upvotes. Ini benar-benar salah dalam arti matematis, dan bahkan berbahaya karena aplikasi Anda kemungkinan akan mengembalikan hasil yang salah dan menyesatkan.

Polisi SQL
sumber
32

EDIT: Saya mendapatkan banyak downvotes tentang ini baru-baru ini ... jadi saya pikir saya hanya akan menambahkan catatan bahwa jawaban ini ditulis sebelum pertanyaan menjalani edit terakhir, di mana pengembalian null disorot sebagai pilihan .. .yang tampaknya sangat bisa diterima. Beberapa jawaban saya ditujukan kepada keprihatinan seperti itu dari Edwardo, dalam komentar, yang tampaknya menganjurkan pengembalian 0. Ini adalah kasus saya menentang.

JAWABAN: Saya pikir ada masalah mendasar di sini, yaitu pembagian dengan 0 tidak legal. Ini merupakan indikasi bahwa ada sesuatu yang secara fundamental salah. Jika Anda membaginya dengan nol, Anda mencoba melakukan sesuatu yang tidak masuk akal secara matematis, sehingga tidak ada jawaban numerik yang Anda dapatkan akan valid. (Penggunaan nol dalam kasus ini masuk akal, karena ini bukan nilai yang akan digunakan dalam perhitungan matematika nanti).

Jadi Edwardo bertanya di komentar "bagaimana jika pengguna memasukkan 0?", Dan dia menganjurkan bahwa tidak apa-apa untuk mendapatkan 0 sebagai balasan. Jika pengguna memasukkan nol dalam jumlah, dan Anda ingin 0 dikembalikan ketika mereka melakukan itu, maka Anda harus memasukkan kode pada tingkat aturan bisnis untuk menangkap nilai itu dan mengembalikan 0 ... tidak memiliki kasus khusus di mana pembagian dengan 0 = 0.

Itu perbedaan yang halus, tetapi ini penting ... karena ketika seseorang memanggil fungsi Anda dan mengharapkannya untuk melakukan hal yang benar, dan itu melakukan sesuatu yang funky yang tidak benar secara matematis, tetapi hanya menangani kasing tepi tertentu itu punya peluang bagus untuk menggigit seseorang nanti. Anda tidak benar-benar membaginya dengan 0 ... Anda hanya mengembalikan jawaban yang buruk ke pertanyaan yang buruk.

Bayangkan saya sedang mengkode sesuatu, dan saya mengacaukannya. Saya seharusnya membaca nilai skala pengukuran radiasi, tetapi dalam kasus tepi aneh yang tidak saya antisipasi, saya baca di 0. Saya kemudian menjatuhkan nilai saya ke dalam fungsi Anda ... Anda mengembalikan saya 0! Hore, tidak ada radiasi! Kecuali itu benar-benar ada dan hanya saja saya melewati nilai buruk ... tapi saya tidak tahu. Saya ingin divisi untuk melempar kesalahan karena itu adalah bendera bahwa ada sesuatu yang salah.

Beska
sumber
15
Saya tidak setuju. Aturan bisnis Anda seharusnya tidak pernah berakhir dengan melakukan matematika ilegal. Jika Anda akhirnya melakukan sesuatu seperti ini, kemungkinan besar model data Anda salah. Setiap kali Anda menemukan membagi oleh 0 Anda harus merenungkan jika data harus sudah NULL bukannya 0
Remus Rusanu
32
Saya tidak percaya saya dipecat oleh seseorang yang bertanya apakah saya pernah "melakukan pemrograman nyata?" karena saya mengatakan untuk melakukannya dengan benar, daripada malas. desah
Beska
11
Maaf, saya tidak bermaksud menyinggung Anda. Tapi pertanyaannya sangat valid di banyak aplikasi LOB umum, dan menjawabnya dengan "pembagian dengan 0 tidak sah" tidak menambah nilai IMHO.
Eduardo Molteni
2
@ JackDouglas Benar. Ini adalah kasus di mana Anda ingin aturan bisnis menangani kasus khusus dengan cara khusus ... tetapi seharusnya bukan matematika yang mendasari yang mengembalikan kosong. Itu harus menjadi aturan bisnis. Jawaban yang diterima mengembalikan nol, yang merupakan cara yang baik untuk mengatasinya. Melempar pengecualian juga tidak apa-apa. Melihat dan menangani sebelum pergi ke SQL bisa dibilang ideal. Menyediakan semacam fungsi yang bisa dipanggil oleh hal-hal lain yang menghasilkan nilai yang salah secara matematis bukanlah cara yang tepat, karena kasing khusus itu mungkin tidak berlaku untuk penelepon yang lain.
Beska
4
@ JackDouglas Ya, itu ringkasan yang bagus, yang saya setujui. Awalnya pertanyaan itu sepertinya diutarakan sebagai "apa yang bisa saya lakukan untuk menyembunyikan kesalahan ini." Sejak itu, ia telah berevolusi. Mengembalikan nilai nol, jawaban yang akhirnya ia dapatkan, sepertinya merupakan respons yang masuk akal. (Saya sangat menganjurkan tidak mengembalikan 0, atau nomor lain.)
Beska
28
SELECT Dividend / ISNULL(NULLIF(Divisor,0), 1) AS Result from table

Dengan menangkap nol dengan nullif (), maka null yang dihasilkan dengan isnull () Anda dapat menghindari pembagian Anda dengan kesalahan nol.

Nisarg
sumber
3
Karena panjangnya, jawaban Anda telah direkomendasikan untuk dihapus. Perhatikan bahwa selalu lebih baik untuk menambahkan penjelasan kecil tentang apa pun yang Anda sarankan - bahkan jika itu tampak sangat sederhana;)
Trinimon
10

Mengganti "bagi dengan nol" dengan nol adalah kontroversial - tetapi itu juga bukan satu-satunya pilihan. Dalam beberapa kasus, mengganti dengan 1 sesuai (wajar). Saya sering menemukan diri saya menggunakan

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

ketika saya melihat pergeseran dalam skor / jumlah, dan ingin default ke 1 jika saya tidak memiliki data. Sebagai contoh

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

Lebih sering daripada tidak, saya sudah benar-benar menghitung rasio ini di tempat lain (paling tidak karena dapat melempar beberapa faktor penyesuaian yang sangat besar untuk penyebut rendah. Dalam hal ini saya biasanya mengontrol OldSampleScore lebih besar dari ambang; yang kemudian menghalangi nol Tapi terkadang 'retasan' itu sesuai.

N Mason
sumber
1
@N Mason; ya, terkadang 1 adalah opsi. Tetapi bagaimana Anda mengingat bagian ISNULL, ketika Anda mengetik backslash?
Henrik Staun Poulsen
1
Maaf Henrik - Saya tidak yakin saya mengerti pertanyaannya.
N Mason
6

Saya menulis sebuah fungsi beberapa waktu lalu untuk mengatasinya untuk prosedur tersimpan saya :

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
Ron Savage
sumber
2
Hai Ron, solusi bagus, kecuali ia memiliki tipe data terbatas (4 tempat desimal) dan @divisors kami bisa negatif juga. Dan bagaimana Anda menegakkan penggunaannya? TIA Henrik Staun Poulsen
Henrik Staun Poulsen
1
Saya berlari cepat untuk menangani skenario masalah tertentu pada saat itu. Aplikasi pengembang tunggal, jadi penegakannya tidak begitu sulit kecuali untuk ingatanku. :-)
Ron Savage
5
Meskipun ada pernyataan cetak, ini bukan proc yang disimpan, ini adalah skalar UDF. Ini akan membunuh Anda dalam MS-SQL jika itu bagian dari kueri.
Mark Sowul
4
Saya setuju dengan pernyataan Mark Sowul bahwa fungsi skalar akan menyebabkan rasa sakit. Ini adalah saran yang mengerikan di T-SQL, jangan lakukan itu! Fungsi Skalar adalah penghancur kinerja! Fungsi nilai tabel in-line adalah satu-satunya fungsi pengguna yang baik di SQL Server (mungkin dengan pengecualian fungsi CLR yang dapat berkinerja baik).
Davos
4
  1. Tambahkan batasan PERIKSA yang memaksa Divisormenjadi nol
  2. Tambahkan validator ke formulir sehingga pengguna tidak bisa memasukkan nilai nol ke dalam bidang ini.
menemukan
sumber
1
Saya mulai menyukai kendala PERIKSA lebih dan lebih.
Henrik Staun Poulsen
4

Untuk memperbarui SQL:

update Table1 set Col1 = Col2 / ISNULL(NULLIF(Col3,0),1)
Vijay Bansal
sumber
3
hai Vijay, Ya, itu akan berhasil, tapi ... Saya akan berhati-hati tentang bagian ISNULL, di mana Anda akhirnya membaginya dengan NULL. Saya lebih suka memberi sinyal kepada pengguna bahwa hasilnya tidak diketahui karena pembagi adalah nol.
Henrik Staun Poulsen
2
Ini menyelamatkan saya dalam subQuery yang rumit, Terima kasih.
QMaster
3

Tidak ada pengaturan global ajaib 'turn Division by 0 exception off'. Operasi harus melempar, karena arti matematis x / 0 berbeda dari makna NULL, sehingga tidak dapat mengembalikan NULL. Saya berasumsi Anda mengurus yang jelas dan pertanyaan Anda memiliki kondisi yang harus menghilangkan catatan dengan pembagi 0 dan tidak pernah mengevaluasi divisi. 'Gotcha' yang biasa adalah daripada kebanyakan pengembang mengharapkan SQL berperilaku seperti bahasa prosedural dan menawarkan hubungan pendek operator logis, tetapi TIDAK . Saya sarankan Anda membaca artikel ini: http://www.sqlmag.com/Articles/ArticleID/9148/pg/2/2.html

Remus Rusanu
sumber
4
Ada semacam "pengaturan global Ajaib"; SET ARITHABORT OFF.
David Manheim
3

Berikut adalah situasi di mana Anda dapat membaginya dengan nol. Aturan bisnis adalah bahwa untuk menghitung perputaran persediaan, Anda mengambil harga pokok penjualan untuk suatu periode, menjadikannya tahunan. Setelah Anda memiliki angka tahunan, Anda membagi dengan persediaan rata-rata untuk periode tersebut.

Saya sedang menghitung jumlah perputaran persediaan yang terjadi dalam periode tiga bulan. Saya telah menghitung bahwa saya memiliki Harga Pokok Penjualan selama periode tiga bulan sebesar $ 1.000. Tingkat penjualan tahunan adalah $ 4.000 ($ 1.000 / 3) * 12. Persediaan awal adalah 0. Persediaan akhir adalah 0. Persediaan rata-rata saya sekarang adalah 0. Saya memiliki penjualan $ 4000 per tahun, dan tidak ada persediaan. Ini menghasilkan jumlah belokan yang tak terbatas. Ini berarti bahwa semua inventaris saya sedang dikonversi dan dibeli oleh pelanggan.

Ini adalah aturan bisnis tentang cara menghitung perputaran persediaan.

Jimmy
sumber
3
Ya, Anda kemudian memiliki jumlah belokan yang tak terbatas . Jadi dalam hal ini, jika Anda memiliki pembagian dengan nol, maka Anda harus menunjukkan sesuatu seperti '#INF'.
SQL Police
1
"Persediaan awal adalah 0. Persediaan akhir adalah 0. Persediaan rata-rata saya sekarang adalah 0." Perhitungan Anda adalah perkiraan. Pada suatu saat inventaris positif atau Anda tidak dapat mengirim / menjual apa pun. Jika Anda tidak puas dengan + ∞ sebagai hasilnya, gunakan estimasi inventaris rata-rata yang lebih baik.
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
Gregory Hart
sumber
Saya tidak suka solusi Anda, karena menggunakan UDF memaksa kueri dijalankan dalam mode berulir tunggal. Saya suka pengaturan pengujian Anda. Saya ingin memilikinya di semua UDF kami.
Henrik Staun Poulsen
Bagi saya solusi ini sempurna dan elegan
Payedimaunt
@Payedimaunt; ya, UDF menghasilkan kode yang sangat elegan. Tapi itu tidak berkinerja baik. Ini adalah "kursor pada pil tidur". :-) Juga sulit untuk mengingat untuk menulis dbo.Bagi sebagai ganti dari "/" biasa
Henrik Staun Poulsen
1

Memfilter data menggunakan klausa dimana sehingga Anda tidak mendapatkan nilai 0.

nunespascal
sumber
1

Terkadang, 0 mungkin tidak sesuai, tetapi terkadang 1 juga tidak tepat. Kadang-kadang lompatan dari 0 hingga 100.000.000 digambarkan sebagai perubahan 1 atau 100 persen juga bisa menyesatkan. 100.000.000 persen mungkin sesuai dalam skenario itu. Itu tergantung pada kesimpulan apa yang ingin Anda buat berdasarkan persentase atau rasio.

Misalnya, barang yang sangat kecil yang dijual dari 2-4 yang terjual dan barang yang sangat besar berubah dari 1.000.000 menjadi 2.000.000 yang terjual mungkin berarti hal yang sangat berbeda bagi seorang analis atau manajemen, tetapi keduanya akan menjadi 100% atau 1 perubahan.

Mungkin lebih mudah untuk mengisolasi nilai NULL daripada menjelajahi sekitar 0% atau 100% baris yang dicampur dengan data yang sah. Seringkali, 0 dalam penyebut dapat menunjukkan kesalahan atau nilai yang hilang, dan Anda mungkin tidak ingin hanya mengisi nilai arbitrer hanya untuk membuat dataset Anda terlihat rapi.

CASE
     WHEN [Denominator] = 0
     THEN NULL --or any value or sub case
     ELSE [Numerator]/[Denominator]
END as DivisionProblem
Joeyslaptop
sumber
1
Saya menemukan bahwa masalahnya adalah ingat untuk melakukan sesuatu kapan pun Anda ingin melakukan pembagian. Jika Anda gagal mengingat menambahkan KASUS atau NULLIF, Anda mendapatkan kasus dukungan dalam x minggu, pada hari Senin pagi. Aku benci itu.
Henrik Staun Poulsen
1

Inilah cara saya memperbaikinya:

IIF (ValueA! = 0, Total / ValueA, 0)

Itu dapat dibungkus dengan pembaruan:

SET Pct = IIF (ValueA! = 0, Total / ValueA, 0)

Atau di pilih:

SELECT IIF (ValueA! = 0, Total / ValueA, 0) SEBAGAI Pct DARI Tablename;

Pikiran?

CorvetteGuru
sumber
Saya dan yang lainnya menemukan bahwa mengganti "tidak dikenal" dengan nol adalah perbaikan yang berbahaya. Saya lebih suka NULL. Tetapi bagian yang sulit adalah ingat untuk menambahkan iif atau nullif pada semua divisi!
Henrik Staun Poulsen
0

Anda dapat menangani kesalahan dengan tepat ketika merambat kembali ke program panggilan (atau mengabaikannya jika itu yang Anda inginkan). Dalam C # setiap kesalahan yang terjadi di SQL akan melempar pengecualian yang bisa saya tangkap dan kemudian menangani kode saya, sama seperti kesalahan lainnya.

Saya setuju dengan Beska karena Anda tidak ingin menyembunyikan kesalahan. Anda mungkin tidak berurusan dengan reaktor nuklir tetapi menyembunyikan kesalahan secara umum adalah praktik pemrograman yang buruk. Ini adalah salah satu alasan kebanyakan bahasa pemrograman modern menerapkan penanganan pengecualian terstruktur untuk memisahkan nilai pengembalian aktual dengan kode kesalahan / status. Ini terutama benar ketika Anda melakukan matematika. Masalah terbesar adalah bahwa Anda tidak dapat membedakan antara 0 yang dikembalikan dengan benar atau 0 sebagai hasil dari kesalahan. Sebaliknya nilai yang dikembalikan adalah nilai yang dihitung dan jika terjadi kesalahan pengecualian dilemparkan. Ini tentu saja akan berbeda tergantung pada bagaimana Anda mengakses database dan bahasa apa yang Anda gunakan tetapi Anda harus selalu bisa mendapatkan pesan kesalahan yang bisa Anda tangani.

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.
}
Despertar
sumber
1
Saya pikir kita semua sepakat bahwa menyembunyikan kesalahan dengan 0 bukanlah solusi. Yang saya usulkan adalah menulis kode kita sehingga setiap "/" diikuti oleh "NULLIF". Dengan cara ini laporan saya / reaktor nuklir tidak dibiarkan sendiri, tetapi menunjukkan "NULL" bukannya kesalahan sial Msg 8134. Tentu saja, jika saya memerlukan proses yang berbeda ketika pembagi adalah 0, maka Beska dan saya setuju. Kita perlu kode itu. Hanya sulit dilakukan setiap kali Anda menulis "/". "/ NULLIF" bukan tidak mungkin dilakukan setiap saat.
Henrik Staun Poulsen
0

Gunakan NULLIF(exp,0)tetapi dengan cara ini -NULLIF(ISNULL(exp,0),0)

NULLIF(exp,0)istirahat jika exp nulltetapi NULLIF(ISNULL(exp,0),0)tidak akan rusak

Johnny Kancharla
sumber
1
Saya tidak bisa mendapatkan NULLIF (exp, 0), jika 0 adalah nol, bukan o. Mencoba; DECLARE @i INT SELECT 1 / NULLIF (@i, 0) untuk melihat apakah Anda dapat memecahkannya.
Henrik Staun Poulsen