3.1. Представления View

Первое, с чем мы начнем знакомиться – вьюшки (View), я их больше люблю называть просмотрщиками или объектами просмотра, но в данной книге буду стараться использовать понятие вью, как более устоявшееся, хотя могли бы наши переводчики найти русский аналог слова View. Мне, например, нравится понятие объект просмотра, ведь вьюшка – это объект, а слово View переводиться как просмотр, к тому же, это понятие лучше отображает суть и звучит на родном языке.

Вьюшки позволяют хранить предопределенные запросы как объекты в базе данных для дальнейшего использования. Таблицы, запрашиваемые в вью, называются базовыми таблицами. С некоторыми ограничениями вы можете именовать и хранить любой SELECT запрос как вью.

Для чего создаются вьюшки? Можно выделить следующие назначения:

  • когда необходимо дать пользователю возможность просматривать не всю таблицу, а только ее часть. В этом случае, пользователь обращается к View как к таблице и видит только те поля, которые ему нужны;
  • для объединение двух или более таблиц. Например, объединив таблицы с помощью вьюшек, упрощается работа со связанными таблицами;
  • вывод статистических данных. Например, чтобы не писать каждый раз запрос на создание статистики, можно создать вью, и использовать его по мере надобности;

3.1.1. Создание вьюшки

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

CREATE VIEW [ < database_name > . ] [ < owner > . ] 
    view_name [ ( column [ ,...n ] ) ] 
[ WITH < view_attribute > [ ,...n ] ] 
AS 
select_statement 
[ WITH CHECK OPTION ] 

< view_attribute > ::= 
    { ENCRYPTION | SCHEMABINDING | VIEW_METADATA }

Минимум, что необходимо указать, это оператор CREATE VIEW, после которого должно идти имя. Далее указываем ключевое слово AS и пишем запрос на выборку данных, который и будет отражать содержимое вьюшки.

Давайте сразу посмотрим на этот оператор в действии, чтобы нам лучше было в последствии понимать суть и технологию его работы. Следующий пример создает вью PhoneView для просмотра имен работников и их телефонов:

CREATE VIEW PhoneView
AS
SELECT pl.vcFamil, pl.vcName, pl.vcSurName, 
  dDateBirthDay, vcPhoneNumber
FROM tbPeoples pl, tbPhoneNumbers pn
WHERE pn.idPeoples=*pl.idPeoples 

Как теперь можно использовать эту вьюшку? Точно так же, как и таблицу, то есть выполнять запрос SELECT:

SELECT * 
FROM PhoneView

Результат выполнения запроса:

vcFamil     vcName     vcSurName   dDateBirthDay   vcPhoneNumber   
-------------------------------------------------------------------
mr.ИВАНОВ   ИВАН       ИВАНЫЧ      2004-01-31      (925) 102-51-01
mr.ИВАНОВ   ИВАН       ИВАНЫЧ      2004-01-31      (925) 163-31-52
mr.ПЕТРОВ   ИВАН       ПАЛЫЧ       1971-04-03      (923) 112-02-46
mr.СИДОРОВ  ИВАН       ПАЛЫЧ       1967-12-13      (923) 152-52-04
mr.СИДОРОВ  ИВАН       ПАЛЫЧ       1967-12-13      (095) 125-16-63
mr.КОНОНОВ  ШВАРЦ      ПЕТРОВИЧ    1981-12-13      (905) 100-10-10
...
(33 row(s) affected)

Вью предоставляет несколько преимуществ:

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

Вью создает контролируемое окружение, которое позволяет сделать доступ к нужным данным, а ненужное отключить. Данные, которые не должны отображаться по каким либо причинам могут быть спрятаны с помощью вьюшки.

Вьюшки позволяют вам хранить результат комплексного запроса. Другие запросы могут использовать этот суммирующий результат.

Итак, вьюшка – это просто запрос на языке SQL, который выбирает данные, а в базе данных она выглядит как таблица и работа с ней происходит также. Из вьюшки можно выбирать данные SQL запросами и также назначать права доступа. Получается, что будет выполняться запрос к запросу.

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

CREATE VIEW Зарплата AS
SELECT разрешенные для налоговой поля
FROM Работники, Доходы
WHERE навести связи

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

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

Когда мы ограничиваем доступ к определенным полям, то такая защита называется вертикальной. Объекты просмотра позволяют создавать и горизонтальную защиту. Например, в таблице есть определенные пользователи, которые должны быть видны только привилегированным пользователям. У таких пользователей в поле "Категория" стоит значение 1. Если запретить прямой доступ к таблице, а для всех пользователей создать вьюшку, то можно скрыть записи. Вьюшка может выглядеть следующим образом:

CREATE VIEW Зарплата AS
SELECT Список полей
FROM Работники, Доходы
WHERE навести связи
  AND Категория=1

В этом примере мы ограничиваем доступ к определенным записям, а не полям и такая защита называется горизонтальной.

Конечно же, вы можете создать и горизонтальную защиту и вертикальную в одном объекте просмотра. Этого нам никто запретить не может.

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

В каждой базе данных могут быть системные вьюшки, которые создаются сервером автоматически. Не советую разрешать к ним доступ, потому что они могут показать что-нибудь лишнее, что поможет хакеру поднять свои права или просто испортить данные. Системные вьюшки начинаются с префикса sys и в колонке Type списка светиться надпись System (если просматривать хранимые на сервере вью с помощью программы Enterprise Manager).

Когда вы создаете вью, SQL Server проверяет существование объектов, на которые ссылаются в объявлении вью. Ваше имя вью должно соответствовать правилам именования объектов базы данных. Вы должны именовать вьюшки так, чтобы их имена отличались от имен таблиц, и их можно было выделить среди других объектов. Это значит, что имя вью не должно конфликтовать не только с существующими объектами просмотра (View), но и с именами таблиц базы данных. Если бы можно было создать просмотр с именем tbPeoples, то следующим запрос не смог бы определить, откуда выбирать данные – из вью или из таблицы с таким именем:

SELECT
FROM tbPeoples

Для выполнения оператора CREATE VIEW, вы должны иметь соответствующие права, например, быть владельцем базы данных. Вы также должны иметь права на выполнение оператора SELECT всех таблиц, используемых в вью. Чтобы избежать ситуации, когда владельцем вью является один человек, а владельцем таблиц другой, всеми объектами должен владеть dbo. Всегда указывайте имя dbo при создании объектов. Например, в следующем примере показано, как PhoneView, который мы рассматривали ранее в этой главе, с явным указанием владельца (dbo):

CREATE VIEW dbo.PhoneView
AS
SELECT pl.vcFamil, pl.vcName, pl.vcSurName, 
  dDateBirthDay, vcPhoneNumber
FROM tbPeoples pl, tbPhoneNumbers pn
WHERE pn.idPeoples=*pl.idPeoples

Все поля вью должны иметь имена, и они должны быть уникальными. Поэтому, необходимо во время выполнения оператора CREATE VIEW учитывать следующие особенности:

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

Например, давайте создадим объект просмотра, который будет считать количество различных имен в таблице. Для этого запрос будет использовать группировку и функцию count:

CREATE VIEW NamesView
AS
SELECT pl.vcName, count(*)
FROM tbPeoples pl
GROUP BY vcName

Если попытаться создать такую вьюшку, то сервер вернет нам ошибку с сообщением, что для второй колонки не указано имя. Если явно указать второй колонке имя, то ошибка исчезнет:

CREATE VIEW NamesView 
AS
SELECT pl.vcName, count(*) AS Количество
FROM tbPeoples pl
GROUP BY vcName

Есть еще один способ задания полей для View – в скобках после имени вьюшки:

CREATE VIEW NamesView1(Имя, Количество)
AS
SELECT pl.vcName, count(*)
FROM tbPeoples pl
GROUP BY vcName

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

Имя                      Количество  
------------------------------------ 
АНДРЕЙ                   5
БОЛИК                    1
ВАСЯ                     1
ВИКТОР                   1
ВИТЯ                     1
...

Теперь рассмотрим пример конфликта колонок. Допустим, что мы написали следующий запрос и решили его превратить в объект просмотра:

SELECT pl.vcFamil, pl.vcName, pl.vcSurName, 
  dDateBirthDay, vcPhoneNumber, pl.idPeoples,
  pn.idPeoples
FROM tbPeoples pl, tbPhoneNumbers pn
WHERE pn.idPeoples=*pl.idPeoples

В секции SELECT поле "idPeoples" выбирается из таблицы работников и из таблицы телефонов. Если смотреть на этот код как запрос, то ошибки нет, и он выполнится. Но если попытаться создать вью:

CREATE VIEW ConflictView
AS SELECT pl.vcFamil, pl.vcName, pl.vcSurName, 
  dDateBirthDay, vcPhoneNumber, pl.idPeoples,
  pn.idPeoples
FROM tbPeoples pl, tbPhoneNumbers pn
WHERE pn.idPeoples=*pl.idPeoples

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

CREATE VIEW ConflictView
AS
SELECT pl.vcFamil, pl.vcName, pl.vcSurName, 
  dDateBirthDay, vcPhoneNumber, pl.idPeoples,
  pn.idPeoples AS PhoneNumbersID
FROM tbPeoples pl, tbPhoneNumbers pn
WHERE pn.idPeoples=*pl.idPeoples

Прежде чем создавать вью, вы должны протестировать SELECT запрос, чтобы убедиться, что он возвращает правильный набор. После этого, проверьте результат созданный вью. Как мы уже увидели, не каждый запрос SELECT может стать вьюшкой, потому что есть некоторые ограничение на запрос SELECT и результат его работы. В примере выше, мы увидели, что камнем преткновения во время создания вью может стать банальный конфликт имен полей.

Существуют и другие ограничения на запрос SELECT, которые необходимо четко соблюдать

  • нельзя использовать ключевое слово INTO;
  • нельзя использовать опции COMPUTE или COMPUTE BY;
  • можно использовать оператор ORDER BY только если используется ключевое слово TOP;
  • вью не может ссылаться на временные таблицы;
  • вью, как и таблица не может содержать более чем 1024 колонки.

3.1.2. Редактирование вью

Очень редко бывает так, что какой-то объект в таблице остается без изменений на протяжении всего цикла жизни объекта. Все в жизни развивается и изменяется и мы должны иметь возможность изменения без удаления объекта. Удаление ни одного из объектов не приносит пользы, потому что, как минимум теряются права доступа. Ведь права назначаются не имени объекта, а идентификатору объекту, а он генерируется при создании объекта.

Оператор ALTER VIEW изменяет объявление вью. Это позволяет вам сохранить разрешения. В общем виде команда выглядит следующим образом:

ALTER VIEW [ < database_name > . ] [ < owner > . ] 
         view_name [ ( column [ ,...n ] ) ] 
[ WITH < view_attribute > [ ,...n ] ] 
AS 
    select_statement 
[ WITH CHECK OPTION ]

Следующий пример изменяет PhoneView так, чтобы помимо телефона отражалась и название должности работника:

ALTER VIEW PhoneView
AS 
SELECT vcFamil, vcName, vcSurname, 
  vcPositionName, vcPhoneNumber, pn.idPeoples
FROM tbPeoples pl, tbPosition ps, tbPhoneNumbers pn
WHERE pl.idPosition=ps.idPosition
 AND pl.idPeoples=pn.idPeoples

Как видите, изменение происходит также, как и создание объекта просмотра.

3.1.3. Удаление вью

Если вам больше не нужен объект просмотра, то его следует удалить. Ничего лишнего в базе данных не должно быть, ведь не используемые объекты отрицательно влияют на безопасность. Для удаления используется оператор DROP VIEW.

DROP VIEW { view } [ ,...n ]

Можно удалять сразу несколько объектов просмотра. Следующий пример удаляет сразу три объекта:

DROP VIEW NamesView, NamesView1, ConflictView

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

3.1.4. Изменение содержимого вью

Я уже говорил о том, что с объектом просмотра можно работать также как и с простой таблицей. Это значит, что возвращаемый результат можно воспринимать как таблице и редактировать. Давайте попробуем изменить в вьюшке PhoneView фамилию работника с идентификатором 1 на Печкина:

UPDATE PhoneView
SET vcFamil='ПОЧЕЧКИН'
WHERE idPeoples=1

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

UPDATE PhoneView
SET vcPositionName='Самый генеральный директор'
WHERE vcPositionName='Генеральный директор'

Просмотрите содержимое таблицы tbPosition и убедитесь, что название должности генерального директора изменилась, хотя мы изменяли вьюшку.

Объект просмотра PhoneView выводит результат из трех таблиц сразу. А что, если мы хотим изменить поля из нескольких таблиц одновременно? Давайте попробуем выполнить следующий запрос:

UPDATE PhoneView
SET vcFamil='ПОЧЕЧКИН', 
    vcPositionName='Самый генеральный директор'
WHERE idPeoples=1

В этом примере изменяется поле фамилии, которое находится в таблицы tbPeoples и поле названия должности из таблицы tbPosition. Если попытаться выполнить этот запрос, то сервер вернет ошибку и сообщит нам, что изменять сразу несколько полей нельзя. Именно это и есть ограничение при изменении записей.

3.1.5. Удаление строк из вью

Попробуем удалить запись из вьюшки PhoneView:

DELETE 
FROM PhoneView
WHERE idPeoples=1

Результатом снова будет ошибка, потому что во время удаления, будет производиться попытка удалить полученные записи из связанных таблиц. Получается, что нельзя удалять строки из объектов просмотра, если выбираются строки из нескольких таблиц. А если выбрать из нескольких?

Давайте создадим вьюшку, которая будет выбирать записи только из одной таблицы:

CREATE VIEW PhoneView1
AS
SELECT pl.vcFamil, pl.vcName, pl.vcSurName
FROM tbPeoples pl

Теперь попробуем удалить запись:

DELETE 
FROM PhoneView1
WHERE vcFamil='КОТИКОВ'

На этот раз все пройдет успешно, и запись будет удалена, потому что объект просмотра использует поля только одной таблицы.

3.1.6. Опции объекта просмотра

Очень интересной опцией, которую можно использовать при создании объекта просмотра является ENCRYPTION, которая заставляет шифровать текст вьюшки в системных таблицах SQL сервера. Таким образом, если злоумышленник получил доступ к системе, то просмотр текста объекта просмотра останется затруднительным. Это действительно является очень полезным свойством. Защита лишней не бывает.

Давайте создадим объект просмотра, данные которого (исходный код) будут зашифрованными в системной таблице:

CREATE VIEW PhoneView1
WITH ENCRYPTION
AS
SELECT pl.vcFamil, pl.vcName, pl.vcSurName
FROM tbPeoples pl

Перед ключевым словом AS мы поставили опцию WITH ENCRYPTION. Теперь текст запроса просмотреть нельзя, даже если вы получите полный доступ к базе, и будете смотреть системные таблицы напрямую.

Предыдущая глава

2.27. Многие ко многим

Следующая глава

3.2. Хранимые процедуры

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне