Изменения

Перейти к: навигация, поиск

Неполные данные и null

4793 байта добавлено, 05:15, 23 декабря 2021
м
DML
* Результаты множественных операций
Оказывается, что в некоторых случаях без null не обойтись и надо уметь с ним работать.
== Операции Тернарная логика с использованием null ===== Тернарная логика ===
С точки зрения SQL, результат логического выражения может быть ''true'', ''false'' или ''unknown''.<br>
С другой стороны есть тип ''boolean'', и у него есть 3 значения: ''true'', ''false'' и '''''null''''' <br>
То есть формально ''unknown'' - это результат вычисления, а '''''null''''' - это конкретное значение, которое может быть записано в БД. На практике ''unknown'' представляется значением '''''null''''', и это различие не будет иметь большого значения.
==== Логические операции ========= Конъюнкция =====
{| style="background-color:#CCC;margin:0.5px;text-align:center"
!style="background-color:#EEE;color:#00F"| <tex>\bf{and}</tex>
|}
===== Дизъюнкция =====
{| style="background-color:#CCC;margin:0.5px;text-align:center"
!style="background-color:#EEE;color:#00F"| <tex>\bf{or}</tex>
|}
===== Отрицание =====
{| style="background-color:#CCC;margin:0.5px;text-align:center"
!style="background-color:#EEE;color:#00F"| <tex></tex>
|}
=== Сравнение ====== Импликация =====TODO: уточнить* A → B = (not A) or B{| style="background-color:#CCC;margin-left:2rem0.5px;text-align:center"!style="background-color:#EEE;color:#00F"| <tex>\bf{(not\ A)\ or\ B=}</tex>
!style="background-color:#EEE"| <tex>\bf{true}</tex>
!style="background-color:#EEE"| <tex>\bf{unknown}</tex>
|-
|style="background-color:#EEE;padding:2px 30px"| <tex>\bf{unknown}</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>trueunknown</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>unknown</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>unknown</tex>
|-
|style="background-color:#EEE;padding:2px 30px"| <tex>\bf{false}</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>truefalse</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>trueunknown</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|}
* A → B = not (A and not B)=== is ===={| style="background-color:#CCC;margin-left:2rem0.5px;text-align:center"!style="background-color:#EEE;color:#00F"| <tex>\bf{not\ (A\ and\ not\ B)}</tex>
!style="background-color:#EEE"| <tex>\bf{true}</tex>
!style="background-color:#EEE"| <tex>\bf{unknown}</tex>
!style="background-color:#EEE"| <tex>\bf{false}</tex>
|-
|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ true}</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>|-|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ unknown}</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>unknown</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>
|-
|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ false}</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>|-|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{unknownis\ not\ true}</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>unknown</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>unknown</tex>
|-
|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{falseis\ not\ unknown}</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|-
|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ not\ false}</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>
|}
Оказывается что законы Де Моргана в данном случае == Проблемы при работе с null ==При работе с '''не работаютnull'''в процессе разработки БД, во избежание непредвиденных ошибок, необъодимо заранее ознакомиться с тем, какие проблемы могут возникнуть. ==== Сравнение =Неоднозначность импликации ==='''TODO: уточнить'''* A → B ===== = =====(not A) or B{| style="background-color:#CCC;margin-left:0.5px2rem;text-align:center"!style="background-color:#EEE;color:#00F"| <tex>\bf{=(not\ A)\ or\ B}</tex>
!style="background-color:#EEE"| <tex>\bf{true}</tex>
!style="background-color:#EEE"| <tex>\bf{unknown}</tex>
|-
|style="background-color:#EEE;padding:2px 30px"| <tex>\bf{unknown}</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>unknowntrue</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>unknown</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>unknown</tex>
|-
|style="background-color:#EEE;padding:2px 30px"| <tex>\bf{false}</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>falsetrue</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>unknowntrue</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|}
* A → B ===== is =====not (A and not B){| style="background-color:#CCC;margin-left:0.5px2rem;text-align:center"!style="background-color:#EEE;color:#00F"| <tex>\bf{not\ (A\ and\ not\ B)}</tex>
!style="background-color:#EEE"| <tex>\bf{true}</tex>
!style="background-color:#EEE"| <tex>\bf{unknown}</tex>
!style="background-color:#EEE"| <tex>\bf{false}</tex>
|-
|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ true}</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>falseunknown</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>
|-
|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ unknown}</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>falseunknown</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>unknown</tex>
|-
|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ false}</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>|-|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ not\ true}</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>|-|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ not\ unknown}</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|-
|style="background-color:#EEE;color:#00F;;padding:2px 30px"| <tex>\bf{is\ not\ false}</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>true</tex>
|style="background-color:#FFF;padding:2px 30px"| <tex>false</tex>
|}
==== Скалярные операции ====Чтобы работа с '''nullОказывается что законы Де Моргана в данном случае ''' не приводила к непреднамеренным ошибкам полезно знать, что работают'''null''' "заразен".<br>Например=== Скалярные операции, следующие порождающие null ===Следующие операции с '''null''' порождают '''null''' , и иногда это может сбивать с толку начинающих разработчиков.
* =, <>, <, <=, >, >=
* +, −, *, /
* ||
* in Рассмотрим несколько примеров. <font color = blue>select</font> (1 + <font color = blue>null</font>) <font color = blue>from</font> Students;Не смотря на то, что этот запрос не несет большого смысла, на его примере можно убедиться, что в арифметических операциях '''null''in'''(true, false, "заразен".<br>  <font color = blue>select</font> StudentId <font color = blue>from</font> Students where GroupId = null)'' не дает нужного эффекта;Это частая ошибка, т.к. сравнение с '''''null''' попродит ''дает 'null'unknown''), а значит запрос вернет пустую таблицу.<br>
===== coalesce(v1Говоря об операции сравнения, v2стоит отметить, что она не транзитивна и не рефлексивна...) ====* <tex>x\ =\ x</tex> - ''true'' или '''''null'''''* <tex>x\ <>\ x</tex> - ''true'' или '''''null'''''* Принимает произвольное число аргументов и возвращает первый не <tex>x\ or\ x</tex> - ''true'' или '''''null'''''* Если все аргументы <tex>x\ or\ not\ x</tex> - ''true'' или '''''null '''''* <tex>x\ and\ not\ x</tex> - возвращает ''false'' или '''''null'''''
=== Дубликаты и null ===
Так как null ≠ null, сравнения кортежей, содержащих null не обладают интуитивными свойствами, например:
* ''<tex>R \cup R'' </tex> - не всегда <tex>R </tex> * ''<tex>R \cap R'' </tex> - не всегда <tex>R</tex> * ''<tex>R \bowtie R'' </tex> - не всегда <tex>R</tex>
=== Спецэффекты Неинтуитивность null ===При детальном рассмотренииРассмотрим запрос, оказывается, что сравнение для нахождения студентов не транзитивно и не рефлексивноиз группы 'M34391'. <font color = blue>select</font> * <font color = blue>from</font> Students <font color = blue>where</font> GroupId <> <font color = green>'M34391'</font>Корректность запроса зависит от смысла 'x = x'' - true или null'''. Неясно, надо ли возвращать в этом запросе студента, о котором нет информации, в какой группе он учится. Следующий запрос, хоть и выглядит странно, предполагает просто поиск всевозможных студентов <font color = blue>select</font> * <font color = blue>from</font> Students <font color = blue>where</font> GroupId <> <font color = green>'M34391'x </font> <font color = blue>union</font> <font color = blue>select</font> * <font color = blue>from</font> Students <font color = blue>where</font> GroupId = <font color = green> x'M34391' </font>Но из- за наличия '''null''', этот запрос не отработает так, как предполагалось. Если ''GroupId'' студента '''''null''''', то сравнение не вернет ''true или '', а значит в результате это учтено не будет. <br>Подробнее у работе функции <font color = blue>where</font> будет рассказано в следующем разделе. == Работа с null в SQL ==Несмотря на множество проблем, описанных выше, в SQL существуют механизмы, позволяющие корректно обработать '''null'''.* === Проверки значений ===Для сравнения с '''x or xnull''' - true используется <font color = blue>is null</font> (или <font color = blue>is not null</font>).* Получить всех студентов с '''''null''''' в поле ''GroupId''можно следующим образом: <font color = blue>select</font> StudentId <font color = blue>from</font> Students <font color = blue>where</font> GroupId <font color = blue>is null</font>;В общем виде синтаксис проверки значений выглядит следующим образом:<font color = red>значение</font> <font color = blue>is</font> <font color = red>[</font><font color = blue>not</font><font color = red>]</font> <font color = red>{</font><font color = blue>null</font>|true|false|unknown<font color = red>}</font>, например:* x <font color = blue>is not</font> true* x <font color = blue>or </font> x <font color = blue>is not xnull</font> Так же в SQL существует функция '''''coalesce(v1, v2, ...)''''', которая принимает произвольное число аргументов и возвращает первый не '''не null'''. Если все аргументы ''' - true или null* ''x and not x', то возвращает ''' - false или null'''.
=== Ключи и null ===
'''Первичные ключи не могут содержать null.'''
== Неинтуитивность null ==
=== Студенты, учащиеся в группе M34391 ===
<font color = blue>select</font> * <font color = blue>from</font> Students <font color = blue>where</font> GroupId <> <font color = green>'M34391'</font>
Корректность запроса зависит от смысла '''null'''. Неясно, надо ли возвращать в этом запросе студента, о котором нет информации, в какой группе он учится.
 
=== Поиск всех студентов ===
<font color = blue>select</font> * <font color = blue>from</font> Students <font color = blue>where</font> GroupId <> <font color = green>'M34391'</font>
<font color = blue>union</font>
<font color = blue>select</font> * <font color = blue>from</font> Students <font color = blue>where</font> GroupId <> <font color = green>'M34391'</font>
Из-за наличия '''null''', этот запрос не отработает так, как предполагалось.
 
== Null и SQL ==
=== Предикаты ===
==== DML ====
<font color = blue>where</font> и <font color = blue>having</font> считают истинным предикат '''только если он вернул ''true'''''
Зная этот факт можно, например убедиться, что ''false'' <font color = blue>and</font> ''unknown'' дает ''false''. Следующий запрос вернет 1:
<font color = blue>select</font> 1 <font color = blue>where not</font> (0 = 1 <font color = blue>and</font> 0 = <font color = blue>null</font>)
 
==== DDL ====
C точки зрения <font color = blue>check</font> constraint-ов не подходит только ''false''. ''Unknown'' превращается в ''true''
=== Типы столбцов ===
* В SQL столбцы могут быть <font color = blue>nullable</font> (по умолчанию)** и не <font color = grayblue>birthday datenullable</font>* <font color = blue>Не nullablebirthday date</font>** <font color = gray>birthday date</font> <font color = blue>not null</font>
Перед созданием <font color === Проверки значений ======= Синтаксис ====*значение is [not] {null|true|false|unknown}==== Примеры ====* x is blue>nullable</font> столбца, рекомендуется дополнительно обдумать, какой конкретно смысл вкладывается в '''null* x is not true* (x or x) is ''' в данном случае, не скажется ли это негативно на остальных запросах, в случае, если начать его использовать. Если есть возможность, во избежание дополнительных проблем, описанных выше, лучше объявлять столбцы '''not null'''.
=== Прочее ===
* <font color = blue>exists</font>** возвращает ''true'' или 'false'** если внутри получились только строки, Агрегирующие состоящие из '''null''', то вернет так же ''false''* агрегирующие функции(<font color = blue>count</font>, <font color = blue>sum</font>, <font color = blue>avg</font> и т.д.)** пропускают '''''null''''', т.е. не учитывают его при подсчете** при отсутствии аргументов, Order отличных от '''''null''''', возвращают '''''null'''''** исключением является <font color = blue>count</font>(*), что просто считает количество строк* <font color = blue>order by</font>** Помимо указаний порядка сортировки (asc или desc), можно указывать, куда ставить '''''null'''-ы'' - в начало или в конец. Например <font color = blue>order by</font> year nulls first. По умолчанию '''''null'''-ы'' складываются либо в начало, либо в конец, это нужно уточнять в документации к конкретной СУБД.
71
правка

Навигация