Една и съща заявка, десет пъти
В седмица 4 написахте справка за среден успех по ученик: съединение на три таблици, групиране, закръгляне. Работи. Следващата седмица трябва същото, но само за 11А. После — само отличниците. После — броят на отличниците по клас. Всеки път копирате същите шест реда и променяте по нещо; при четвъртото копие някой ще забрави JOIN-а с classes и справката тихо ще излъже.
SQL има решение за това от самото си начало: заявката се записва в базата под име и оттам нататък се ползва като таблица.
CREATE VIEW — заявка с име
Изглед (view)
Заявка SELECT, запазена в базата под име. Държи се като таблица — от нея се чете със SELECT, ползва се в JOIN и в подзаявки — но не съхранява данни: при всяко обръщение СУБД изпълнява запазената заявка върху текущите таблици.
CREATE VIEW v_uspeh AS
SELECT s.id AS student_id, s.name, c.name AS klas,
ROUND(AVG(m.mark), 2) AS sreden
FROM students s
JOIN classes c ON c.id = s.class_id
JOIN marks m ON m.student_id = s.id
GROUP BY s.id;
-- Оттук нататък сложната заявка е една дума:
SELECT name, klas, sreden FROM v_uspeh WHERE klas = '11А' ORDER BY sreden DESC;- Всяка колона на изгледа трябва да има име. За изрази и агрегати това значи задължително
AS— MySQL отказва изглед с две колони с еднакво име или с колона без име. - Изгледът може да е върху всичко, което SELECT може: JOIN, GROUP BY, HAVING, подзаявки, дори друг изглед.
ORDER BYвътре в изгледа е безсмислен — редът се задава при SELECT от изгледа. Слагайте го отвън.
Изгледът като източник за справки
Смисълът на изгледа се вижда, когато върху него започнете да строите. Всичко, което умеете от седмици 2–4, работи и тук:
-- филтър и сортиране върху изгледа
SELECT name, sreden FROM v_uspeh WHERE sreden >= 5.50 ORDER BY sreden DESC;
-- групиране върху изгледа (изгледът вече е групирал по ученик - това е второ ниво)
SELECT klas, COUNT(*) AS broy, ROUND(AVG(sreden), 2) AS sreden_na_klasa
FROM v_uspeh GROUP BY klas;
-- JOIN между изглед и таблица
SELECT v.name, v.sreden, s.grade AS godishen
FROM v_uspeh v JOIN students s ON s.id = v.student_id
WHERE v.sreden < s.grade;
-- изглед върху изглед
CREATE VIEW v_otlichnici AS
SELECT name, klas, sreden FROM v_uspeh WHERE sreden >= 5.50;Изглед върху изглед
Слоевете са полезни: v_uspeh отговаря на въпроса „какъв е успехът“, v_otlichnici — „кои са отличниците“. Второто не повтаря логиката на първото, а я ползва. Но три-четири нива един върху друг стават трудни за проследяване и бавни — СУБД изпълнява всички вложени заявки наведнъж, при всяко обръщение.
Обновяеми и необновяеми изгледи
Щом изгледът се държи като таблица, може ли да се пише в него? Зависи дали СУБД може еднозначно да реши кой ред на коя таблица да промени.
| Обновяем изглед | Необновяем изглед | |
|---|---|---|
| Върху какво е | една таблица, избрани колони и редове | JOIN, GROUP BY, DISTINCT, агрегати, UNION |
| Пример | SELECT id, name, class_id FROM students WHERE class_id = 1 | v_uspeh — AVG върху три таблици |
| INSERT / UPDATE / DELETE | минават към таблицата (MySQL) | грешка — кой ред на marks да се промени, за да стане sreden = 6? |
| Колони извън изгледа | при INSERT получават стойността по подразбиране | — |
DROP VIEW v_otlichnici; -- изтрива изгледа, данните остават
DROP VIEW IF EXISTS v_uspeh; -- без грешка, ако го няма
CREATE OR REPLACE VIEW v_uspeh AS ...; -- MySQL: пренаписване на място
SHOW CREATE VIEW v_uspeh; -- MySQL: показва запазената заявкаПрава през изглед
Има и трета причина за изгледи освен удобството и актуалността: достъп. Таблицата staff съдържа ЕГН и заплата. Библиотекарят трябва да вижда кой на каква длъжност е — и нищо повече. Вместо да му давате право върху таблицата (цялата), правите изглед с двете безобидни колони и давате право само върху изгледа.
CREATE VIEW staff_public AS
SELECT name, position FROM staff;
-- следващия урок, в MySQL:
GRANT SELECT ON school.staff_public TO 'bibliotekar'@'localhost';
-- потребителят вижда изгледа, но SELECT * FROM staff му е отказанСъщото важи за редове: изглед с WHERE class_id = 1 показва на класния на 11А само неговите ученици. Изгледът е прозорец към базата, а правата решават кой през кой прозорец гледа. Продължаваме с това в урок 8.
Какво трябва да запомниш
- Изглед = SELECT с име; държи се като таблица, но не пази данни — изпълнява се при всяко обръщение.
- Ползва се като източник: SELECT с WHERE и ORDER BY, GROUP BY върху него, JOIN с таблици, изглед върху изглед.
- Всяка колона на изгледа има име — изразите и агрегатите винаги с AS; ORDER BY се слага отвън.
- Изгледът спестява писане и пази логиката на едно място, но не ускорява — за това са индексите.
- Обновяем е само прост изглед върху една таблица; изглед с JOIN/GROUP BY е само за четене.
- DROP VIEW маха изгледа, не данните; през изглед се дават права само върху част от таблицата.