У меня есть это сообщение об ошибке:
Msg 8134, Уровень 16, Состояние 1, Строка 1 При обнаружении ошибки деления на ноль.
Каков наилучший способ написания кода SQL, чтобы я больше никогда не видел это сообщение об ошибке?
Я мог бы сделать одно из следующего:
- Добавьте предложение where, чтобы мой делитель никогда не был равен нулю
Или
- Я мог бы добавить описание случая, чтобы был специальный режим для нуля.
Это лучший способ использовать NULLIF
предложение?
Есть ли лучший способ, или как это можно осуществить?
sql
sql-server
sql-server-2005
sql-server-2008
Хенрик Стаун Поулсен
источник
источник
Ответы:
Чтобы избежать ошибки «Деление на ноль», мы запрограммировали ее так:
Но вот гораздо лучший способ сделать это:
Теперь единственная проблема - вспомнить бит NullIf, если я использую клавишу "/".
источник
IsNull
вместоNullIf
? Попробуй сам!SELECT Value,1/NullIf(Value,0)FROM(VALUES(0),(5.0),(NULL))x(Value);
Если вы не имеете в виду "breaks", вы подразумеваете, что возвращает NULL? Вы можете преобразовать это в то, что вы хотите с помощьюIsNull
илиCoalesce
.SELECT 1 / NULLIF(NULL, 0)
не удается, но это потому, чтоNULLIF()
нужно знать тип данных первого аргумента. Это измененный пример работает нормально:SELECT 1 / NULLIF(CAST(NULL AS INT), 0)
. В реальной жизни вы собираетесь указывать столбец таблицы,NULLIF()
а неNULL
константу. Поскольку столбцы таблицы имеют известные типы данных, это также работает отлично:SELECT 1 / NULLIF(SomeNullableColumn, 0) FROM SomeTable
.Если вы хотите вернуть ноль, в случае возникновения нулевого отклонения, вы можете использовать:
Для каждого делителя, равного нулю, вы получите ноль в наборе результатов.
источник
Это казалось лучшим решением для моей ситуации, когда я пытался решить проблему деления на ноль, что происходит в моих данных.
Предположим, вы хотите вычислить соотношение мужчин и женщин для различных школьных клубов, но обнаруживаете, что следующий запрос не выполняется и выдает ошибку деления на ноль, когда он пытается вычислить соотношение для клуба Властелина колец, в котором нет женщин :
Вы можете использовать функцию,
NULLIF
чтобы избежать деления на ноль.NULLIF
сравнивает два выражения и возвращает ноль, если они равны, или первое выражение в противном случае.Перепишите запрос как:
Любое число, разделенное на число,
NULL
даетNULL
ошибку.источник
select males/(males+females), females/(males+females)
. Это даст вам процентное соотношение мужчин и женщин в клубе, например, 31% мужчин, 69% женщин.Вы также можете сделать это в начале запроса:
Так что если у вас есть что-то подобное,
100/0
он вернет NULL. Я сделал это только для простых запросов, поэтому я не знаю, как это повлияет на более длинные / сложные запросы.источник
Вы можете, по крайней мере, остановить прерывание запроса с ошибкой и вернуть,
NULL
если есть деление на ноль:Тем не менее, я бы НИКОГДА не конвертировал это в ноль,
coalesce
как показано в другом ответе, получившем много голосов. Это совершенно неверно в математическом смысле и даже опасно, поскольку ваше приложение, скорее всего, даст неверные и вводящие в заблуждение результаты.источник
РЕДАКТИРОВАТЬ: я получил много отрицательных отзывов об этом в последнее время ... так что я решил добавить примечание, что этот ответ был написан до того, как вопрос подвергся его последнему редактированию, где возвращаемый ноль был выделен как опция ... что кажется очень приемлемым. Некоторые из моих ответов были адресованы таким же проблемам, как и Эдвардо, в комментариях, которые, казалось, выступали за возвращение 0. Это случай, против которого я выступал.
ОТВЕТ: Я думаю, что здесь есть основная проблема, которая заключается в том, что деление на 0 не является законным. Это признак того, что что-то в корне неправильно. Если вы делите на ноль, вы пытаетесь сделать что-то, что не имеет смысла математически, поэтому никакой числовой ответ, который вы можете получить, не будет действительным. (Использование null в этом случае является разумным, поскольку это не значение, которое будет использоваться в последующих математических вычислениях).
Таким образом, Эдвардо спрашивает в комментариях «что если пользователь введет 0?», И он настаивает на том, что все должно быть в порядке, чтобы получить 0 взамен. Если пользователь помещает ноль в сумму, и вы хотите, чтобы 0 возвращалось, когда они это делают, то вам нужно вставить код на уровне бизнес-правил, чтобы перехватить это значение и вернуть 0 ... не должно быть какого-то особого случая, когда деление на 0 = 0.
Это небольшая разница, но это важно ... потому что в следующий раз, когда кто-то вызовет вашу функцию и ожидает, что она будет делать правильные вещи, и она сделает что-то напуганное, что математически не правильно, но просто обрабатывает конкретный крайний случай, когда у него есть хороший шанс укусить кого-нибудь позже. Вы на самом деле не делите на 0 ... вы просто возвращаете плохой ответ на плохой вопрос.
Представь, что я что-то кодирую, и я облажался. Я должен был прочитать значение масштабирования измерения радиации, но в странном граничном случае я не ожидал, я прочитал в 0. Затем я опускаю свое значение в вашу функцию ... вы возвращаете мне 0! Ура, нет излучения! За исключением того, что это действительно там, и это просто, что я передал плохую ценность ... но я понятия не имею. Я хочу, чтобы подразделение выдавало ошибку, потому что это признак того, что что-то не так.
источник
Улавливая ноль с помощью nullif (), затем полученное значение null с помощью isnull () вы можете обойти деление на ноль ошибок.
источник
Замена «делить на ноль» на ноль противоречива, но это не единственный вариант. В некоторых случаях замена на 1 является (разумно) целесообразной. Я часто использую
когда я смотрю на сдвиги в счетах / счетчиках и хочу по умолчанию 1, если у меня нет данных. Например
Чаще всего я фактически вычислял это соотношение где-то еще (не в последнюю очередь потому, что оно может генерировать очень большие поправочные коэффициенты для низких знаменателей. В этом случае я обычно контролирую для OldSampleScore больше порога, который затем исключает ноль Но иногда «взлом» уместен.
источник
Некоторое время назад я написал функцию для обработки хранимых процедур :
источник
Divisor
быть ненулевымисточник
Для обновления SQL:
источник
Не существует волшебной глобальной настройки «отключить деление на 0 исключений». Операция должна сгенерировать, так как математическое значение x / 0 отличается от значения NULL, поэтому оно не может возвращать NULL. Я предполагаю, что вы заботитесь об очевидном, и ваши запросы имеют условия, которые должны исключать записи с делителем 0 и никогда не оценивать деление. Обычная «ошибка» заключается в том, что большинство разработчиков ожидают, что SQL будет вести себя как процедурные языки, и предлагают логическое замыкание оператора, но это НЕ . Я рекомендую вам прочитать эту статью: http://www.sqlmag.com/Articles/ArticleID/9148/pg/2/2.html
источник
Вот ситуация, когда вы можете разделить на ноль. Бизнес-правило заключается в том, что для расчета оборачиваемости запасов вы берете стоимость проданных товаров за период, а затем переводите в год. После того, как у вас есть годовое число, вы делите на средний запас за период.
Я смотрю на подсчет количества оборотов инвентаря, которые происходят за три месяца. Я подсчитал, что у меня есть стоимость товаров, проданных за трехмесячный период, в размере 1000 долларов. Годовой уровень продаж составляет 4000 долларов США (1000 долларов США / 3) * 12. Начальный инвентарь равен 0. Конечный инвентарь равен 0. Мой средний запас равен 0. У меня продажи 4000 долларов в год, и нет запасов. Это дает бесконечное количество ходов. Это означает, что весь мой инвентарь конвертируется и покупается клиентами.
Это бизнес-правило для расчета оборотов запасов.
источник
источник
Отфильтруйте данные с помощью предложения where, чтобы не получить 0 значений.
источник
Иногда 0 может не подходить, но иногда 1 также не подходит. Иногда скачок от 0 до 100 000 000, описываемый как 1 или 100-процентное изменение, также может вводить в заблуждение. 100 000 000 процентов могут быть уместны в этом сценарии. Это зависит от того, какие выводы вы намереваетесь сделать, основываясь на процентах или соотношениях.
Например, очень мелко продаваемый товар с 2-4 проданными и очень крупно продаваемый предмет с 1 000 000 до 2 000 000 проданных товаров может означать совершенно разные вещи для аналитика или для руководства, но оба будут иметь значение 100% или 1 изменение.
Возможно, будет проще изолировать значения NULL, чем просматривать группы из 0% или 100% строк, смешанных с допустимыми данными. Зачастую 0 в знаменателе может указывать на ошибку или пропущенное значение, и вы можете не захотеть просто заполнять произвольное значение только для того, чтобы ваш набор данных выглядел аккуратно.
источник
Вот как я это исправил:
IIF (ValueA! = 0, Total / ValueA, 0)
Это может быть включено в обновление:
SET Pct = IIF (ValueA! = 0, Total / ValueA, 0)
Или в избранном:
ВЫБЕРИТЕ IIF (ValueA! = 0, Total / ValueA, 0) AS Pct FROM Tablename;
Мысли?
источник
Вы можете соответствующим образом обработать ошибку, когда она распространяется обратно в вызывающую программу (или игнорировать ее, если вы этого хотите). В C # любые ошибки, возникающие в SQL, выдают исключение, которое я могу перехватить, а затем обработать в своем коде, как и любую другую ошибку.
Я согласен с Беской в том, что вы не хотите скрывать ошибку. Возможно, вы не имеете дело с ядерным реактором, но в целом сокрытие ошибок - плохая практика программирования. Это одна из причин, по которой большинство современных языков программирования реализуют структурированную обработку исключений, чтобы отделить фактическое возвращаемое значение от кода ошибки / состояния. Это особенно верно, когда вы занимаетесь математикой. Самая большая проблема заключается в том, что вы не можете различить возвращаемый правильно 0 или 0 в результате ошибки. Вместо этого любое возвращаемое значение является вычисленным значением, и если что-то идет не так, генерируется исключение. Конечно, это будет отличаться в зависимости от того, как вы обращаетесь к базе данных и на каком языке вы пользуетесь, но вы всегда должны получать сообщение об ошибке, с которым вы можете иметь дело.
источник
Используйте,
NULLIF(exp,0)
но таким образом -NULLIF(ISNULL(exp,0),0)
NULLIF(exp,0)
ломается, если exp есть,null
ноNULLIF(ISNULL(exp,0),0)
не сломаетсяисточник