Уникайте ділення на нуль у PostgreSQL


80

Я хотів би виконати поділ у реченні SELECT. Коли я приєднуюсь до деяких таблиць і використовую агрегатну функцію, я часто маю значення нуля або нуля як дільники. На даний момент я придумав лише цей метод, щоб уникнути ділення на нульові та нульові значення.

(CASE(COALESCE(COUNT(column_name),1)) WHEN 0 THEN 1
ELSE (COALESCE(COUNT(column_name),1)) END) 

Цікаво, чи є кращий спосіб зробити це?


4
Поділ на нульове значення не є проблемою, оскільки ділення на нуль є. До речі, count () ніколи не повертає null.
Девід Олдрідж,

Я цього не знав! дякую за інформацію.
William Wino

Відповіді:


44

Оскільки count()ніколи не повертаєтьсяNULL (на відміну від інших сукупних функцій), вам потрібно лише впіймати 0справу (що є єдиним проблемним випадком):

CASE count(column_name)
   WHEN 0 THEN 1
   ELSE count(column_name)
END

Цитуючи посібник про сукупні функції:

Слід зазначити, що за винятком count, ці функції повертають нульове значення, коли не вибрано жодного рядка.


223

Ви можете використовувати функцію NULLIF, наприклад

something/NULLIF(column_name,0)

Якщо значення column_name0 - результат усього виразу буде НУЛЬНИМ


16
щось на зразок value / COALESCE (NULLIF (ім'я_столбця, 0), 1) буде працювати, я гадаю
Akash

Спробував з COALESCE, як запропонував @Akash, і це зробило
abd

3
Це ідеально семантичне рішення багатьох задач на ділення на нуль! Іноді ви не хочете, щоб ділення було якимсь іншим значенням, ви хочете, щоб воно взагалі не обчислювалося!
LeoRochael

40

Я усвідомлюю, що це давнє запитання, але іншим рішенням буде використання найбільшої функції:

greatest( count(column_name), 1 )  -- NULL and 0 are valid argument values

Примітка: Моєю перевагою було б або повернути NULL, як у відповіді Ервіна та Юрія, або вирішити це логічно, виявивши значення 0перед операцією поділу та повернувшись 0. В іншому випадку дані можуть бути неправильно представлені за допомогою 1.


Я збираюся використати це, оскільки мій дільник - це "минулий час" для процесу, і 0, ймовірно, означає частку секунди, тому я буду використовувати 0,01 хвилини як час за замовчуванням. Я лише порівнюю продуктивність процесу.
PhilHibbs

Для мене це було найпростіше рішення з точки зору читабельності
Флоран Дестремау,

5

Інше рішення - уникнення ділення на нуль, заміни на 1

select column + (column = 0)::integer;

Це справді розумно.
lightyrs

3

Якщо ви хочете, щоб дільник становив 1, коли відлік дорівнює нулю:

count(column_name) + 1 * (count(column_name) = 0)::integer

Акторський склад з trueдо integer- 1.


Хороший фокус, але я думаю, що виклад справи може бути більш очевидним.
Девід Олдрідж,

CASEтакож швидше, навіть якщо багатослівніше.
Erwin Brandstetter
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.