понедельник, 30 января 2017 г.

Про отношения с таблицами. C примерами на SQL

Отношение есть подмножество декартова произведения множеств, элементы которого - кортежи, составленные из элементов перемножаемых множеств. N-арное отношение есть подмножество декартова произведения N множеств, состоящее из кортежей длины N. В частности, бинарное отношение есть множество пар, или кортежей длины 2, где первый элемент принадлежит первому, а второй - второму из двух перемножаемых множеств.

Например, для двух множеств

A = {1, 2, 3}
B = {'Стакан', 'Лимон'}

декартово произведение есть

A x B = {
    (1, 'Стакан'), 
    (1, 'Лимон'),
    (2, 'Стакан'),
    (2, 'Лимон'),
    (3, 'Стакан'),
    (3, 'Лимон')
}

А его подмножества есть отношения. Например, такие:

{(1, 'Стакан')}
{(1, 'Стакан'), (2, 'Лимон')}
{(1, 'Стакан'), (2, 'Лимон'), (3, 'Стакан')}

Эти отношения легко поместить в таблицу реляционной БД:

SQL> create table things (
  2      id number,
  3      name varchar2(50)
  4  );
Table created

SQL> insert into things values (1, 'Стакан');
1 row inserted
SQL> insert into things values (2, 'Лимон');
1 row inserted
SQL> insert into things values (3, 'Стакан');
1 row inserted

Таким же образом можно вставить в таблицу все декартово произведение (A x B), но это нарушит хотя и незадекларированную, но подразумеваемую уникальность значений столбца id. Данные в таблицах БД, как правило, представляют собой именно строгие подмножества декартова произведения множеств значений всех столбцов.

В качестве другого примера, создадим таблицу folks с такими данными:

SQL> create table folks(
  2      id number,
  3      first_name varchar2(50),
  4      last_name varchar2(50),
  5      sex char
  6  );
Table created

SQL> insert into folks values (1, 'Илья', 'Иванов', 'M');
1 row inserted
SQL> insert into folks values (2, 'Иван', 'Сидоров', 'M');
1 row inserted
SQL> insert into folks values (3, 'Анна', 'Петрова', 'F');
1 row inserted

SQL> select * from folks;

   ID FIRST_NAME      LAST_NAME       SEX
----- --------------- --------------- ----- 
    1 Илья            Иванов          M
    2 Иван            Сидоров         M
    3 Анна            Петрова         F

Эти данные - подмножество декартова произведения четырех множеств:

A = {1, 2, 3}
B = {Илья, Иван, Анна}
C = {Иванов, Сидоров, Петрова}
D = {M, F}

Их декартово произведение таково:

SQL> select A.id, B.first_name, C.last_name, D.sex
from
    (select unique id from folks) A,
    (select unique first_name from folks) B,
    (select unique last_name from folks) C,
    (select unique sex from folks) D
;

   ID FIRST_NAME      LAST_NAME       SEX
----- --------------- --------------- ---
    1 Анна            Сидоров         M
    2 Анна            Сидоров         M
    3 Анна            Сидоров         M
    1 Илья            Сидоров         M
    2 Илья            Сидоров         M
    3 Илья            Сидоров         M
    1 Иван            Сидоров         M
    2 Иван            Сидоров         M
    3 Иван            Сидоров         M
    1 Анна            Иванов          M
    2 Анна            Иванов          M
    3 Анна            Иванов          M
    1 Илья            Иванов          M
    2 Илья            Иванов          M
    3 Илья            Иванов          M
    1 Иван            Иванов          M
    2 Иван            Иванов          M
    3 Иван            Иванов          M
    1 Анна            Петрова         M
    2 Анна            Петрова         M
    3 Анна            Петрова         M
    1 Илья            Петрова         M
    2 Илья            Петрова         M
    3 Илья            Петрова         M
    1 Иван            Петрова         M
    2 Иван            Петрова         M
    3 Иван            Петрова         M
    1 Анна            Сидоров         F
    2 Анна            Сидоров         F
    3 Анна            Сидоров         F
    1 Илья            Сидоров         F
    2 Илья            Сидоров         F
    3 Илья            Сидоров         F
    1 Иван            Сидоров         F
    2 Иван            Сидоров         F
    3 Иван            Сидоров         F
    1 Анна            Иванов          F
    2 Анна            Иванов          F
    3 Анна            Иванов          F
    1 Илья            Иванов          F
    2 Илья            Иванов          F
    3 Илья            Иванов          F
    1 Иван            Иванов          F
    2 Иван            Иванов          F
    3 Иван            Иванов          F
    1 Анна            Петрова         F
    2 Анна            Петрова         F
    3 Анна            Петрова         F
    1 Илья            Петрова         F
    2 Илья            Петрова         F
    3 Илья            Петрова         F
    1 Иван            Петрова         F
    2 Иван            Петрова         F
    3 Иван            Петрова         F

54 rows selected

Элементы кортежей отношения имеют имена и называются атрибутами отношения. Атрибуты отношения соответствуют столбцам таблицы (или полям ее строк), кортежи - соответствуют строкам таблицы, а само отношение - таблице. N-арное отношение соответствует таблице с N столбцами и, наоборот, таблица с N столбцами представляет N-арное отношение. В рассмотренном примере отношение, представленное таблицей folks, содержит три кортежа и имеет четыре атрибута id, first_name, last_name и sex.

Отношения и операции над ними изучает реляционная алгебра - раздел математики, который лежит в основе построения реляционных БД. Так же, как арифметика оперирует числами, теория множеств - множествами, реляционная алгебра оперирует отношениями. Операндами и результатом операций над отношениями всегда являются отношения.

Операции над отношениями, представляющие практический интерес при работе с БД, следующие:

  • проекция (projection),
  • выборка (selection),
  • переименование (rename),
  • соединение (join).

Поскольку отношения - это множества, то к ним применимы и операции над множествами:

  • объединение (union),
  • пересечение (intersection),
  • вычитание (minus),
  • декартово произведение (cross product).

Рассмотрим перечисленные операции с примерами на SQL в Oracle 11gR2.

Проекция создает отношение с подмножеством атрибутов исходного отношения. Например, из отношения (таблицы) folks с четырьмя атрибутами (столбцами) получим новое отношение (таблицу) с двумя атрибутами (столбцами) first_name и last_name:

SQL> select first_name, last_name from folks;

FIRST_NAME      LAST_NAME    
--------------- ---------------  
Илья            Иванов        
Иван            Сидоров
Анна            Петрова     

Выборка создает отношение, являющееся подмножеством исходного отношения. Кортежи (строки) выбираются из исходного отношения (таблицы) по некоторому критерию:

select * from folks where sex = 'F';

   ID FIRST_NAME      LAST_NAME       SEX
----- --------------- --------------- ----- 
    3 Анна            Петрова         F

Операция переименования переименовывает атрибуты (столбцы) исходного отношения (таблицы). Следующий запрос комбинирует проекцию, выборку и переименование:

SQL> select first_name "Имя", last_name "Фамилия"
  2  from folks
  3  where sex = 'M';

Имя             Фамилия
--------------- ----------------
Илья            Иванов
Иван            Сидоров

Однако, реляционная алгебра не предусматривает получения отношений с атрибутами, отсутствующими в исходном отношении. Так что вычисляемые столбцы - это завоевание производителей БД и языка SQL:

SQL> select first_name||' '||last_name full_name from folks;

FULL_NAME
------------------------------
Илья Иванов
Иван Сидоров
Анна Петрова

Операций соединения (join) в реляционной алгебре на самом деле несколько:

  • натуральное (natural join),
  • по равенству (equijoin),
  • по произвольному условию (theta-join),
  • полусоединение (semi-join),
  • антиполусоединение (anti-semi-join).

Разработчики языка SQL и реляционных БД расширили этот набор еще тремя соединениями:

  • левое внешнее (left outer join),
  • правое внешнее (right outer join),
  • полное внешнее (full outer join).

Натуральное соединение соединяет два отношения по значениям одноименных атрибутов. Множество атрибутов полученного отношения есть объединение множеств атрибутов исходных отношений. У таблиц folks и things имеется одноименный столбец id, по нему и выполняется натуральное соединение:

SQL> select * from folks natural join things;

   ID FIRST_NAME      LAST_NAME       SEX NAME            
----- --------------- --------------- --- --------------- 
    1 Илья            Иванов          M   Стакан          
    2 Иван            Сидоров         M   Лимон           
    3 Анна            Петрова         F   Стакан          

Если при проектировании таблиц БД придерживаться правила, что столбец с первичным ключом и столбец с ссылающимся на него внешним ключом называются <имя_таблицы>_id, то натуральное соединение естественным образом свяжет две таблицы по этому столбцу.

Соединение по равенству предполагает, что кортежи (строки) двух отношений (таблиц) соединяются по одинаковым значениям некоторых атрибутов (столбцов). Множество атрибутов полученного отношения есть все атриубты двух исходных отношений. Соединим отношение с самим собой по одинаковым значениям атрибута name:

SQL> select * from things t1, things t2 where t1.name = t2.name;

   ID NAME               ID NAME
----- --------------- ----- ---------------
    3 Стакан              1 Стакан
    1 Стакан              1 Стакан
    2 Лимон               2 Лимон
    3 Стакан              3 Стакан
    1 Стакан              3 Стакан

Тета-соединение соединяет отношения по произвольному условию:

SQL> select * from things t1, things t2 where t1.name > t2.name;

   ID NAME               ID NAME
----- --------------- ----- ---------------
    1 Стакан              2 Лимон
    3 Стакан              2 Лимон

SQL> select * from things t1, things t2 where mod(t1.id,2) != mod(t2.id,2);

   ID NAME               ID NAME
----- --------------- ----- ---------------
    1 Стакан              2 Лимон
    2 Лимон               1 Стакан
    2 Лимон               3 Стакан
    3 Стакан              2 Лимон

Полусоединение двух отношений порождает отношение с атрибутами одного из исходных отношений и кортежами, которые соединяются с кортежами другого отношения по заданному условию. Проиллюстрировать эту операцию можно с помощью EXIST или IN c подзапросом:

SQL> select *
  2  from folks
  3  where exists (select 1 from things where id = folks.id);

   ID FIRST_NAME      LAST_NAME       SEX
----- --------------- --------------- ----- 
    1 Илья            Иванов          M
    2 Иван            Сидоров         M
    3 Анна            Петрова         F

SQL> select *
  2  from folks
  3  where id in (select id from things);

   ID FIRST_NAME      LAST_NAME       SEX
----- --------------- --------------- ----- 
    1 Илья            Иванов          M
    2 Иван            Сидоров         M
    3 Анна            Петрова         F

Антиполусоединение также порождает отношение с атрибутами одного из исходных отношений, кортежи которого, в отличие от полусоединения, НЕ соединяются с кортежами другого отношения по заданному условию. Это можно проиллюстрировать с помощью NOT EXISTS:

SQL> select *
  2  from folks
  3  where not exists (select 1 from things where id > folks.id);

   ID FIRST_NAME      LAST_NAME       SEX
----- --------------- --------------- ----- 
    3 Анна           Петрова          F

Наконец, три типа внешних соединений - левое, правое и полное - иллюстрируются следующими тремя запросами:

SQL> select *
  2  from folks left outer join things on folks.id+2 = things.id;

   ID FIRST_NAME      LAST_NAME       SEX    ID NAME            
----- --------------- --------------- --- ----- --------------- 
    1 Илья            Иванов          M       3 Стакан
    3 Анна            Петрова         F
    2 Иван            Сидоров         M

SQL> select *
  2  from folks right outer join things on folks.id+2 = things.id;

   ID FIRST_NAME      LAST_NAME       SEX    ID NAME            
----- --------------- --------------- --- ----- --------------- 
    1 Илья            Иванов          M       3 Стакан
                                              1 Стакан
                                              2 Лимон

SQL> select *
  2  from folks full outer join things on folks.id+2 = things.id;

   ID FIRST_NAME      LAST_NAME       SEX    ID NAME            
----- --------------- --------------- --- ----- --------------- 
    1 Илья            Иванов          M       3 Стакан
    3 Анна            Петрова         F
    2 Иван            Сидоров         M
                                              1 Стакан
                                              2 Лимон

От операций соединения перейдем к "множественным" операциям над отношениями. Операции объединения, пересечения и разности над отношениями возможны тогда, когда типы атрибутов операндов-отношений совпадают (или приводятся один к другому).

Объединение создает из двух исходных отношений новое отношение, содержащее кортежи, присутствующие хотя бы в одном из исходных отношений. Пример объединения на языке SQL:

SQL> select id, name from things
  2  union
  3  select id, first_name from folks;

   ID NAME
----- ---------------
    1 Стакан
    2 Лимон
    3 Стакан
    1 Илья
    2 Иван
    3 Анна

6 rows selected

Пересечение создает из двух исходных отношений новое отношение, содержащее кортежи, присутствующие в каждом из исходных отношений. Пример пересечения на языке SQL:

SQL> select 1 id, 'Стакан' name from dual -- отношение с одним элементом
  2  intersect
  3  select id, name from things;

   ID NAME
----- ---------------
    1 Стакан

Вычитание создает из двух исходных отношений новое отношение, содержащее кортежи, присутствующие в первом отношении, но не во втором. Пример вычитания отношений на языке SQL:

SQL> select id, name from things
  2  minus
  3  select 1 id, 'Стакан' name from dual;

   ID NAME
----- ---------------
   2 Лимон
   3 Стакан

И наоборот:

SQL> select 4 id, 'Чайник' name from dual
  2  minus
  3  select id, name from things;

   ID NAME
----- ---------------
    4 Чайник

Декартово произведение уже было проиллюстрировано выше. Еще один пример:

SQL> select * from folks, things;

   ID FIRST_NAME      LAST_NAME       SEX    ID NAME            
----- --------------- --------------- --- ----- --------------- 
    1 Илья            Иванов          M       1 Стакан          
    1 Илья            Иванов          M       2 Лимон           
    1 Илья            Иванов          M       3 Стакан          
    2 Иван            Сидоров         M       1 Стакан          
    2 Иван            Сидоров         M       2 Лимон           
    2 Иван            Сидоров         M       3 Стакан          
    3 Анна            Петрова         F       1 Стакан          
    3 Анна            Петрова         F       2 Лимон           
    3 Анна            Петрова         F       3 Стакан          

9 rows selected

Реляционная алгебра не предлагает операций для построения новых отношений путем агрегирования значений атрибутов. Таким образом, возможности SQL, связанные с агрегированием данных в запросах, есть еще одно расширение, сделанное производителями БД.

В заключение, по ассоциации идей, перекину еще один мостик между понятиями - а именно, понятиями "декартово произведение" и "декартова система координат". Не случайно в их названиях имеется общее слово.

Декартово произведение множества действительных чисел на себя есть множество всех пар действительных чисел, и одновременно - множество возможных координат точки на плоскости, где проведены оси абсцисс и ординат, X и Y. Любое подмножество множества (X x Y) по определению есть отношение. Точка, прямая, кривая, окружность, любая плоская фигура и любое множество точек на плоскости есть графическое представление отношения. В частности, график функции на плоскости есть графическое представление отношения.

Несложно также представить, что каждая строка таблицы с N столбцами соответствует точке в N-мерном пространстве, где на N координатных осях находятся значения всех N столбцов. Если заполнить все точки этого пространства, получим декартово произведение множеств значений всех столбцов.

Не забудем удалить таблицы, которые больше не нужны:

SQL> drop table folks;
Table dropped
SQL> drop table things;
Table dropped

Комментариев нет:

Отправить комментарий