Сравнение с нулевым поведением? - PullRequest
0 голосов
/ 17 апреля 2020

В недавнем обзоре кода меня попросили изменить

Amount > 0

на

ISNULL(Amount,0) > 0

Есть ли вероятность того, что эти результаты могут исправить разные результаты? Из того, что я могу сказать, они оба возвращали бы false, если Amount равна нулю или 0 и true в любом другом случае

Чтобы дать дополнительную информацию, я хочу получить все строки в одной таблице, если они этого не делают. иметь соответствующую строку во второй таблице с суммой> 0

-- Get members that do not have unpaid fees
Select m.Name from Members m
left join Fees f on m.Id = F.memberId and F.AmountDue > 0
where F.memberId is null

Ответы [ 2 ]

2 голосов
/ 17 апреля 2020

amount > 0 проверяет, является ли amount строгостью, превышающей 0. Если значение равно NULL, условие возвращает unknown (что не true, а фактически отличное от false) ..

ISNULL(amount, 0) > 0 делает то же самое. NULL значения превращаются в 0, что также не проходит проверку - однако в этом случае вместо unknown возвращается false.

В зависимости от того, что вы хотите сделать с результатом условие, оба условия могут или не могут вести себя одинаково. Например, если вы используете это в предложении where, заметной разницы нет. Однако второе условие менее эффективно, поскольку требует дополнительных вычислений и, скорее всего, не сможет воспользоваться существующим индексом для amount, если таковой имеется.

0 голосов
/ 17 апреля 2020

Сравнение чего-либо со значением NULL приводит к НЕИЗВЕСТНОМУ, а не ЛОЖНОМУ.

По сути, это имеет тот же эффект, что и возвращение false, в том, что запрос будет возвращать только те строки, где сумма не равна нулю и больше 0, но вы должны быть осторожны, чтобы не предполагать, что когда сумма равна нулю, результат сравнение ложно

Например, при этом также не будут возвращаться пустые строки:

WHERE NOT(amount > 0) 

amount > 0 НЕИЗВЕСТНО, а НЕ ЛОЖНО. Если бы это было ложно, то НЕ могло бы сделать это истинным

Вы могли бы себе представить, что NULL - это загрязняющий агент, который проходит весь путь через все логические условия и операции, к которым он прикасается, поворачивая их все НЕИЗВЕСТНО и затем «становится ложным» прямо в самый последний момент, потому что последний оценщик логического предиката требует ИСТИНА

В целом, вы можете считать НЕИЗВЕСТНЫЙ синонимом ПУСТОГО; UNKNOWN относительно ограничен логическими логиками c. В других контекстах, таких как математические операции с участием NULL, результат равен нулю (0 + NULL = NULL). Единственная операция, которая может работать со значением NULL и создавать логическое значение, - это amount IS [NOT] NULL


В соответствии с вашим обзором кода, если они собираются настаивать на общем покрытии, «необходимо объединить любое значение, которое может быть нулевым» Может показаться, что бизнес-правило состоит в том, что система не допускает значений NULL - в этом случае должно быть, что столбец сделан не NULL и заполнен только фактическими значениями. Передача любого значения через функцию, которая может изменить или не изменить его, ограничивает использование индексов и создает проблемы для планирования запросов. Можно надеяться, что умный оптимизатор сможет расширить / переписать ISNULL(amount, 0) > 0 до amount > 0 or (amount is null and 0>0), прежде чем упростить полностью удалить условие в скобках, но это не всегда так просто. Лучше не вводить дерьмо, во-первых, чем пожимание плечами и go «ну, в моем простом тестовом примере это, кажется, не делает вещи медленнее»

Применение общего правила без какой-либо мысли или оправдания может привести к очень плохо работающей системе. То, как вы будете передавать это людям, которые создают правила, может быть затруднительно с офисной политикой c, поскольку их подход неверен, но они вряд ли признают это или хотят, чтобы им говорили


Кроме того, вы можете почувствовать, что эквивалентный запрос лучше отражает представление о том, что вы пытаетесь сделать:

SELECT m.Name 
FROM Members m
WHERE NOT EXISTS(
  SELECT 1 
  FROM Fees f 
  WHERE m.Id = F.memberId and F.AmountDue > 0
)

Левый шаблон анти-объединения является моим любимым для всех видов, но я делаю чувствую, что это больше говорит само за себя - «все участники, которые не имеют связанных записей, где они должны деньги». NOT IN также делает это вполне читабельным, но его следует использовать с осторожностью, так как некоторые реализации базы данных могут быть довольно наивными:

SELECT m.Name 
FROM Members m
WHERE NOT IN (
  SELECT F.MemberId 
  FROM Fees f 
  WHERE F.AmountDue > 0
)

SQL сервер с большой вероятностью перепишет LEFT JOIN WHERE NULL / WHERE NOT EXISTS / WHERE NOT IN, поэтому они планируются и выполняются одинаково, но вы можете обнаружить, что в этом / dim представлении о подходе IN к следующему обзору кода не так много внимания:)

...