Базы данных и язык SQL - Лекция 2

Страница создана Фёдор Морозов
 
ПРОДОЛЖИТЬ ЧТЕНИЕ
Базы данных
и язык SQL
   Лекция 2
Нормализация и нормальные формы
  Нормальная форма — требование, предъявляемое к
структуре таблиц в теории реляционных баз данных для
устранения    из   базы    избыточных     функциональных
зависимостей между атрибутами (полями таблиц).
  Процесс преобразования отношений базы данных к виду,
отвечающему       нормальным        формам,    называется
нормализацией. Нормализация предназначена для приведения
структуры БД к виду, обеспечивающему минимальную
логическую избыточность, и не имеет целью уменьшение или
увеличение производительности работы или же уменьшение
или увеличение физического объёма базы данных. Конечной
целью нормализации является уменьшение потенциальной
противоречивости хранимой в базе данных информации.
1NF
Переменная отношения находится в первой нормальной форме (1NF)
тогда и только тогда, когда каждое из значений его полей атомарно.
Исходная ненормализованная (то                               Номер
есть не являющаяся правильным               Сотрудник
                                                           телефона
представлением некоторого отношения)                     283-56-82
                                           Иванов И. И.
таблица:                                                 390-57-34
                                         Петров П. П.     708-62-34

Таблица, приведённая к 1NF
(являющаяся правильным                           Номер
                                Сотрудник
                                               телефона
представлением некоторого
                              Иванов И. И.    283-56-82
отношения):
                              Иванов И. И.    390-57-34
                              Петров П. П.    708-62-34
2NF
    Для второй нормальной формы (2NF) таблица должна находиться в первой
нормальной форме. Любое её поле, не входящее в состав первичного ключа,
функционально полно должно зависеть от первичного ключа.
    Например, пусть в следующем отношении первичный ключ образует пара
атрибутов {Сотрудник, Должность}:
              Сотрудник      Должность      Зарплата    Наличие компьютера
             Гришин        Кладовщик       20000       Нет
             Васильев      Программист     40000       Есть
             Иванов        Кладовщик       25000       Нет

     Зарплату сотруднику каждый начальник устанавливает сам (хотя её границы
зависят от должности). Наличие же компьютера у сотрудника зависит только от
должности, то есть зависимость от первичного ключа неполная. В результате
приведения к 2NF исходное отношение следует декомпозировать (логически
разбить) на два отношения:
 Сотрудник     Должность        Зарплата                                 Наличие
                                                         Должность
                                                                       компьютера
Гришин       Кладовщик       20000
                                                       Кладовщик     Нет
Васильев     Программист     40000
                                                       Программист   Есть
Иванов       Кладовщик       25000
3NF
     Для третьей нормальной формы (3NF) таблица должна находиться во второй
нормальной форме. Любой её не ключевой атрибут функционально зависит только от
первичного ключа.
     Рассмотрим в качестве примера отношение, которое находится во 2NF, но не
соответствует 3NF.
                        Сотрудник          Отдел              Телефон
                       Гришин         Бухгалтерия           11-22-33
                       Васильев       Бухгалтерия           11-22-33
                       Петров         Снабжение             44-55-66
     В отношении атрибут «Сотрудник» является первичным ключом. Личных телефонов у
сотрудников нет, и телефон сотрудника зависит исключительно от отдела.
     Таким образом, в отношении существуют следующие функциональные зависимости:
Сотрудник → Отдел, Отдел → Телефон, Сотрудник → Телефон. Зависимость Сотрудник →
Телефон является побочной, следовательно, отношение не находится в 3NF. В результате
разделения отношения получаются два отношения, находящиеся в 3NF:

           Отдел           Телефон                  Сотрудник               Отдел

    Бухгалтерия         11-22-33                   Гришин              Бухгалтерия

    Снабжение           44-55-66                   Васильев            Бухгалтерия
                                                   Петров              Снабжение
SQL. NULL                                  id      name            org        salary
NULL в Системах управления базами
данных (СУБД) — специальное значение            1   Гришин        NULL           10000
 (псевдозначение), которое может быть           2   Васильев      IT             15000
записано в поле таблицы базы данных
(БД). NULL соответствует понятию                3   Петров        Снабжение      NULL
«пустое поле», то есть «поле, не содержащее     4   Иванов        IT             20000
никакого значения». Введено для того, чтобы
различать в полях БД пустые (визуально не отображаемые) значения (например, строку нулевой
длины) и отсутствующие значения (когда в поле не записано вообще никакого значения, даже
пустого).
NULL означает отсутствие, неизвестность информации. Значение NULL не является значением в
полном смысле слова: по определению оно означает отсутствие значения и не принадлежит ни
одному типу данных. Поэтому NULL не равно ни логическому значению FALSE, ни пустой
строке, ни нулю. При сравнении NULL с любым значением будет получен результат NULL, а не
FALSE и не 0. Более того, NULL не равно NULL!
Для того, чтобы, например, извлечь из таблицы всех работников, у которых не указана (NULL)
заработная плата либо не указан отдел, в котором они работают, необходимо выполнить запрос
вида:                                                                   name
SELECT name
FROM Employees                                                       Гришин
WHERE org IS NULL                                                    Петров
OR salary IS NULL; --- в проверке никаких знаков равенства! Только IS (NOT) NULL!
SQL. JOIN
    Ключевое слово join в SQL используется при построении select-
выражений. Инструкция JOIN позволяет объединить колонки из нескольких
таблиц в одну. Объединение происходит временное и целостность таблиц не
нарушается. Существует три типа join-выражений:
         inner join;
         outer join;
         cross join;
    В свою очередь, outer join может быть left, right и full (слова inner и outer
обычно опускаются).
    В качестве примера возьмём две простые таблицы (таблица А с
работниками ссылается на таблицу B с организациями) и сконструируем для
них SQL-выражения с использованием join.
          id      name         Id_B                     id        name
          1    Гришин      1                           1     Бухгалтерия
          2    Васильев    2                           2     IT
          3    Петров      3                           3     Снабжение
          4    Иванов      NULL                        4     Охрана
INNER JOIN
           id      name        Id_B                 id        name
           1    Гришин     1                       1     Бухгалтерия
           2    Васильев   2                       2     IT
           3    Петров     3                       3     Снабжение
           4    Иванов     NULL                    4     Охрана

                                         id     name     Id_B     Id        name
SELECT *
FROM a                                   1    Гришин     1        1    Бухгалтерия
JOIN b                                   2    Васильев   2        2    IT
ON a.id_B = b.id                         3    Петров     3        3    Снабжение

   Обратите внимание на диаграмму множеств. Внутреннее соединение INNER
JOIN производит выборку только тех записей, которые соответствуют
пересечению таблиц А и В. Работник «Иванов» из таблицы А не нашёл себе
соответствий в таблице В, также, как и вид организации «Охрана» из таблицы В
не привязана ни к одному работнику. Поэтому данные значения не попали в
конечный результат выборки.
LEFT OUTER JOIN
            id        name        Id_B                 id          name
            1      Гришин     1                        1    Бухгалтерия
            2      Васильев   2                        2    IT
            3      Петров     3                        3    Снабжение
            4      Иванов     NULL                     4    Охрана

                                         id     name        Id_B          Id        name
SELECT *                                 1    Гришин        1         1        Бухгалтерия
FROM a                                   2    Васильев      2         2        IT
LEFT JOIN b                              3    Петров        3         3        Снабжение
ON a.id_B = b.id
                                         4    Иванов        NULL      NULL     NULL

Левостороннее внешнее соединение LEFT OUTER JOIN производит полный
выбор записей из таблицы А с соответствующими записями (если таковые
имеются) таблицы B. Если совпадения нет, то правая часть будет содержать
NULL.
RIGHT OUTER JOIN
           id      name          Id_B                  id               name
           1    Гришин       1                         1       Бухгалтерия
           2    Васильев     2                         2       IT
           3    Петров       3                         3       Снабжение
           4    Иванов       NULL                      4       Охрана

                                               id     name          Id_B       Id        name

SELECT *                                   1        Гришин          1          1    Бухгалтерия
                   Table A       Table B
FROM a                                     2        Васильев        2          2    IT
RIGHT JOIN b                               3        Петров          3          3    Снабжение
ON a.id_B = b.id                           NULL     NULL            NULL       4    Охрана

Правостороннее внешнее соединение действует по аналогии с LEFT JOIN’ом.
RIGHT OUTER JOIN производит полный выбор записей из таблицы В с
соответствующими записями (если таковые имеются) таблицы А. Если
совпадения нет, то правая часть будет содержать NULL.
FULL OUTER JOIN
           id      name        Id_B                     id            name
           1    Гришин     1                            1        Бухгалтерия
           2    Васильев   2                            2        IT
           3    Петров     3                            3        Снабжение
           4    Иванов     NULL                         4        Охрана

                                          id     name        Id_B             Id        name
                                      1        Гришин        1            1        Бухгалтерия
SELECT *                              2        Васильев      2            2        IT
FROM a                                3        Петров        3            3        Снабжение
FULL JOIN b                           4        Иванов        NULL         NULL     NULL
ON a.id_B = b.id                      NULL     NULL          NULL         4        Охрана

Полное внешнее объединение FULL OUTER JOIN производит выборку
множества всех записей из таблицы А и B с соответствующими записями с обеих
сторон при их наличии. Если совпадения нет, отсутствующая сторона будет
содержать NULL. Обратите внимание на две последних строки в итоговой
выборке.
CROSS JOIN                            id     name     Id_B   Id        name

Так же существует выборка перекрестного     1    Гришин     1      1    Бухгалтерия

соединения (называемое ещё                  1    Гришин     1      2    IT
декартовым произведением), CROSS JOIN,      1    Гришин     1      3    Снабжение
с перебором все вариантов,                  1    Гришин     1      4    Охрана
которое сложно объяснить диаграммами:       2    Васильев   2      1    Бухгалтерия
                                            2    Васильев   2      2    IT
SELECT *
                                            2    Васильев   2      3    Снабжение
FROM a
                                            2    Васильев   2      4    Охрана
CROSS JOIN b;
                                            3    Петров     3      1    Бухгалтерия
---(ещё можно написать запрос как
                                            3    Петров     3      2    IT
---SELECT * FROM a, b)
                                            3    Петров     3      3    Снабжение
Данное перекрестное соединение выбирает     3    Петров     3      4    Охрана
буквально "всё ко всему", в результате мы   4    Иванов     NULL   1    Бухгалтерия
получим 4 x 4 = 16 записей, т.е. намного    4    Иванов     NULL   2    IT
больше, чем в оригинале мы имеем            4    Иванов     NULL   3    Снабжение
в таблицах.                                 4    Иванов     NULL   4    Охрана
Работа с множествами
    Прежде чем начать описания функций и их свойств в SQL,
работающих со множествами – дадим определение термину
“множество” на языке SQL. Ведь многим из нас известно, что
множество - это один из ключевых объектов математики, в частности,
теории множеств и логики. По определению Бертрана Рассела:
“Множество – совокупность различных элементов, мыслимая как
единое целое” .

     А сейчас переместим это определение в базу данных и увидим,
что вывод любого запроса можно принять за множество. Наверное у
вас возникнет вопрос в виде: “И что же это нам дает?” Ответ прост –
применение некоторых свойств и операций, присущих множествам.
Сейчас мы с вами разберем, что это за операции и как они реализованы
в SQL.
Объединение. UNION
 Объединением двух множеств A и B называется множество, содержащее в себе все
элементы исходных множеств, и обозначается как A ∪ B.
В языке SQL ключевое слово UNION применяется для объединения результатов двух SQL-
запросов в единую таблицу, состоящую из схожих строк. Оба запроса должны возвращать
одинаковое число столбцов и совместимые типы данных в соответствующих столбцах.
Оператор указывается между запросами. В упрощенном виде это выглядит следующим
образом:

UNION [ALL]

UNION [ALL]

.....;
По умолчанию любые дублирующие записи автоматически скрываются(своего рода default-
ный DISTINCT), если не использовано выражение UNION ALL.
Необходимо отметить, что UNION сам по себе не гарантирует порядок строк. Строки из
второго запроса могут оказаться в начале, в конце или вообще перемешаться со строками из
первого запроса. В случаях, когда требуется определенный порядок, необходимо
использовать выражение ORDER BY.
Объединение. UNION
Как выглядит объединение множеств на языке SQL:               person        amount
           sales2005          sales2006                       Иван          1000
            person    amount         person   amount          Алексей       2000
           Иван
           Алексей
                     1000
                     2000
                               ∪    Иван
                                    Алексей
                                              2000
                                              2000
                                                       =
                                                              Иван
                                                              Сергей
                                                                            2000
                                                                            5000
           Сергей    5000           Петр      35000           Петр          35000

(SELECT * FROM sales2005) UNION (SELECT * FROM sales2006);
В результате отобразятся две строки с Иваном, так как эти строки
различаются значениями в столбцах. Но при этом в результате
присутствует лишь одна строка с Алексеем, поскольку значения в         person        amount
столбцах полностью совпадают. Применение UNION ALL дает              Иван            1000
другой результат, так как дубликаты не скрываются. Выполнение        Иван            2000
запроса:
                                                                     Алексей         2000
                                                                     Алексей         2000
(SELECT * FROM sales2005)
UNION ALL                                                            Сергей          5000
(SELECT * FROM sales2006);     даст следующий результат:             Петр            35000
Пересечение. Intersect
     Пересечение — множество, состоящее из элементов, которые
одновременно принадлежат всем данным множествам. Обозначается как A ⋂
B. То есть, это те элементы множеств, которые есть во всех рассматриваемых
множествах. Для пересечение множеств на языке SQL есть функция
INTERSECT, которая также как и UNION обладает ограничением на
результат запросов, которые должны быть совместимы по объединению, т.е.
содержать одинаковое количество столбцов, и каждый столбец первого
запроса должен быть того же типа данных (или автоматически приводиться к
нему), что и находящийся в том же месте столбец второго запроса. Также,
пересечение не игнорирует поля, которые содержит значения null.
     
     INTERSECT
     
     INTERSECT
     
      .....;
Пересечение. Intersect
Как выглядит пересечение множеств на языке SQL:
     sales2005                  sales2006

   person   amount         person     amount        person
 Иван       1000         Иван        2000          Иван
 Алексей    2000     ⋂   Алексей     2000      =   Алексей
 Сергей     5000         Петр        35000

(SELECT person FROM sales2005)
INTERSECT
(SELECT person FROM sales2006);
В результате отобразятся две строки – с Алексеем и с Иваном, так как
эти строки находятся в обеих таблицах.
Разность. Minus/Except
     Разность двух множеств — это операция, результатом которой является
множество, в которое входят все элементы первого множества, не входящие во
второе множество. A\B означает множество элементов, принадлежащих A, но не
принадлежащих B.
     В языке SQL нет стандарта для оператора разности множеств, поэтому он
может в некоторых СУБД принимать значение MINUS, в других – EXCEPT. В
любом случае, как и UNION, оператор разности обладает ограничением на
результат запросов, которые должны быть совместимы по объединению, т.е.
содержать одинаковое количество столбцов, и каждый столбец первого запроса
должен быть того же типа данных (или автоматически приводиться к нему), что
и находящийся в том же месте столбец второго запроса.
     
     MINUS/EXCEPT
     
     MINUS/EXCEPT
     
      .....;
Разность. Minus/Except
Как выглядит разность множеств на языке SQL (версия для СУБД MS
SQL Server):

    sales2005              sales2006
   person   amount        person    amount
  Иван      1000          Иван      2000         person
  Алексей   2000     \    Алексей   2000     =   Сергей
  Сергей    5000          Петр      35000

(SELECT person FROM sales2005)
EXCEPT
(SELECT person FROM sales2006);
В результате отобразится строка с Сергеем, уникальным именем для
sales2005, т.к. все остальные имена были исключены множеством имён
sales2006.
Lifehack
Попробуем, используя знания работы со множествами, сделать финт такого рода:

                                                (A \ B) ∪ (B \ A)

Т.е., вычленим из двух выборок уникальные записи, обойдя пересечения. Нам
необходимы все данные из таблицы sales2005, которых нет в sales2006 и наоборот – всё
из sales2006, чего нет в sales2005. Делается это так (версия для СУБД MS SQL Server):
(SELECT person FROM sales2005
EXCEPT
SELECT person FROM sales2006);             ---(A \ B)
UNION                                      ---∪
(SELECT person FROM sales2006
EXCEPT
SELECT person FROM sales2005);             ---(B \ A)

Подумайте, как ещё можно добиться такого же результата.
Домашнее задание
 1) по книге Цыганкова/Мальцева – читать с самого
 начала до пункта 3.4 включительно;
 2) Грабер М. Введение в SQL – читать главы 8, 9,
 14 полностью.
 3) на сайте SQL-EX.RU выполнить к следующему
 занятию задачи 6, 7, 8 (решить через JOIN), 9, 16,
 23, 34, 35, 36, 38, 40, 44, 45, 48, 49, 50.
До встречи,
 друзья 
Вы также можете почитать