Jak uniknąć błędu „dziel przez zero” w SQL?

363

Mam ten komunikat o błędzie:

Msg 8134, poziom 16, stan 1, wiersz 1 Napotkano błąd dzielenia przez zero.

Jaki jest najlepszy sposób na napisanie kodu SQL, aby nigdy więcej nie zobaczyłem tego komunikatu o błędzie?

Mógłbym wykonać jedną z następujących czynności:

  • Dodaj klauzulę where, aby mój dzielnik nigdy nie wynosił zero

Lub

  • Mógłbym dodać opis przypadku, aby było specjalne traktowanie dla zera.

Czy to najlepszy sposób na użycie NULLIFklauzuli?

Czy istnieje lepszy sposób lub jak można to egzekwować?

Henrik Staun Poulsen
źródło
7
Być może pewna poprawność danych jest w porządku.
Anthony

Odpowiedzi:

644

Aby uniknąć błędu „Dzielenie przez zero” zaprogramowaliśmy go w następujący sposób:

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

Ale tutaj jest o wiele ładniejszy sposób:

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

Teraz jedynym problemem jest zapamiętanie bitu NullIf, jeśli użyję klucza „/”.

Henrik Staun Poulsen
źródło
13
Znacznie ładniejszy sposób na zrobienie tego „Select dividend / nullif (divisor, 0) ...” psuje się, jeśli dzielnik jest NULL.
Anderson
8
@Anderson To wcale nie prawda. Czy na pewno nie użyłeś przypadkowo IsNullzamiast NullIf? Spróbuj sam! SELECT Value,1/NullIf(Value,0)FROM(VALUES(0),(5.0),(NULL))x(Value);Chyba że przez „przerwy” masz na myśli zwrot NULL? Możesz przekonwertować to na co chcesz za pomocą IsNulllub Coalesce.
ErikE
1
@ErikE, to prawda ... spróbuj uruchomić ... wybierz 1 / nullif (null, 0) ... dostajesz "Typ pierwszego argumentu dla NULLIF nie może być stałą NULL, ponieważ typ pierwszego argumentu ma być znanym. ” Postępuj tak, używając „coalesce (FieldName, 0)” ... np. Wybierz 1 / nullif (coalesce (null, 0), 0)
John Joseph
1
@JohnJoseph Nie wiem, czy się ze mną zgadzasz, czy kłócisz ze mną.
ErikE
1
@JohnJoseph Przyjrzyj się bliżej otrzymanemu błędowi. Tak, SELECT 1 / NULLIF(NULL, 0)kończy się niepowodzeniem, ale dlatego, że NULLIF()musi znać typ danych pierwszego argumentu. Ten zmieniony przykład działa prawidłowo: SELECT 1 / NULLIF(CAST(NULL AS INT), 0). W prawdziwym życiu dostarczysz kolumnę tabeli NULLIF()zamiast NULLstałej. Ponieważ kolumny tabeli mają znanych typów danych, to również działa dobrze: SELECT 1 / NULLIF(SomeNullableColumn, 0) FROM SomeTable.
MarredCheese
180

Jeśli chcesz zwrócić zero, na wypadek gdyby nastąpiło zerowe odchylenie, możesz użyć:

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

Dla każdego dzielnika, który wynosi zero, otrzymasz zero w zestawie wyników.

Tobias Domhan
źródło
9
Niektóre testy porównawcze pokazują, że COALESCE jest nieco wolniejszy niż ISNULL. Jednak COALESCE jest zgodny ze standardami, więc jest bardziej przenośny.
Paul Chernoch
37
Jeśli ktoś inny nie od razu zrozumie, dlaczego to działa, NULLIF (d, 0) zwróci NULL, jeśli d wynosi 0. W SQL dzielenie przez NULL zwraca NULL. Koalesce zastępuje wynikową wartość NULL wartością 0.
GuiSim
16
@SQLGeorge Chociaż zgadzam się z twoim argumentem, pamiętaj, że są przypadki, w których bardziej zależy na tym, co jest statystycznie poprawne niż matematyczne. W niektórych przypadkach, gdy używane są funkcje statystyczne, 0 lub nawet 1 jest akceptowalnym wynikiem, gdy dzielnik wynosi zero.
Athafoud,
10
Czy ktoś może mi wyjaśnić, dlaczego jest tak źle? Jeśli próbuję obliczyć procent, a dzielnik wynosi zero, z pewnością chcę, aby wynik wynosił zero procent.
Todd Sharp,
10
Myślę, że @George i @ James / Wilson zasadniczo nie rozumieją postawionego pytania. Z pewnością istnieją aplikacje biznesowe, w których właściwe jest zwrócenie „0”, nawet jeśli nie jest to technicznie prawdą z matematycznego punktu widzenia.
Sean Branchaw
66

Wydawało się, że jest to najlepsza poprawka w mojej sytuacji, gdy próbuję rozwiązać problem dzielenia przez zero, co dzieje się w moich danych.

Załóżmy, że chcesz obliczyć proporcje mężczyzn i kobiet dla różnych klubów szkolnych, ale odkrywasz, że poniższe zapytanie kończy się niepowodzeniem i powoduje błąd dzielenia przez zero, gdy próbuje obliczyć stosunek dla Lord of the Rings Club, w którym nie ma kobiet :

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

Możesz użyć tej funkcji, NULLIFaby uniknąć dzielenia przez zero. NULLIFporównuje dwa wyrażenia i zwraca null, jeśli są równe lub w przeciwnym razie pierwsze wyrażenie.

Przepisz zapytanie jako:

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

Dowolna liczba podzielona przez NULLdaje NULLi nie jest generowany błąd.

szczery
źródło
6
Tak, rzeczywiście, jest to DROGA LEPSZA niż ta inna odpowiedź, która ma tak wiele pozytywnych opinii. W swoim rozwiązaniu masz co najmniej NULL, co oznacza, że ​​nie możesz podać poprawnego wyniku. Ale jeśli przekonwertujesz wynik z NULL na zero, po prostu otrzymasz błędne i mylące wyniki.
SQL Police
8
Przy okazji, jeśli chcesz, aby obliczyć współczynnik / kobieta mężczyzna, to proponuję, aby lepiej porównać go do sumy, na przykład: select males/(males+females), females/(males+females). To da ci procentowy rozkład mężczyzn i kobiet w klubie, na przykład 31% mężczyzn i 69% kobiet.
SQL Police
44

Możesz to również zrobić na początku zapytania:

SET ARITHABORT OFF 
SET ANSI_WARNINGS OFF

Więc jeśli masz coś takiego 100/0, zwróci NULL. Zrobiłem to tylko dla prostych zapytań, więc nie wiem, jak wpłynie to na dłuższe / złożone.

Taz
źródło
1
Pracuje dla mnie. W moim przypadku muszę użyć operacji dzielenia według klauzuli WHERE. Jestem pewien, że nie ma dzielnika zerowego, ponieważ kiedy komentuję GDZIE, nie ma wartości zerowych w wynikach. Ale w jakiś sposób optymalizator kwerendy dzieli przez zero podczas filtrowania. SET ARITHABORT OFF SET i ANSI_WARNINGS OFF robią to - po 2 dniach walki z dzieleniem przez zero przy klauzuli WHERE. Dzięki!
huhu78
2
To „czuje się” tak brudne, ale uwielbiam to! Potrzebowałem go w zapytaniu, które agreguje i używa instrukcji CASE, nie było opcją, ponieważ wtedy musiałem dodać tę kolumnę do GROUP BY, która całkowicie zmieniła wyniki. Uczynienie wstępnego zapytania subselekcją, a następnie wykonanie GROUP BY dla zewnętrznego zapytania również zmienia wyniki, ponieważ występuje podział.
Andrew Steitz
1
OK, więc nadal podoba mi się to „rozwiązanie”, ale jak wielu z was prawdopodobnie czuło, czułem, że musi istnieć „czystszy” sposób. Co się stanie, jeśli zapomnę ponownie włączyć ostrzeżenia? A może ktoś zamaskował mój kod (co się nigdy nie zdarza, prawda?) I nie pomyślał o ostrzeżeniach? W każdym razie widziałem inne odpowiedzi na temat NULLIF (). Wiedziałem o NULLIF (), ale nie zdawałem sobie sprawy, że dzielenie przez NULL zwraca NULL (myślałem, że to błąd). Więc ... Poszedłem z następującymi: ISNULL ((SUM (foo) / NULLIF (SUM (bar), 0)), 0) AS Śr.
Andrew Steitz
2
Nie znałem tego rozwiązania. Nie jestem pewien, czy mi się to podoba, ale kiedyś warto o tym wiedzieć. Dziękuję Ci bardzo.
Henrik Staun Poulsen,
1
Jest to najłatwiejsze rozwiązanie, ale należy pamiętać, że wpłynie to negatywnie na wydajność. Od docs.microsoft.com/en-us/sql/t-sql/statements/… : „Ustawienie WYŁĄCZENIA ARITHABORT może negatywnie wpłynąć na optymalizację zapytań prowadząc do problemów z wydajnością”.
mono blaine
36

Możesz przynajmniej zatrzymać awarię zapytania z błędem i zwrócić, NULLjeśli istnieje podział przez zero:

SELECT a / NULLIF(b, 0) FROM t 

Jednak NIGDY nie przekonwertowałbym tego na zero, coalescetak jak pokazano w innej odpowiedzi, która uzyskała wiele pozytywnych opinii. Jest to całkowicie błędne w sensie matematycznym, a nawet niebezpieczne, ponieważ aplikacja prawdopodobnie zwróci złe i wprowadzające w błąd wyniki.

SQL Police
źródło
32

EDYCJA: Dostaję ostatnio dużo głosów negatywnych na ten temat ... więc pomyślałem, że dodam notatkę, że ta odpowiedź została napisana przed poddaniem pytania jej ostatniej edycji, w której zwracanie wartości null było podświetlone jako opcja .. . które wydaje się bardzo do przyjęcia. Część mojej odpowiedzi dotyczyła takich obaw, jak Edwardo, w komentarzach, które zdawały się opowiadać za zwrotem 0. To był przypadek, któremu się szydziłem.

ODPOWIEDŹ: Wydaje mi się, że kryje się w tym problem podstawowy, polegający na tym, że podział przez 0 jest niezgodny z prawem. Wskazuje to, że coś jest z gruntu nie tak. Jeśli dzielisz przez zero, próbujesz zrobić coś, co nie ma sensu matematycznego, więc żadna odpowiedź liczbowa, którą możesz uzyskać, nie będzie poprawna. (Zastosowanie null w tym przypadku jest uzasadnione, ponieważ nie jest to wartość, która zostanie wykorzystana w późniejszych obliczeniach matematycznych).

Więc Edwardo pyta w komentarzach „a jeśli użytkownik wpisze 0?”, I opowiada się za tym, aby w zamian otrzymać 0. Jeśli użytkownik doda zero do kwoty, a chcesz, aby 0 zwróciło, gdy to zrobi, powinieneś wstawić kod na poziomie reguł biznesowych, aby złapać tę wartość i zwrócić 0 ... nie ma specjalnego przypadku, w którym dzielenie przez 0 = 0.

To subtelna różnica, ale jest ważna ... ponieważ następnym razem ktoś wywoła twoją funkcję i oczekuje, że zrobi to dobrze, i zrobi coś funky, co nie jest poprawne matematycznie, ale obsługuje konkretny przypadek krawędzi duża szansa, że ​​później kogoś ugryziesz. Tak naprawdę nie dzielisz przez 0 ... po prostu odpowiadasz złą odpowiedzią na złe pytanie.

Wyobraź sobie, że coś koduję i spieprzę to. Powinienem odczytywać wartość skalowania pomiaru promieniowania, ale w dziwnym przypadku krawędzi, którego nie spodziewałem, czytam w 0. Następnie upuszczam moją wartość do twojej funkcji ... zwracasz mi 0! Hurra, brak promieniowania! Tyle, że naprawdę tam jest i po prostu przekazywałem złą wartość ... ale nie mam pojęcia. Chcę, aby podział zgłosił błąd, ponieważ to flaga wskazuje, że coś jest nie tak.

Beska
źródło
15
Nie zgadzam się. Twoje reguły biznesowe nigdy nie powinny kończyć się nielegalną matematyką. Jeśli skończysz robić coś takiego, najprawdopodobniej twój model danych jest zły. Ilekroć napotkasz podział przez 0, powinieneś zastanowić się, czy dane powinny mieć wartość NULL zamiast 0.
Remus Rusanu
32
Nie mogę uwierzyć, że zostałem doceniony przez kogoś, kto pyta, czy kiedykolwiek „wykonałem jakieś prawdziwe programowanie?” ponieważ mówię, żeby zrobić to dobrze, a nie leniwie. westchnienie
Beska
11
Przepraszam, nie chciałem cię urazić. Ale pytanie jest całkowicie poprawne w wielu popularnych aplikacjach LOB, a udzielenie odpowiedzi „dzielenie przez 0 jest niezgodne z prawem” nie dodaje wartości IMHO.
Eduardo Molteni,
2
@JackDouglas Right. Jest to przypadek, w którym chcesz, aby reguły biznesowe obsługiwały specjalny przypadek w specjalny sposób ... ale nie powinna to być podstawowa matematyka zwracająca puste miejsce. Powinna to być reguła biznesowa. Zaakceptowana odpowiedź zwraca wartość null, co jest dobrym sposobem na poradzenie sobie z nią. Zgłoszenie wyjątku byłoby również w porządku. Wykrywanie go i obsługa przed przejściem do SQL byłoby prawdopodobnie idealnym rozwiązaniem. Zapewnienie jakiejś funkcji, którą inne rzeczy mogłyby wywołać, która zwróciła matematycznie niepoprawną wartość, nie jest dobrym rozwiązaniem, ponieważ ten szczególny przypadek może nie mieć zastosowania do tych innych wywołujących.
Beska
4
@JackDouglas Tak, to dobre podsumowanie, z którym się zgadzam. Początkowo pytanie wydawało się być sformułowane jako „co mogę zrobić, aby ukryć ten błąd”. Od tego czasu ewoluowało. Zwracając wartość zerową, odpowiedź, do której w końcu dochodzi, wydaje się być jedną rozsądną odpowiedzią. (Zdecydowanie opowiadałem się za tym, aby nie zwracać cyfry 0 lub innej).
Beska
28
SELECT Dividend / ISNULL(NULLIF(Divisor,0), 1) AS Result from table

Łapiąc zero za pomocą nullif (), a następnie wynikowy null za pomocą isnull (), można obejść dzielenie przez błąd zerowy.

Nisarg
źródło
3
Ze względu na jego długość zalecono usunięcie. Pamiętaj, że zawsze lepiej jest dodać małe wyjaśnienie tego, co sugerujesz - nawet jeśli wydaje się to bardzo proste;)
Trinimon
10

Zamiana „dziel przez zero” na zero jest kontrowersyjna - ale nie jest też jedyną opcją. W niektórych przypadkach zastąpienie 1 jest (rozsądnie) właściwe. Często używam

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

kiedy patrzę na zmiany wyników / zliczeń i chcę ustawić domyślnie na 1, jeśli nie mam danych. Na przykład

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

Częściej niż nie, faktycznie obliczałem ten stosunek gdzie indziej (zwłaszcza dlatego, że może on rzucić bardzo duże współczynniki dostosowania dla niskich mianowników. W tym przypadku normalnie kontroluję OldSampleScore jest większy niż próg; co następnie wyklucza zero Ale czasami „hack” jest odpowiedni.

N Mason
źródło
1
@N Mason; tak, czasami 1 jest opcją. Ale jak pamiętasz część ISNULL po wpisaniu odwrotnego ukośnika?
Henrik Staun Poulsen
1
Przepraszam Henrik - nie jestem pewien, czy rozumiem pytanie.
N Mason
6

Jakiś czas temu napisałem funkcję do obsługi jej dla moich procedur przechowywanych :

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
źródło
2
Cześć Ron, Ładne rozwiązanie, z wyjątkiem tego, że ma ograniczony typ danych (4 miejsca po przecinku), a nasi @Divisors mogą być również ujemni. Jak wymuszasz jego użycie? TIA Henrik Staun Poulsen
Henrik Staun Poulsen
1
Zrobiłem to dość szybko, aby poradzić sobie z konkretnym scenariuszem problemu w tym czasie. Pojedyncza aplikacja dla programistów, więc egzekwowanie nie jest tak trudne, z wyjątkiem mojej pamięci. :-)
Ron Savage
5
Pomimo instrukcji print, nie jest to przechowywany proc, to skalarny UDF. To zabije cię w MS-SQL, jeśli jest to część zapytania.
Mark Sowul
4
Zgodziłem się z twierdzeniem Marka Sowula, że ​​funkcja skalarna spowoduje ból. To straszna sugestia w języku T-SQL, nie rób tego! Funkcje skalarne są niszczycielami wydajności! Funkcja wyceniana w tabeli to jedyne dobre funkcje użytkownika w SQL Server (być może z wyjątkiem funkcji CLR, które mogą działać dobrze).
Davos
4
  1. Dodaj ograniczenie CHECK, które zmusza Divisordo bycia niezerową
  2. Dodaj walidator do formularza, aby użytkownik nie mógł wprowadzić zerowych wartości w tym polu.
finnw
źródło
1
Coraz bardziej lubię ograniczenia CHECK.
Henrik Staun Poulsen
4

W przypadku aktualizacji SQL:

update Table1 set Col1 = Col2 / ISNULL(NULLIF(Col3,0),1)
Vijay Bansal
źródło
3
Cześć Vijay, Tak, to zadziała, ale ... Będę ostrożny z częścią ISNULL, w której dzielisz przez NULL. Wolę raczej zasygnalizować użytkownikowi, że wynik jest nieznany, ponieważ dzielnik wynosi zero.
Henrik Staun Poulsen
2
Uratowało mnie to w skomplikowanym podzapytaniu, dzięki.
QMaster
3

Nie ma magicznego globalnego ustawienia „wyłącz podział przez 0 wyjątków”. Operacja musi zostać odrzucona, ponieważ matematyczne znaczenie x / 0 różni się od NULL, więc nie może zwrócić NULL. Zakładam, że zajmujesz się oczywistością, a twoje zapytania mają warunki, które powinny wyeliminować zapisy z dzielnikiem 0 i nigdy nie oceniać podziału. Zwykłe „haczyka” jest niż większość deweloperów spodziewać SQL zachowywać się jak językach proceduralnych i oferują logicznego operatora zwarcie, ale robi NOT . Polecam przeczytanie tego artykułu: http://www.sqlmag.com/Articles/ArticleID/9148/pg/2/2.html

Remus Rusanu
źródło
4
Istnieje takie „magiczne globalne ustawienie”; WYŁĄCZ ARITHABORT.
David Manheim
3

Oto sytuacja, w której możesz podzielić przez zero. Zasadą biznesową jest to, że aby obliczyć obroty zapasów, bierzesz koszt sprzedanych towarów za dany okres, ujmując go rocznie. Po uzyskaniu rocznej liczby dzielisz przez średnią wartość zapasów w danym okresie.

Patrzę na obliczenie liczby zwrotów zapasów, które występują w okresie trzech miesięcy. Obliczyłem, że mam Koszt Towaru sprzedany w okresie trzech miesięcy w wysokości 1000 USD. Roczna stopa sprzedaży wynosi 4000 USD (1000 USD / 3) * 12. Początkowy zapas wynosi 0. Końcowy zapas wynosi 0. Mój średni zapas wynosi teraz 0. Mam sprzedaż 4000 USD rocznie i nie mam zapasów. Daje to nieskończoną liczbę zwojów. Oznacza to, że wszystkie moje zapasy są konwertowane i kupowane przez klientów.

Jest to reguła biznesowa obliczania obrotów zapasów.

Jimmy
źródło
3
Tak, masz wtedy nieskończoną liczbę zwojów. W takim przypadku, jeśli masz dzielenie przez zero, powinieneś pokazać coś takiego jak „#INF”.
SQL Police
1
„Początkowy zapas wynosi 0. Końcowy zapas wynosi 0. Mój średni zapas wynosi teraz 0.” Twoje obliczenia są szacunkowe. W pewnym momencie zapasy są pozytywne lub nie możesz niczego wysłać / sprzedać. Jeśli jesteś niezadowolony z + ∞, użyj lepszego oszacowania średnich zapasów.
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
źródło
Nie podoba mi się twoje rozwiązanie, ponieważ użycie UDF zmusza zapytanie do uruchomienia w trybie pojedynczego wątku. Podoba mi się twoja konfiguracja testowa. Chciałbym mieć to we wszystkich naszych UDF-ach.
Henrik Staun Poulsen
Dla mnie to rozwiązanie jest idealne i eleganckie
Payedimaunt
@Payedimaunt; tak, UDF prowadzą do bardzo eleganckiego kodu. Ale to nie działa dobrze. To „kursory na pigułki nasenne”. :-) Trudno też zapamiętać napisanie dbo. Podziel zamiast zwykłego „/”
Henrik Staun Poulsen
1

Odfiltruj dane za pomocą klauzuli where, aby nie uzyskać 0 wartości.

nunespascal
źródło
1

Czasami 0 może być niewłaściwe, ale czasami 1 również nie jest właściwe. Czasami skok od 0 do 100 000 000, opisany jako zmiana 1 lub 100 procentowa, może również wprowadzać w błąd. W tym scenariuszu odpowiednie może być 100 000 000 procent. To zależy od tego, jakie wnioski zamierzasz wyciągnąć na podstawie wartości procentowych lub współczynników.

Na przykład bardzo sprzedający się przedmiot przechodzący z 2-4 sprzedanych i bardzo sprzedający się przedmiot zmieniający się z 1 000 000 na 2 000 000 sprzedanych może oznaczać bardzo różne rzeczy dla analityka lub kierownictwa, ale oba przyniosą 100% lub 1 zmiana.

Wydzielenie wartości NULL może być łatwiejsze niż przeszukanie wiązki 0% lub 100% wierszy zmieszanych z wiarygodnymi danymi. Często 0 w mianowniku może wskazywać na błąd lub brakującą wartość, i możesz nie chcieć po prostu wpisać dowolnej wartości, aby twój zestaw danych wyglądał schludnie.

CASE
     WHEN [Denominator] = 0
     THEN NULL --or any value or sub case
     ELSE [Numerator]/[Denominator]
END as DivisionProblem
Joeyslaptop
źródło
1
Uważam, że problem polega na tym, aby pamiętać o zrobieniu czegoś, kiedy chcesz dokonać podziału. Jeśli nie pamiętasz dodania CASE lub NULLIF, otrzymasz zgłoszenie do pomocy technicznej za x tygodni w poniedziałek rano. Nienawidzę tego.
Henrik Staun Poulsen
1

Tak to naprawiłem:

IIF (wartość A! = 0, suma / wartość A, 0)

Może być zapakowany w aktualizację:

USTAW Pct = IIF (wartość A! = 0, suma / wartość A, 0)

Lub w wybranych:

WYBIERZ IIF (wartość A! = 0, suma / wartość A, 0) AS Pct FROM Tablename;

Myśli?

CorvetteGuru
źródło
Ja i inni stwierdziliśmy, że zastąpienie „nieznanego” przez zero jest niebezpiecznym rozwiązaniem. Wolę NULL. Ale trudno jest pamiętać o dodaniu iif lub nullif do wszystkich dywizji!
Henrik Staun Poulsen
0

Możesz odpowiednio obsłużyć błąd, gdy propaguje się z powrotem do programu wywołującego (lub zignoruj ​​go, jeśli tego chcesz). W języku C # wszelkie błędy występujące w SQL spowodują zgłoszenie wyjątku, który mogę przechwycić, a następnie obsłużyć mój kod, tak jak każdy inny błąd.

Zgadzam się z Beską, że nie chcesz ukryć błędu. Być może nie masz do czynienia z reaktorem jądrowym, ale ukrywanie błędów ogólnie jest złą praktyką programistyczną. Jest to jeden z powodów, dla których większość współczesnych języków programowania implementuje ustrukturyzowaną obsługę wyjątków w celu oddzielenia rzeczywistej wartości zwracanej za pomocą kodu błędu / statusu. Jest to szczególnie prawdziwe, gdy robisz matematykę. Największym problemem jest to, że nie można odróżnić zwracanego poprawnie 0 od 0 w wyniku błędu. Zamiast tego każda zwracana wartość jest wartością obliczoną, a jeśli coś pójdzie nie tak, zgłaszany jest wyjątek. To oczywiście będzie się różnić w zależności od tego, w jaki sposób uzyskujesz dostęp do bazy danych i jakiego języka używasz, ale zawsze powinieneś mieć komunikat o błędzie, z którym możesz sobie poradzić.

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
źródło
1
Myślę, że wszyscy się zgadzamy, że ukrywanie błędu za pomocą 0 nie jest rozwiązaniem. Proponuję napisać nasz kod w taki sposób, aby po każdym „/” następował „NULLIF”. W ten sposób mój raport / reaktor jądrowy nie jest pozostawiony samemu sobie, ale pokazuje „NULL” zamiast tego nieznośnego błędu Msg 8134. Oczywiście, jeśli potrzebuję innego procesu, gdy dzielnik wynosi 0, to Beska i ja zgadzamy się. Musimy to zakodować. Trudno to zrobić za każdym razem, gdy piszesz „/”. „/ NULLIF” nie jest niemożliwe za każdym razem.
Henrik Staun Poulsen
0

Użyj, NULLIF(exp,0)ale w ten sposób -NULLIF(ISNULL(exp,0),0)

NULLIF(exp,0)psuje się, jeśli exp jest, nullale NULLIF(ISNULL(exp,0),0)nie psuje się

Johnny Kancharla
źródło
1
Nie mogę uzyskać wartości NULLIF (exp, 0), jeśli 0 to zero, a nie o. Próbować; ZADEKLARUJ @i INT WYBIERZ 1 / NULLIF (@i, 0), aby sprawdzić, czy możesz go złamać.
Henrik Staun Poulsen