<table style="width: 100%;"><tr><td style="width: 40%;">
<a href="../articles/sql_for_beginner.md">Основы SQL
</a></td><td style="width: 20%;">
<a href="../readme.md">Содержание
</a></td><td style="width: 40%;">
<a href="../articles/sql_import.md">Создание базы данных. Импорт данных.
</a></td><tr>
</table>

# Представления (View)

В предыдущей лекции инструкции DML рассматривались применительно к базовым таблицам. Данные базовой таблицы хранятся на диске. В отличие от базовых таблиц, **представления** по умолчанию не существуют физически, т.е. их содержимое не сохраняется на диске (*Это не относится к так называемым индексированным представлениям, которые мы в рамках нашего курса рассматривать не будем*)

**Представление (VIEW)** — объект базы данных, являющийся результатом выполнения запроса к базе данных, определенного с помощью оператора **SELECT**, *в момент обращения к представлению*.

Представления иногда называют «виртуальными таблицами». Такое название связано с тем, что представление доступно для пользователя как таблица, но само оно не содержит данных, а извлекает их из таблиц в момент обращения к нему. Если данные изменены в базовой таблице, то пользователь получит актуальные данные при обращении к представлению, использующему данную таблицу; кэширования результатов выборки из таблицы при работе представлений не производится.

Представления могут основываться как на таблицах, так и на других представлениях, т.е. могут быть вложенными (до 32 уровней вложенности).

**Преимущества использования представлений:**

* Дает возможность гибкой настройки прав доступа к данным за счет того, что права даются не на таблицу, а на представление. Это очень удобно в случае если пользователю нужно дать права на отдельные строки таблицы или возможность получения не самих данных, а результата каких-то действий над ними.
* Позволяет разделить логику хранения данных и программного обеспечения. Можно менять структуру данных, не затрагивая программный код, нужно лишь создать представления, аналогичные таблицам, к которым раньше обращались приложения. Это очень удобно когда нет возможности изменить программный код или к одной базе данных обращаются несколько приложений с различными требованиями к структуре данных.
* Удобство в использовании за счет автоматического выполнения таких действий как доступ к определенной части строк и/или столбцов, получение данных из нескольких таблиц и их преобразование с помощью различных функций.


## Создание представления для MySQL

<!-- https://habr.com/ru/post/47031/ -->

Для создания представления используется оператор CREATE VIEW, имеющий следующий синтаксис:

```sql
CREATE [OR REPLACE]
[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]
```

*view_name* — имя создаваемого представления. *select_statement* — оператор **SELECT**, выбирающий данные из таблиц и/или других представлений, которые будут содержаться в представлении

Оператор CREATE VIEW содержит 4 необязательные конструкции:

* **OR REPLACE** — при использовании данной конструкции в случае существования представления с таким именем старое будет удалено, а новое создано. В противном случае возникнет ошибка, информирующая о сществовании представления с таким именем и новое представление создано не будет. Следует отметить одну особенность — имена таблиц и представлений в рамках одной базы данных должны быть уникальны, т.е. нельзя создать представление с именем уже существующей таблицы. Однако конструкция **OR REPLACE** действует только на представления и замещать таблицу не будет.
* **ALGORITM** — определяет алгоритм, используемый при обращении к представлению.
* **column_list** — задает имена полей представления.
* **WITH CHECK OPTION** — при использовании данной конструкции все добавляемые или изменяемые строки будут проверяться на соответствие определению представления. В случае несоответствия данное изменение не будет выполнено. Обратите внимание, что при указании данной конструкции для необновляемого представления возникнет ошибка и представление не будет создано.

По умолчанию колонки представления имеют те же имена, что и поля возращаемые оператором **SELECT** в определении представления. При явном указании имен полей представления **column_list** должен включать по одному имени для каждого поля разделенных запятой. Существует две причины по которым желательно использовать явное указание имен полей представления:

* Имена полей представления должны быть уникальны в пределах данного представления. При создании представления основанного на нескольких таблицах возможна ситуация повторения имен полей представления. Например:

    ```sql
    CREATE VIEW v AS SELECT a.id, b.id FROM a,b;
    ```

    Для избежания такой ситуации нужно явно указывать имена полей представления
    
    ```sql
    CREATE VIEW v (a_id, b_id) AS SELECT a.id, b.id FROM a,b;
    ```

    Того же результата можно добиться, используя синонимы (алиасы) для названий колонок:

    ```sql
    CREATE VIEW v AS SELECT a.id a_id, b.id b_id FROM a,b;
    ```

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

    ```sql
    CREATE VIEW v AS SELECT group_concat(DISTINCT column_name oreder BY column_name separator '+') FROM table_name;
    ```

    Вряд ли удобно использовать в дальнейшем в качестве имени поля `group_concat(DISTINCT username ORDER BY username separator '+')`

## Создание представления для MSSQL

Представление создается посредством инструкции **CREATE VIEW**, синтаксис которой выглядит следующим образом:

```sql
CREATE VIEW view_name [(column_list)]
    [WITH {ENCRYPTION | SCHEMABINDING | VIEW_METADATA}]
    AS select_statement
    [WITH CHECK OPTION]
```

Параметр *view_name* задает имя определяемого представления, а в параметре *column_list* указывается список имен, которые будут использоваться в качестве имен столбцов представления. Если этот необязательный параметр опущен, то используются имена столбцов таблиц, по которым создается представление. Параметр *select_statement* задает инструкцию **SELECT**, которая извлекает строки и столбцы из таблиц (или других представлений). Параметр *WITH ENCRYPTION* задает шифрование инструкции SELECT, повышая таким образом уровень безопасности системы баз данных.

Предложение SCHEMABINDING привязывает представление к схеме таблицы, по которой оно создается. Когда это предложение указывается, имена объектов баз данных в инструкции SELECT должны состоять из двух частей, т.е. в виде schema.db_object, где schema - владелец, а db_object может быть таблицей, представлением или определяемой пользователем функцией.

Любая попытка модифицировать структуру представлений или таблиц, на которые ссылается созданное таким образом представление, будет неудачной. Чтобы такие таблицы или представления можно было модифицировать (инструкцией ALTER) или удалять (инструкцией DROP), нужно удалить это представление или убрать из него предложение SCHEMABINDING.

Когда при создании представления указывается параметр VIEW_METADATA, все его столбцы можно обновлять (за исключением столбцов с типом данных timestamp), если представление имеет триггеры INSERT или UPDATE INSTEAD OF.

Инструкция SELECT в представлении не может содержать предложение ORDER BY или параметр INTO. Кроме этого, по временным таблицам нельзя выполнять запросы.

Представления можно использовать для разных целей:

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

Для скрытия подробностей сложных запросов. Если для приложения базы данных требуются запросы со сложными операциями соединения, создание соответствующих представлений может упростить такие запросы.

Для ограничения вставляемых или обновляемых значений некоторым диапазоном.

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

```sql
CREATE VIEW view_Consultant
    AS SELECT EmpId, ProjectNumber, EnterDate
    FROM Works_on
    WHERE Job = 'Консультант';
```

Запрос в этом примере выбирает из таблицы Works_on строки, удовлетворяющие условию Job='Консультант'. Представление view_Consultant определяется строками и столбцами, возвращаемыми этим запросом.

Как уже упоминалось ранее, в общем формате инструкции CREATE VIEW не обязательно указывать имена столбцов представления. Однако, с другой стороны, в приведенных далее двух случаях обязательно требуется явно указывать имена столбцов:

* если столбец представления создается из выражения или агрегатной функции;
* если два или больше столбцов представления имеют одинаковое имя в базовой таблице.

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

```sql
CREATE VIEW view_Count (projectNumber, countProject)
    AS SELECT ProjectNumber, COUNT(*)
    FROM Works_on
    GROUP BY ProjectNumber;
```    

Здесь имена столбцов представления *view_Count* должны быть указаны явно по той причине, что инструкция *SELECT* содержит агрегатную функцию `count(*)`, которая требует, чтобы все столбцы представления были именованы.

Не требуется явно указывать список столбцов в инструкции *CREATE VIEW*, если применить заголовки столбцов, как это показано в примере ниже:

```sql
CREATE VIEW view_Count1
    AS SELECT ProjectNumber, COUNT(*) countProject
    FROM Works_on
    GROUP BY ProjectNumber;
```

Представление можно создать из другого представления, как показано в примере:

```sql
CREATE VIEW view_project_p2
    AS SELECT EmpId
    FROM view_Consultant
        WHERE ProjectNumber ='p2';
```

Представление view_project_p2 в примере выше создается из представления view_Consultant. Все запросы, использующие представление view_project_p2, преобразовываются в эквивалентные запросы к базовой таблице Works_on.
















<table style="width: 100%;"><tr><td style="width: 40%;">
<a href="../articles/sql_for_beginner.md">Основы SQL
</a></td><td style="width: 20%;">
<a href="../readme.md">Содержание
</a></td><td style="width: 40%;">
<a href="../articles/sql_import.md">Создание базы данных. Импорт данных.
</a></td><tr></table>
