Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ "ЛЬВІВСЬКА ПОЛІТЕХНІКА"
Інститут компютерних наук та інформаційних технологій
Кафедра систем автоматизованого проектування
ПОЯСНЮВАЛЬНА ЗАПИСКА
до курсового проекту
з дисципліни "Технологія розробки великих компютерних систем"
на тему: "Основи SQL "
Допущено до захисту:
Дата: _______________
Виконала:
студентка групи ІТП-12м
Бідак Н.В.
Прийняв:
Стех Ю.В
Оцінка __________
Залікова книжка № 0808553
Дата ____________
Львів 2012
Національний Університет «Львівська Політехніка»
Інститут компютерних наук та інформаційних технологій
Кафедра САПР
Дисципліна: « Технологія розробки великих компютерних систем»
Спеціальність: Компютерні науки
Курс: пятий Група: ІТП-12м Семестр: девятий
на курсовий проект студента
Бідак Н.В.
№ п/п |
Назва етапів курсової роботи |
Термін виконання етапів роботи |
Примітки |
1 |
Отримання індивідуального завдання |
||
2 |
Пошук необхідної літератури |
||
3 |
Обробка відповідної літератури |
||
4 |
Написання програми |
||
5 |
Написання теоретичної частини курсової роботи |
||
6 |
|||
7 |
Остаточна перевірка, закінчення курсової роботи |
Студент: ___________Бідак Н.В.
Керівник:___________ Стех Ю.В.
____________2012р.
Студент: Бідак Н.В.
“Основи SQL”. Курсова робота. НУ „Львівська політехніка”, каф.: САПР, дисципліна: “ Технологія розробки великих компютерних систем ”, 2012.
Дана курсова робота містить в собі 163 сторінки, 19 таблиць, 1 малюнок.
Виконання курсової роботи має за мету:
ЗМІСТ
Завдання 2
Календарний план 3
Анотація 4
Основи SQL 8
1. Введення в структуровану мову запитів SQL 8
1.1. Основні поняття 8
1.2. Стандарт і реалізація мови SQL 9
1.3. Введення в технологію клієнт-сервер 10
1.4. Типи команд SQL 12
1.5. Переваги мови SQL 13
1.6. Запис SQL операторів 14
1.7. Опис учбової бази даних 15
2. Визначення структури даних 16
2.1. Типи даних мови SQL, визначені стандартом 16
2.2. Типи даних, використовувані в SQL сервері 19
2.3. Вирази 22
2.4. Змінні 22
2.5. Управляючі Конструкції SQL 23
2.6. Основні об'єкти структури бази даних SQL -сервера 24
3. Створення бази даних і проектування таблиць 26
3.1. База даних 26
3.2. Таблиця 29
3.3. Індекси 32
4. Ефективне виконання запитів для витягання даних 36
4.1. Пропозиція SELECT 36
4.2. Пропозиція FROM 37
4.3. Пропозиція WHERE 38
4.4. Пропозиція ORDER BY 42
5. З'єднання і теоретико-множинні операції над відношеннями 42
5.1. Операція вибірки 43
5.2. Операція проекції 44
5.3. Декартовий добуток 44
5.4. Операція з'єднання по двох відношеннях (таблицях) 45
5.5. Операція об'єднання 49
5.6. Операція перетину 50
5.7. Операція різниці 50
5.8. Операція ділення відношень 50
6. Обчислення і підведення підсумків в запитах 52
6.1. Побудова обчислюваних полів 52
6.2. Використання підсумкових функцій 53
6.3. Пропозиція GROUP BY 55
6.4. Пропозиція HAVING 57
7. Побудова нетривіальних запитів 58
7.1. Поняття підзапиту 58
7.2. Використання підзапитів, що повертають одиничне значення 58
7.3. Використання підзапитів, що повертають безліч значень 60
8. Запити модифікації даних 65
8.1. Запит додавання 65
8.2. Запит видалення 67
8.3. Запит оновлення 67
8.4. Введення в поняття "Цілісність даних" 68
9. Визначення обмежень цілісності 72
9.1. Таблиці з обмеженнями в стандарті мови 72
9.2. Таблиці в середовищі MS SQL Server 75
10. Представлення 83
10.1. Визначення представлення 83
10.2. Оновлення даних в представленнях 85
10.3. Переваги і недоліки представлень 86
11. Функції користувача 89
11.1. Поняття функції користувача 89
11.2. Функції Scalar 89
11.3. Функції Inline 91
11.4. Функції Multi-statement 92
11.5. Вбудовані функції 94
11.6. Функції для роботи з датою і часом 96
12. Збережені процедури 97
12.1. Поняття збереженої процедури 97
12.2. Збережені процедури, в середовищі MS SQL Server 98
13. Курсори 104
13.1. Поняття курсору 104
13.2. Реалізація курсорів в середовищі MS SQL Server 105
13.3. Управління курсором в середовищі MS SQL Server 106
14. Тригери 114
14.1. Визначення тригера в стандарті мови SQL 114
14.2. Реалізація тригерів в середовищі MS SQL Server 115
15. Тригери в рекурсивних структурах 124
15.1. Введення в рекурсивні структури 124
15.2. Реалізація правил цілісності даних 125
15.3. Додавання запису в рекурсивну структуру 127
15.4. Зміна запису в рекурсивній структурі 128
15.5. Видалення запису з рекурсивної структури 129
16. Транзакції і блокування 131
16.1. Введення в транзакції 131
16.2. ACID -властивості транзакцій 131
16.3. Блокування 132
16.4. Управління транзакціями 133
16.5. Управління транзакціями в середовищі MS SQL Server 134
16.6. Блокування в середовищі MS SQL Server 137
16.7. Рівні ізоляції SQL Server 138
17. Основні методи захисту даних. Управління користувачами 142
17.1. Управління користувачами бази даних 142
17.2. Управління користувачами в середовищі MS SQL Server 142
17.3. Управління доступом до даних 144
17.4. Реалізація прав на доступ до об'єктів баз даних в середовищі MS SQL Server 147
18. Впровадження SQL -операторів в прикладні програми 152
18.1. SQL і прикладні програми 152
18.2. Архітектура ODBC 153
18.3. Джерела даних і ODBC 154
18.4. Взаємодія з базою даних в Java -програмах 154
18.5. Звернення до бази даних з використанням технології ADO 157
Висновок 162
Список літератури 163
Всяка професійна діяльність так чи інакше пов'язана з інформацією, з організацією її збору, зберігання, вибірки. Можна сказати, що невід'ємною частиною повсякденного життя стали бази даних, для підтримки яких потрібно деякий організаційний метод, або механізм. Такий механізм називається системою управління базами даних ( СУБД ). Отже, введемо основні поняття.
База даних (БД) - спільно використовуваний набір логічно пов'язаних даних (і їх опис), призначений для задоволення інформаційних потреб організації.
СУБД (система управління базами даних ) - програмне забезпечення, за допомогою якого користувачі можуть визначати, створювати і підтримувати базу даних, а також діставати до неї контрольований доступ.
Системи управління базами даних існують вже багато років, багато хто з них зобов'язаний своїм походженням системам з неструктурованими файлами на великих ЕОМ. Разом із загальноприйнятими сучасними технологіями в області систем управління базами даних починають з'являтися нові напрями, що обумовлено вимогами зростаючого бізнесу, об'ємами корпоративних даних, що все збільшуються, і, звичайно ж, впливом технологій Internet.
Реляційні бази даних
Управління основними потоками інформації здійснюється за допомогою так званих систем управління реляційними базами даних, які беруть свій початок в традиційних системах управління базами даних. Саме об'єднання реляційних баз даних і клієнт-серверних технологій дозволяє сучасному підприємству успішно управляти власними даними, залишаючись конкурентоздатним на ринку товарів і послуг.
Реляційні БД мають потужний теоретичний фундамент, заснований на математичній теорії відношень. Поява теорії реляційних баз даних дала поштовх до розробки ряду мов запитів, які можна віднести до двох класів :
• мови алгебри, що дозволяють виражати запити засобами спеціалізованих операторів, що застосовуються до відношень;
• мови числення предикатів, що є набором правив для запису вираження, що визначає нове відношення із заданої сукупності існуючих відношень. Отже, числення предикатів є метод визначення того відношення, яке бажано отримати як відповідь на запит із відношень, вже наявних у базі даних.
У реляційній моделі об'єкти реального світу і взаємозв'язку між ними представляються за допомогою сукупності пов'язаних між собою таблиць (відношень).
Навіть у тому випадку, коли функції СУБД використовуються для вибору інформації з однієї або декількох таблиць (тобто виконується запит ), результат також представляється в табличному вигляді. Більше того, можна виконати запит із застосуванням результатів іншого запиту.
Кожна таблиця БД представляється як сукупність рядків і стовпців, де рядки (записи) відповідають екземпляру об'єкту, конкретній події або явищу, а стовпці(поля) - атрибутам (ознакам, характеристикам, параметрам) об'єкту, події, явища.
У кожній таблиці БД потрібна наявність первинного ключа - так іменують поле або набір полів, що однозначно ідентифікує кожен екземпляр об'єкту або запис. Значення первинного ключа в таблиці БД має бути унікальним, тобто в таблиці не допускається наявність двох і більше записів з однаковими значеннями первинного ключа. Він має бути мінімально достатнім, а значить, не містити полів, видалення яких не відіб'ється на його унікальності.
Реляційні зв'язки між таблицями баз даних
Зв'язки між об'єктами реального світу можуть знаходити своє віддзеркалення в структурі даних, а можуть і матися на увазі, тобто бути присутнім на неформальному рівні.
Між двома або більше таблицями бази даних можуть існувати відношення підлеглості, які визначають, що для кожного запису головної таблиці (званою ще батьківською) можлива наявність однієї або декількох записів в підпорядкованій таблиці (званою ще дочірньою).
Виділяють три різновиди зв'язку між таблицями бази даних :
• ""один-до-багатьох";
• ""один-до-одного";
• ""багато-до-багатьох".
Відношення "один-до-багатьох"
Відношення "один-до-багатьох" має місце, коли одному запису батьківської таблиці може відповідати декілька записів дочірньої. Зв'язок "один-до-багатьох" іноді називають зв'язком "багато-до-одного". І у тому, і в іншому випадку суть зв'язку між таблицями залишається незмінною. Зв'язок "один-до-багатьох" є найпоширенішим для реляційних баз даних. Він дозволяє моделювати також ієрархічні структури даних.
Відношення "один-до-одного"
Відношення "один-до-одного" має місце, коли одному запису у батьківській таблиці відповідає один запис в дочірній. Це відношення зустрічається набагато рідше, ніж відношення "один-до-багатьох". Його використовують, якщо не хочуть, щоб таблиця БД "розпухала" від другорядної інформації, проте для читання пов'язаної інформації в декількох таблицях доводиться робити ряд операцій читання замість однієї, коли дані зберігаються в одній таблиці.
Відношення "багато-до-багатьох"
Відношення "багато-до-багатьох" застосовується в наступних випадках:
• одному запису у батьківській таблиці відповідає більше за один запис в дочірній;
• одному запису в дочірній таблиці відповідає більше за один запис у батьківській.
Всякий зв'язок "багато-до-багатьох" в реляційній базі даних необхідно замінити на зв'язок "один-до-багатьох" (одну або більше) за допомогою введення додаткових таблиць.
Ріст кількості даних, необхідність їх зберігання і обробки привели до того, що виникла потреба в створенні стандартної мови баз даних, яка могла би функціонувати в численних комп'ютерних системах різних видів. Дійсно, з її допомогою користувачі можуть маніпулювати даними незалежно від того, чи працюють вони на персональному комп'ютері, мережевій робочій станції або універсальній ЕОМ.
Однією з мов, що з'явилися в результаті розробки реляційної моделі даних, є мова SQL (Structured Query Language), яка нині отримала дуже широке поширення і фактично перетворилася на стандартну мову реляційних баз даних. Стандарт на мову SQL був випущений Американським національним інститутом стандартів (ANSI) в 1986 р., а в 1987 р. Міжнародна організація стандартів (ISO) прийняла його як міжнародного. Нинішній стандарт SQL відомий під назвою SQL/92.
З використанням будь-яких стандартів пов'язані не лише численні і цілком очевидні переваги, але і певні недоліки. Передусім, стандарти направляють в певне русло розвиток відповідної індустрії; у разі мови SQL наявність твердих засадничих принципів приводить, кінець кінцем, до сумісності його різних реалізацій і сприяє як підвищенню переносимості програмного забезпечення і баз даних в цілому, так і універсальності роботи адміністраторів баз даних. З іншого боку, стандарти обмежують гнучкість і функціональні можливості конкретної реалізації. Під реалізацією мови SQL розуміється програмний продукт SQL відповідного виробника. Для розширення функціональних можливостей багато розробників, що дотримуються прийнятих стандартів, додають до стандартної мови SQL різні розширення. Слід зазначити, що стандарти вимагають від будь-якої закінченої реалізації мови SQL наявності певних характеристик і у загальних рисах відбивають основні тенденції, які не лише призводять до сумісності між усіма конкуруючими реалізаціями, але і сприяють підвищенню значущості програмістів SQL і користувачів реляційних баз даних на сучасному ринку програмного забезпечення.
Усі конкретні реалізації мови дещо відрізняються одна від одної. В інтересах самих же виробників гарантувати, щоб їх реалізація відповідала сучасним стандартам ANSI в частині переносимості і зручності роботи користувачів. Проте кожна реалізація SQL містить удосконалення, що відповідають вимогам того або іншого сервера баз даних. Ці удосконалення або розширення мови SQL є додатковими командами і опціями, що є додаваннями до стандартного пакету і доступні в цій конкретній реалізації.
Нині мова SQL підтримується багатьма десятками СУБД різних типів, розроблених для найрізноманітніших обчислювальних платформ, починаючи від персональних комп'ютерів і закінчуючи мейнфреймами.
Усі мови маніпулювання даними, створені для багатьох СУБД до появи реляційних баз даних, були орієнтовані на операції з даними, представленими у вигляді логічних записів файлів. Зрозуміло, це вимагало від користувача детального знання організації зберігання цих і серйозних зусиль для вказівки тієї, які дані потрібні, де вони розміщуються і як їх отримати.
Дана мова SQL орієнтована на операції з даними, представленими у вигляді логічно взаємозв'язаних сукупностей таблиць -відношень. Найважливіша особливість його структур - орієнтація на кінцевий результат обробки даних, а не на процедуру цієї обробки. Мова SQL сам визначає, де знаходяться дані, індекси і навіть які найбільш ефективні послідовності операцій слід використовувати для отримання результату, а тому вказувати ці деталі в запиті до бази даних не вимагається.
У зв'язку з розширенням ринку інформаційних послуг виробники програмного забезпечення стали випускати усе більш інтелектуальні, а значить, і об'ємні програмні комплекси. Багато організацій і окремі користувачі часто не могли розмістити придбані продукти на власних ЕОМ. Для обміну інформацією і її поширення були створені мережі ЕОМ, а узагальнюючі програми і дані стали встановлювати на спеціальних файлових серверах.
Завдяки працюючим з файловими серверами СУБД, безліч користувачів отримують доступ до одних і тих же баз даних. Спрощується розробка різних автоматизованих систем управління організаціями. Проте при такому підході уся обробка запитів з програм або з терміналів призначених для користувача ЕОМ на них і виконується, тому для реалізації навіть простого запиту необхідно прочитувати з файлового сервера або записувати на нього цілі файли, а це веде до конфліктних ситуацій і перевантаження мережі. Для виключення вказаних недоліків була запропонована технологія клієнт-сервер, але при цьому знадобилася єдина мова спілкування з сервером - вибір ліг на SQL.
Технологія клієнт-сервер означає такий спосіб взаємодії програмних компонентів, при якій вони утворюють єдину систему. Як видно з самої назви, існує деякий клієнтський процес, що вимагає певних ресурсів, а також серверний процес, який ці ресурси надає. Зовсім необов'язково, щоб вони знаходилися на одному комп'ютері. Зазвичай прийнято розміщувати сервер на одному вузлі локальної мережі, а клієнтів - на інших вузлах.
У контексті бази даних клієнт управляє призначеним для користувача інтерфейсом і логікою додатка, діючи як робоча станція, на якій виконуються додатки баз даних. Клієнт приймає від користувача запит, перевіряє синтаксис і генерує запит до бази даних на мові SQL або іншій мові бази даних, відповідному логіку додатка. Потім передає повідомлення сервера, чекає вступу відповіді і форматує отримані дані для представлення їх користувачеві. Сервер приймає і обробляє запити до бази даних, після чого відправляє отримані результати назад клієнтові. Така обробка включає перевірку повноважень клієнта, забезпечення вимог цілісності, а також виконання запиту і оновлення даних. Окрім цього підтримується управління паралельністю і відновленням.
Архітектура клієнт-сервер має ряд переваг :
• забезпечується ширший доступ до існуючих баз даних ;
• підвищується загальна продуктивність системи : оскільки клієнти і сервер знаходяться на різних комп'ютерах, їх процесори здатні виконувати додатки паралельно. Налаштування продуктивності комп'ютера з сервером спрощується, якщо на нім виконується тільки робота з базою даних ;
• знижується вартість апаратного забезпечення; досить потужний комп'ютер з великим пристроєм зберігання потрібний тільки серверу - для зберігання і управління базою даних ;
• скорочуються комунікаційні витрати. Додатки виконують частину операцій на клієнтських комп'ютерах і посилають через мережу тільки запити до баз даних, що дозволяє значно скоротити об'єм що пересилаються по мережі даних;
• підвищується рівень несуперечності даних. Сервер може самостійно управляти перевіркою цілісності даних, оскільки лише на нім визначаються і перевіряються усі обмеження. При цьому кожному застосуванню не доведеться виконувати власну перевірку;
• архітектура клієнт-сервер природно відображається на архітектуру відкритих систем.
Подальше розширення дворівневої архітектури клієнт-сервер припускає розподіл функціональної частини колишнього, "товстого" (інтелектуального) клієнта на дві частини. У трирівневій архітектурі клієнт-сервер "тонкий" (неінтелектуальний) клієнт на робочій станції управляє тільки призначеним для користувача інтерфейсом, тоді як середній рівень обробки даних управляє усією іншою логікою додатка. Третій рівень - сервер бази даних. Ця трирівнева архітектура виявилася більше відповідною для деяких середовищ - наприклад, для мереж Internet і intranet, де в якості клієнта може виступати звичайний Web -браузер.
Реалізація в SQL концепції операцій, орієнтованих на табличне представлення даних, дозволила створити компактну мову з невеликим набором пропозицій. Мова SQL може використовуватися як для виконання запитів до даних, так і для побудови прикладних програм.
Основні категорії команд мови SQL призначені для виконання різних функцій, включаючи побудову об'єктів бази даних і маніпулювання ними, початкове завантаження даних в таблиці, оновлення і видалення існуючої інформації, виконання запитів до бази даних, управління доступом до неї і її загальне адміністрування.
Основні категорії команд мови SQL :
• DDL - мова визначення даних;
• DML - мова маніпулювання даними;
• DQL - мова запитів ;
• DCL - мова управління даними;
• команди адміністрування даних;
• команди управління транзакціями
Визначення структур бази даних (DDL)
Мова визначення даних (Data Definition Language, DDL) дозволяє створювати і змінювати структуру об'єктів бази даних, наприклад, створювати і видаляти таблиці. Основними командами мови DDL є наступні: CREATE TABLE, ALTER TABLE, DROP TABLE, CREATE INDEX, ALTER INDEX, DROP INDEX.
Маніпулювання даними (DML)
Мова маніпулювання даними (Data Manipulation Language, DML) використовується для маніпулювання інформацією усередині об'єктів реляційної бази даних за допомогою трьох основних команд: INSERT, UPDATE, DELETE.
Вибірка даних (DQL)
Мова запитів DQL найбільш відома користувачам реляційної бази даних, не дивлячись на те, що він включає всього одну команду SELECT. Ця команда разом зі своїми численними опціями і пропозиціями використовується для формування запитів до реляційної бази даних.
Мова управління даними (DCL - Data Control Language)
Команди управління даними дозволяють управляти доступом до інформації, що знаходиться усередині бази даних. Як правило, вони використовуються для створення об'єктів, пов'язаних з доступом до даних, а також служать для контролю над розподілом привілеїв між користувачами. Команди управління даними наступні: GRANT, REVOKE.
Команди адміністрування даних
За допомогою команд адміністрування даних користувач здійснює контроль за виконуваними діями і аналізує операції бази даних ; вони також можуть виявитися корисними при аналізі продуктивності системи. Не слід плутати адміністрування даних з адмініструванням бази даних, яке є загальним управлінням базою даних і має на увазі використання команд усіх рівнів.
Команди управління транзакціями
Існують наступні команди, що дозволяють управляти транзакціями бази даних : COMMIT, ROLLBACK, SAVEPOINT, SET TRANSACTION.
Мова SQL є основою багатьох СУБД, оскільки відповідає за фізичну структуризацію і запис даних на диск, а також за читання даних з диска, дозволяє приймати SQL -запити від інших компонентів СУБД і призначених для користувача застосувань. Таким чином, SQL - потужний інструмент, який забезпечує користувачам, програмам і обчислювальним системам доступ до інформації, що міститься в реляційних базах даних.
Основні достоїнства мови SQL полягають в наступному:
• стандартність - як вже було сказано, використання мови SQL в програмах стандартизоване міжнародними організаціями;
• незалежність від конкретних СУБД - усі поширені СУБД використовують SQL, оскільки реляційну базу даних можна перенести з однією СУБД на іншу з мінімальними доопрацюваннями;
• можливість перенесення з однієї обчислювальної системи на іншу - СУБД може бути орієнтована на різні обчислювальні системи, проте додатки, створені за допомогою SQL, допускають використання як для локальних БД, так і для великих розрахованих на багато користувачів систем;
• реляційна основа мови - SQL є мовою реляційних БД, тому він став популярним тоді, коли отримала широке поширення реляційна модель представлення даних. Таблична структура реляційної БД добре зрозуміла, а тому мова SQL проста для вивчення;
• можливість створення інтерактивних запитів - SQL забезпечує користувачам негайний доступ до даних, при цьому в інтерактивному режимі можна отримати результат запиту за дуже короткий час без написання складної програми;
• можливість програмного доступу до БД - мову SQL легко використовувати в додатках, яким необхідно звертатися до баз даних. Одні і ті ж оператори SQL вживаються як для інтерактивного, так і програмного доступу, тому частини програм, що містять звернення до БД, можна спочатку перевірити в інтерактивному режимі, а потім вбудовувати в програму;
• забезпечення різного представлення даних - за допомогою SQL можна представити таку структуру даних, що той або інший користувач бачитиме різні їх представлення. Крім того, дані з різних частин БД можуть бути скомбіновані і представлені у вигляді однієї простої таблиці, а значить, представлення придатні для посилення захисту БД і її налаштування під конкретні вимоги окремих користувачів;
• можливість динамічної зміни і розширення структури БД - мова SQL дозволяє маніпулювати структурою БД, тим самим забезпечуючи гнучкість з точки зору пристосованості БД до вимог предметної області, що змінюються;
• підтримка архітектури клієнт-сервер - SQL - одно з кращих засобів для реалізації додатків на платформі клієнт-сервер. SQL служить сполучною ланкою між клієнтською системою, що взаємодіє з користувачем, і серверною системою, що управляє БД, дозволяючи кожній з них зосередитися на виконанні своїх функцій.
Будь-яка мова роботи з базами даних повинна надавати користувачеві наступні можливості:
• створювати бази даних і таблиці з повним описом їх структури;
• виконувати основні операції маніпулювання даними, зокрема, вставку, модифікацію і видалення даних з таблиць ;
• виконувати прості і складні запити, що здійснюють перетворення даних.
Крім того, мова роботи з базами даних повинна вирішувати усі вказані вище завдання при мінімальних зусиллях з боку користувача, а структура і синтаксис його команд - досить прості і доступні для вивчення. І нарешті, він має бути універсальним, тобто відповідати деякому визнаному стандарту, що дозволить використовувати один і той же синтаксис і структуру команд при переході від однієї СУБД до іншої. Мова SQL задовольняє практично усім цим вимогам.
Мова SQL є прикладом мови з орієнтацією, що трансформується, або ж мови, призначеної для роботи з таблицями з метою перетворення вхідних даних до необхідного вихідного виду. Він включає тільки команди визначення і маніпулювання даними і не містить яких-небудь команд управління ходом обчислень. Подібні завдання повинні вирішуватися або за допомогою мов програмування або управління завданнями, або інтерактивно, в результаті дій, що виконуються самим користувачем. Унаслідок подібної незавершеності в плані організації обчислювального процесу мова SQL може використовуватися двома способами. Перший передбачає інтерактивну роботу, що полягає у введенні користувачем з терміналу окремих SQL -операторів. Другий полягає у впровадженні SQL -операторів в програми на процедурних мовах. Мова SQL відносно проста у вивченні. Оскільки це не процедурна мова, в нім необхідно вказувати, яка інформація має бути отримана, а не як її можна отримати. Інакше кажучи, SQL не вимагає вказівки методів доступу до даних. Як і більшість сучасних мов, він підтримує вільний формат запису операторів. Це означає, що при введенні окремі елементи операторів не пов'язані з фіксованими позиціями екрану. Мова SQL може використовуватися широким кругом фахівців, включаючи адміністраторів баз цих, прикладних програмістів і безліч інших кінцевих користувачів.
Мова SQL - перша і доки єдина стандартна мова для роботи з базами даних, який отримав досить широке поширення. Практично усі видатні розробники СУБД нині створюють свої продукти з використанням мови SQL або з SQL -інтерфейсом. У нього зроблені величезні інвестиції як з боку розробників, так і з боку користувачів. Він став частиною архітектури додатків, є стратегічним вибором багатьох великих і впливових організацій.
Мова SQL використовується в інших стандартах і навіть чинить вплив на розробку інших стандартів як інструмент визначення (наприклад, стандарт Remote Data Access, RDA). Створення мови сприяло не лише виробленню необхідних теоретичних основ, але і підготовці успішно реалізованих технічних рішень. Це особливо справедливо відносно оптимізації запитів, методів розподілу даних і реалізації засобів захисту. Почали з'являтися спеціалізовані реалізації мови, призначені для нових ринків : системи управління обробкою транзакцій (OnLine Transaction Processing, OLTP ) і системи оперативної аналітичної обробки або системи підтримки ухвалення рішень (OnLine Analytical Processing, OLAP ). Вже відомі плани подальших розширень стандарту, що включають підтримку розподіленої обробки, об'єктно-орієнтованого програмування, розширень користувачів і мультимедіа.
Для успішного вивчення мови SQL необхідно привести короткий опис структури SQL-операторів і нотації, які використовуються для визначення формату різноманітних конструкцій мови. Оператор SQL складається із зарезервованих слів, а також із слів, визначуваних користувачем. Зарезервовані слова є постійною частиною мови SQL і мають фіксоване значення. Їх слід записувати в точності так, як це встановлено, не можна розбивати на частини для перенесення з одного рядка на іншу. Слова, визначувані користувачем, задаються ним самим (відповідно до синтаксичних правил) і є ідентифікаторами або іменами різних об'єктів бази даних. Слова в операторові розміщуються також відповідно до встановлених синтаксичних правил.
Ідентифікатори мови SQL призначені для позначення об'єктів у базі даних і є іменами таблиць, представлень, стовпців і інших об'єктів бази даних. Символи, які можуть використовуватися в створюваних користувачем ідентифікаторах мови SQL, мають бути визначені як набір символів. Стандарт SQL задає набір символів, який використовується за умовчанням, - він включає рядкові і прописні букви латинського алфавіту ( A - Z, a - z ), цифри ( 0-9 ) і символ підкреслення ( _ ). На формат ідентифікатора накладаються наступні обмеження:
• ідентифікатор може мати довжину до 128 символів;
• ідентифікатор повинен починатися з букви;
• ідентифікатор не може містити пропуски.
<ідентифікатор>::=<буква>
{<буква>|<цифра>}[,..n]
Більшість компонентів мови не чутлива до регістра. Оскільки у мови SQL вільний формат, окремі SQL -операторі і їх послідовності матимуть більше читаний вигляд при використанні відступів і вирівнювання.
Мова, в термінах якої дається опис мови SQL, називається метамовою . Синтаксичні визначення зазвичай задають за допомогою спеціальної металінгвістичної символіки, званою Бекуса-Науера формулами (БНФ). Прописні букви використовуються для запису зарезервованих слів і повинні вказуватися в операторах точно так, як це буде показано. Рядкові букви вживаються для запису слів, визначуваних користувачем. Вживані в нотації БНФ символи і їх позначення показані в таблиці.
Таблиця 1.1. |
|
Символ |
Позначення |
::= |
Рівно за визначенням |
| |
Необхідність вибору одного з декількох приведених значень |
<.> |
Описана за допомогою метамови структура мови |
{.} |
Обов'язковий вибір деякої конструкції із списку |
[.] |
Необов'язковий вибір деякої конструкції із списку |
[,.n] |
Необов'язкова можливість повторення конструкції від нуля до декількох разів |
У подальшому викладі в якості прикладу використовуватиметься невелика база даних, що відбиває процес постачання або продажу деякого товару постійним клієнтам.
Виходячи з аналізу предметної області, можна виділити два типи сутностей - ТОВАР і КЛІЄНТ, які пов'язані між собою відношенням "багато-до-багатьох", оскільки кожен покупець може купити багато найменувань товару, а кожен товар може бути куплений багатьма покупцями. Проте реляційна модель даних вимагає замінити відношення "багато-до-багатьох" на декілька відношень "один-до-багатьох". Додамо ще один тип сутностей, процес продажу товарів, що відображає, - УГОДА.
Встановимо зв'язки між об'єктами. Один покупець може неодноразово купувати товари, тому між об'єктами КЛІЄНТ і УГОДА є зв'язок "один-до-багатьох". Кожне найменування товару може неодноразово брати участь в угодах, в результаті між об'єктами ТОВАР і УГОДА є зв'язок "один-до-багатьох".
Визначимо атрибути і зв'яжемо їх з сутностями і зв'язками. До об'єкту ТОВАР відносяться такі характеристики, як назва, тип, ціна, сорт. До об'єкту КЛІЄНТ - ім'я, по батькові, прізвище, фірма, місто, телефон. Тип суті УГОДА може бути охарактеризована такими ознаками, як дата і кількість проданого товару.
Важливим етапом в створенні бази даних є визначення атрибутів, які однозначно визначають кожен екземпляр суті, тобто виявлення первинних ключів.
Для таблиці ТОВАР назва не може служити первинним ключем, оскільки товари різних типів можуть мати однакові назви, тому введемо первинний ключ КодТовару, під яким можна розуміти, наприклад, артикул товару. Так само ні Ім'я, ні Фірма, ні Місто не можуть служити первинним ключем в таблиці КЛІЄНТ. Введемо первинний ключ КодКлієнта, під яким можна розуміти номер паспорта, ідентифікаційний номер платника податків або будь-який інший атрибут, що однозначно визначає кожного клієнта. Для таблиці УГОДА первинним ключем є поле КодУгоди, оскільки воно однозначно визначає дату, покупця і інші елементи даних. В якості первинного ключа можна було б вибрати не одно поле, а деяку сукупність полів, але для ілюстрації конструкцій мови обмежимося простими первинними ключами.
Встановимо зв'язки між таблицями. Один покупець може неодноразово купувати товари. Тому між таблицями КЛІЄНТ і УГОДА є зв'язок "один-до-багатьох" по полю КодКлієнта.
Кожен покупець може придбати декілька різних товарів. Тому між таблицями ТОВАР і УГОДА є зв'язок "один-до-багатьох" по полю КодТовару.
Тепер треба створити зв'язки між таблицями бази даних. Для цього помістимо копії первинних ключів з батьківської таблиці ( таблиці з боку "один") в дочірню таблицю ( таблицю з боку "багато"). Для організації зв'язку між таблицями ТОВАР і УГОДА помістимо копію поля КодТовару з таблиці ТОВАР в таблицю УГОДА. Для організації зв'язку між таблицями КЛІЄНТ і УГОДА помістимо копію поля КодКлієнта з таблиці КЛІЄНТ в таблицю УГОДА. Для таблиці УГОДА поля КодКлієнта і КодТовару є зовнішніми (чужими) ключами. В результаті отримаємо наступну структуру бази даних.
Мал. 1.1. Приклад структури бази даних.
Дані - це сукупна інформація, що зберігається у базі даних у вигляді одного з декількох різних типів . За допомогою типів даних встановлюються основні правила для даних, що містяться в конкретному стовпці таблиці, у тому числі розмір пам'яті, що виділяється для них.
У мові SQL є шість скалярних типів даних, визначених стандартом. Їх короткий опис представлений в таблиці.
Таблиця 2.1. |
|
Тип даних |
Оголошення |
Символьний |
CHAR | VARCHAR |
Бітовий |
BIT | BIT VARYING |
Точні числа |
NUMERIC | DECIMAL | INTEGER | SMALLINT |
Закруглені числа |
FLOAT | REAL | DOUBLE PRECISION |
Дата/час |
DATE | TIME | TIMESTAMP |
Інтервал |
INTERVAL |
Символьні дані
Символьні дані складаються з послідовності символів, що входять у визначений творцями СУБД набір символів. Оскільки набори символів є специфічними для різних діалектів мови SQL, перелік символів, які можуть входити до складу значень даних символьного типу, також залежить від конкретної реалізації. Найчастіше використовуються набори символів ASCII і EBCDIC. Для визначення даних символьного типу використовується наступний формат:
<символьний_тип>::=
{ CHARACTER [ VARYING][довжина] | [CHAR |
VARCHAR][довжина]}
При визначенні стовпця з символьним типом даних параметр довжина застосовується для вказівки максимальної кількості символів, які можуть бути поміщені в цей стовпець (за умовчанням набуває значення 1 ). Символьний рядок може бути визначений як що має фіксовану або змінну ( VARYING ) довжину. Якщо рядок визначений з фіксованою довжиною значень, то при введенні в неї меншої кількості символів значення доповнюється до вказаної довжини пропусками, що додаються справа. Якщо рядок визначений зі змінною довжиною значень, то при введенні в неї меншої кількості символів у базі даних будуть збережені тільки введені символи, що дозволить досягти певної економії зовнішньої пам'яті.
Бітові дані
Бітовий тип даних використовується для визначення бітових рядків, тобто послідовності двійкових цифр (бітів), кожна з яких може мати значення або 0, або 1 . Дані бітового типу визначаються за допомогою наступного формату:
<бітовий_тип>::=
BIT [VARYING][довжина]
Точні числа
Тип точних числових даних застосовується для визначення чисел, які мають точне представлення, тобто числа складаються з цифр, необов'язкової десяткової точки і необов'язкового символу знаку. Дані точного числового типу визначаються точністю і завдовжки дробовій частині. Точність задає загальну кількість значущих десяткових цифр числа, в яке входить довжина як цілої частини, так і дробовою, але без урахування самої десяткової точки. Масштаб вказує кількість дробових десяткових розрядів числа.
<фіксований_тип>::=
{NUMERIC[точність[,масштаб]]|{DECIMAL|DEC}
[точність[, масштаб]]
| {INTEGER |INT}| SMALLINT}
Типи NUMERIC і DECIMAL призначені для зберігання чисел в десятковому форматі. За умовчанням довжина дробової частини дорівнює нулю, а точність, що приймається за умовчанням, залежить від реалізації. Тип INTEGER ( INT ) використовується для зберігання великих позитивних або негативних цілих чисел. Тип SMALLINT - для зберігання невеликих позитивних або негативних цілих чисел; в цьому випадку витрата зовнішньої пам'яті істотно скорочується.
Закруглені числа
Тип закруглених чисел застосовується для опису даних, які не можна точно представити в комп'ютері, зокрема дійсних чисел. Закруглені числа або числа з плаваючою точкою представляються в науковій нотації, при якій число записується за допомогою мантиси, помноженої на певну міру десяти (порядок), наприклад:10Е3, +5.2Е6, -0.2Е-4 . Для визначення даних речового типу використовується формат:
<речовий_тип>::=
{ FLOAT [точність]| REAL |
DOUBLE PRECISION}
Параметр точність задає кількість значущих цифр мантиси. Точність типів REAL і DOUBLE PRECISION залежить від конкретної реалізації.
Дата і час
Тип даних "дата/час" використовується для визначення моментів часу з деякою встановленою точністю. Стандарт SQL підтримує наступний формат:
<тип_дати/часу>::=
{DATE | TIME[точність][WITH TIME ZONE]|
TIMESTAMP[точність][WITH TIME ZONE]}
Тип даних DATE використовується для зберігання календарних дат, що включають поля YEAR (рік), MONTH (місяць) і DAY (день). Тип даних TIME - для зберігання відміток часу, що включають поля HOUR (годинник), MINUTE (хвилини) і SECOND (секунди). Тип даних TIMESTAMP - для спільного зберігання дати і часу. Параметр точність задає кількість дробових десяткових знаків, що визначають точність збереження значення в полі SECOND. Якщо цей параметр опускається, за умовчанням його значення для стовпців типу TIME набуває рівним нулю (тобто зберігаються цілі секунди), тоді як для полів типу TIMESTAMP він приймається рівним 6. Наявність ключового слова WITH TIME ZONE визначає використання полів TIMEZONE HOUR і TIMEZONE MINUTE, тим самим задаються година і хвилини зміщення зонального часу по відношенню до універсального координатного часу (Грінвічському часу).
Дані типу INTERVAL використовуються для представлення періодів часу.
Поняття домена
Домен - це набір допустимих значень для одного або декількох атрибутів. Якщо в таблиці бази даних або в декількох таблицях є присутніми стовпці, що мають одні і ті ж характеристики, можна описати тип такого стовпця і його поведінку через домен, а потім поставити у відповідність кожному з однакових стовпців імя домена. Домен визначає усі потенційні значення, які можуть бути присвоєні атрибуту.
Стандарт SQL дозволяє визначити домен за допомогою наступного оператора:
<визначення_домена>::=
CREATE DOMAIN ім'я_домена [AS]
тип_даних
[ DEFAULT значення]
[ CHECK (допустимі_значення)]
Кожному створюваному домену привласнюється ім'я, тип даних, значення за умовчанням і набір допустимих значень. Слід зазначити, що приведений формат оператора являється неповним. Тепер при створенні таблиці можна вказати замість типу даних ім'я домена.
Видалення доменів з бази даних виконується за допомогою оператора:
DROP DOMAIN ім'я_домена [ RESTRICT |
CASCADE]
У разі вказівки ключового слова CASCADE будь-які стовпці таблиць, створені з використанням домена, що видаляється, будуть автоматично змінені і описані як вміщуючі дані того типу, який був вказаний у визначенні домена, що видалявся.
Альтернативою доменам в середовищі SQL Server являються призначені для користувача типи даних.
Системні типи даних
Один з основних моментів процесу створення таблиці - визначення типів даних для її полів. Тип даних поля таблиці визначає тип інформації, яка розміщуватиметься в цьому полі. Поняття типу даних в SQL Server повністю адекватно поняттю типу даних в сучасних мовах програмування. SQL -сервер підтримує велике число різних типів даних : текстові, числові, двійкові (див. таблицю 2.2).
Таблиця 2.2. |
|||
image |
smalldatetime |
bit |
binary |
text |
real |
decimal |
char |
uniqueidentifier |
money |
numeric |
timestamp |
tinyint |
datetime |
smallmoney |
nvarchar |
smallint |
float |
varbinary |
nchar |
int |
ntext |
varchar |
sysname |
Приведемо короткий огляд типів даних SQL Server.
Для зберігання символьної інформації використовуються символьні типи даних, до яких відносяться CHAR (довжина), VARCHAR (довжина), NCHAR (довжина), NVARCHAR (довжина). Останні два призначені для зберігання символів Unicode. Максимальне значення довжини обмежене 8000 знаками ( 4000 - для символів Unicode).
Зберігання символьних даних великого об'єму (до 2 Гб) здійснюється за допомогою текстових типів даних TEXT і NTEXT.
До цілочисельних типів даних відносяться INT ( INTEGER ), SMALLINT, TINYINT, BIGINT. Для зберігання даних цілочисельного типу використовується, відповідно, 4 байти (діапазон від - 231 до 231-1 ), 2 байти (діапазон від - 215 до 215-1 ), 1 байт (діапазон від 0 до 255 ) або 8 байт (діапазон від - 263 до 263-1 ). Об'єкти і вирази цілочисельного типу можуть застосовуватися у будь-яких математичних операціях.
Числа, у складі яких є десяткова точка, називаються нецілочисельними. Нецілочисельні дані розділяються на два типи - десяткові і приблизні.
До десяткових типів даних відносяться типи DECIMAL [(точність[,масштаб])] чи DEC і NUMERIC [(точність[,масштаб])]. Типи даних DECIMAL і NUMERIC дозволяють самостійно визначити формат точності числа з плаваючою комою. Параметр точність вказує максимальна кількість цифр даних цього типу (до і після десяткової точки в сумі), що вводяться, а параметр масштаб - максимальна кількість цифр, розташованих після десяткової точки. У звичайному режимі сервер дозволяє вводити не більше 28 цифр, використовуваних в типах DECIMAL і NUMERIC (від 2 до 17 байт).
До приблизних типів даних відносяться FLOAT (точність до 15 цифр, 8 байт) і REAL (точність до 7 цифр, 4 байти). Ці типи представляють дані у форматі з плаваючою комою, тобто для представлення чисел використовується мантиса і порядок, що забезпечує однакову точність обчислень незалежно від того, наскільки мало або велике значення.
Для зберігання інформації про дату і час призначені такі типи даних, як DATETIME і SMALLDATETIME, що використовують для представлення дати і часу 8 і 4 байти відповідно.
Типи даних MONEY і SMALLMONEY роблять можливим зберігання інформації грошового типу ; вони забезпечують точність значень до 4 знаків після коми і використовують 8 і 4 байти відповідно.
Тип даних BIT дозволяє зберігати один біт, який набуває значень 0 або 1.
У середовищі SQL Server реалізований ряд спеціальних типів даних.
Тип даних TIMESTAMP застосовується в якості індикатора зміни версії рядка в межах бази даних.
Тип даних UNIQUEIDENTIFIER використовується для зберігання глобальних унікальних ідентифікаційних номерів.
Тип даних SYSNAME призначений для ідентифікаторів об'єктів.
Тип даних SQL_VARIANT дозволяє зберігати значення будь-якого з підтримуваних SQL Server типів даних за винятком TEXT, NTEXT, IMAGE і TIMESTAMP.
Тип даних TABLE, подібно до тимчасових таблиць, забезпечує зберігання набору рядків, призначених для наступної обробки. Тип даних TABLE може застосовуватися тільки для визначення локальних змінних і повертаних призначеними для користувача функціями значень. Приклад використання типу даних TABLE наведений в лекції, присвяченій функціям користувача.
Тип даних CURSOR потрібний для роботи з такими об'єктами, як курсори, і може бути затребуваний тільки для змінних і параметрів процедур, що зберігаються. Курсори SQL Server є механізмом обміну даними між сервером і клієнтом. Курсор дозволяє клієнтським застосуванням працювати не з повним набором даних, а лише з однією або декількома рядками. Приклади використання даних типу CURSOR ми розглянемо в лекціях, присвячених курсорам і процедурам, що зберігаються.
Створення користувацького типу даних
У системі SQL -сервера є підтримка призначених для користувача типів даних. Вони можуть використовуватися при визначенні якого-небудь специфічного або часто вживаного формату.
Створення користувацького типу даних здійснюється виконанням системної процедури :
sp_addtype [@typename=]type,[@phystype=]
system_data_type
[,[@nulltype=]'null_type']
Тип даних system_data_type вибирається з наступної таблиці.
Таблиця 2.3. |
|||
image |
smalldatetime |
decimal |
bit |
text |
real |
'decimal[(p[,s])]' |
'binary(n)' |
uniqueidentifier |
datetime |
numeric |
'char(n)' |
smallint |
float |
'numeric[(p[,s])]' |
'nvarchar(n)' |
int |
'float(n)' |
'varbinary(n)' |
|
ntext |
'varchar(n)' |
'nchar(n)' |
EXEC sp_addtype bir, DATETIME, 'NULL'
чи
EXEC sp_addtype bir, DATETIME, 'NOT NULL'
Приклад 2.1. Створення користувацького типу даних bir.
CREATE TABLE tab
((id_n INT IDENTITY(1,1) PRIMARY KEY
names VARCHAR(40),
birthday BIR)
Приклад 2.2. Використання користувацького типу даних bir при створенні таблиці.
Видалення користувацького типу даних відбувається в результаті виконання процедури sp_droptype type : EXEC sp_droptype 'bir'
Отримання інформації про типи дані
Отримати список усіх типів даних, включаючи призначені для користувача, можна з системної таблиці systypes :
SELECT * FROM systypes
Перетворення типів
Нерідко вимагається конвертувати значення одного типу в значення іншого. Найчастіше виконується конвертація чисел в символьні дані і навпаки, для цього використовується спеціалізована функція STR. Для виконання інших перетворень SQL Server пропонує універсальні функції CONVERT і CAST, за допомогою яких значення одного типу перетворюються в значення іншого типу, якщо такі зміни взагалі можливі. CONVERT і CAST приблизно однакові і можуть бути взаємозамінними.
CAST(вираження AS тип_даних)
CONVERT(тип_даних[(довжина)]
вираження [, стиль])
За допомогою аргументу стиль можна управляти стилем представлення значень наступних типів даних : дата/час, грошовий або нецілочисельний.
DECLARE @d DATETIME
DECLARE @s CHAR(8)
SET @s='29.10.01'
SET @d=CAST(@s AS DATETIME)
Приклад 2.3. Перетворення даних символьного типу до даних типу дата/час.
Разом з типами даних засадничими поняттями при роботі з мовою SQL в середовищі MS SQL Server являються вирази, оператори, змінні, що управляють конструкції.
Вирази є комбінацією ідентифікаторів, функцій, знаків логічних і арифметичних операцій, констант і інших об'єктів. Вираження може бути використане в якості аргументу в командах, процедурах, що зберігаються, або запитах.
Вираження складається з операндів (власне даних ) і операторів (знаків операцій, вироблюваних над операндами ). Операндами можуть виступати константи, змінні, імена стовпців, функції, підзапити.
Оператори - це знаки операцій над одним або декількома виразами для створення нового вираження. Серед операторів можна виділити унарні оператори, оператори присвоєння, арифметичні оператори, строкові оператори, оператори порівняння, логічні оператори, бітові оператори .
У середовищі SQL Server існує декілька способів передання даних між командами. Один з них - передача даних через локальні змінні. Перш ніж використовувати яку-небудь змінну, її слід оголосити. Оголошення змінної виконується командою DECLARE, що має наступний формат :
DECLARE {@ім'я_змінної тип_даних }
[,..n]
Значення змінної можна присвоїти за допомогою команд SET і SELECT. За допомогою команди SELECT змінній можна присвоїти не лише конкретне значення, але і результат обчислення вираження.
DECLARE @a INT
SET @a=10
Приклад 2.4. Використання SET для надання значення локальній змінній.
DECLARE @k INT
SELECT @k=SUM(кількість) FROM Товар
Приклад 2.5. Використання SELECT для привласнення локальної змінної результату обчислень.
Мова SQL є непроцедурною, але проте в середовищі SQL Server передбачений ряд різних управляючих конструкцій, без яких неможливе написання ефективних алгоритмів.
Угрупування двох і більше команд в єдиний блок здійснюється з використанням ключових слів BEGIN і END :
<блок_операторів>::=
BEGIN
{ sql_оператор | блок_операторів }
END
Згруповані команди сприймаються інтерпретатором SQL як одна команда. Подібне угрупування потрібно для конструкцій поліваріантних розгалужень, умовних і циклічних конструкцій. Блоки BEGIN..END можуть бути вкладеними.
Деякі команди SQL не повинні виконуватися разом з іншими командами (йдеться про команди резервного копіювання, зміни структури таблиць, процедур, що зберігаються, і подібних до них), тому їх спільне включення в конструкцію BEGIN..END не допускається.
Нерідко певна частина програми повинна виконуватися тільки при реалізації деякої логічної умови. Синтаксис умовного оператора показаний нижче:
<умовний_оператор>::=
IF балка_вираження
{ sql_оператор | блок_операторів }
[ ELSE
{sql_оператор | блок_операторів } ]
Цикли організовуються за допомогою наступної конструкції:
<оператор_циклу>::=
WHILE балка_вираження
{ sql_оператор | блок_операторів }
[ BREAK ]
{ sql_оператор | блок_операторів }
[ CONTINUE ]
Цикл можна примусово зупинити, якщо в його тілі виконати команду BREAK. Якщо ж треба почати цикл наново, не чекаючи виконання усіх команд в тілі, необхідно виконати команду CONTINUE.
Для заміни безлічі поодиноких або вкладених умовних операторів використовується наступна конструкція:
<оператор_поліваріантних_розгалужень>::=
CASE вхідне_значення
WHEN {значення_для_порівняння |
балка_вираження } THEN
вых_вираження [,..n]
[ ELSE інакше_вих_вираження ]
END
Якщо вхідне значення і значення для порівняння співпадають, то конструкція повертає вихідне значення. Якщо ж значення вхідного параметра не знайдене ні в одній із строк WHEN..THEN, то тоді буде повернено значення, вказане після ключового слова ELSE.
Розглянемо логічну структуру бази даних.
Логічна структура визначає структуру таблиць, взаємини між ними, список користувачів, Збережені процедури, правила, умовчання і інші об'єкти бази даних.
Логічно дані в SQL Server організовані у вигляді об'єктів. До основних об'єктів бази даних SQL Server відносяться об'єкти, представлені в таблиці 2.4.
Таблиця 2.4. |
|
Tables |
Таблиці бази даних, в яких зберігаються власне дані |
Views |
Перегляди (віртуальні таблиці) для відображення даних з таблиць |
Stored Procedures |
Збережені процедури |
Triggers |
Тригери - спеціальні Збережені процедури, викликаються при зміні даних в таблиці |
User Defined function |
Створювані користувачем функції |
Indexes |
Індекси - додаткові структури, покликані підвищити продуктивність роботи з даними |
User Defined Data Types |
Визначувані користувачем типи даних |
Keys |
Ключі - один з видів обмежень цілісності даних |
Constraints |
Обмеження цілісності - об'єкти для забезпечення логічної цілісності даних |
Users |
Користувачі, що мають доступ до бази даних |
Roles |
Ролі, що дозволяють об'єднувати користувачів в групи |
Rules |
Правила бази даних, що дозволяють контролювати логічну цілісність даних |
Defaults |
Умовчання або стандартні установки бази даних |
Приведемо короткий огляд основних об'єктів баз даних.
Таблиці
Усі дані в SQL містяться в об'єктах, званих таблицями. Таблиці є сукупністю яких-небудь відомостей про об'єкти, явища, процеси реального світу. Ніякі інші об'єкти не зберігають дані, але вони можуть звертатися до даних в таблиці. Таблиці в SQL мають таку ж структуру, що і таблиці усіх інших СУБД і містять:
• cтроки; кожен рядок (чи запис) є сукупністю атрибутів (властивостей) конкретного екземпляра об'єкту ;
• cтовпці; кожен стовпець (поле) є атрибутом або сукупністю атрибутів. Поле рядка є мінімальним елементом таблиці. Кожен стовпець в таблиці має певне ім'я, тип даних і розмір.
Представлення
Представленнями (переглядами) називають віртуальні таблиці, вміст яких визначається запитом. Подібно до реальних таблиць, представлення містять іменовані стовпці і рядки з даними. Для кінцевих користувачів представлення виглядає як таблиця, але насправді воно не містить даних, а лише представляє дані, розташовані в одній або декількох таблицях. Інформація, яку бачить користувач через представлення, не зберігається у базі даних як самостійний об'єкт.
Збережені процедури
Збережені процедури, є групою команд SQL, об'єднаних в один модуль. Така група команд компілюється і виконується як єдине ціле.
Тригери
Тригерами називається спеціальний клас процедур, що зберігаються, автоматично запускаються при додаванні, зміні або видаленні даних з таблиці.
Функції
Функції в мовах програмування - це конструкції, що містять часто виконуваний код. Функція виконує які-небудь дії над даними і повертає деяке значення.
Індекси
Індекс - структура, пов'язана з таблицею або представленням і призначена для прискорення пошуку інформації в них. Індекс визначається для одного або декількох стовпців, званих індексованими стовпцями. Він містить відсортовані значення індексованого стовпця або стовпців з посиланнями на відповідний рядок початкової таблиці або представлення. Підвищення продуктивності досягається за рахунок сортування даних. Використання індексів може істотно підвищити продуктивність пошуку, проте для зберігання індексів потрібний додатковий простір у базі даних.
Призначені для користувача типи даних
Призначені для користувача типи даних - це типи даних, які створює користувач на основі системних типів даних, коли в декількох таблицях необхідно зберігати однотипні значення; причому треба гарантувати, що стовпці в таблиці матимуть однаковий розмір, тип даних і чутливість до значень NULL .
Обмеження цілісності
Обмеження цілісності - механізм, що забезпечує автоматичний контроль відповідності даних встановленим умовам (чи обмеженням). Обмеження цілісності мають пріоритет над тригерами, правилами і значеннями за умовчанням. До обмежень цілісності відносяться: обмеження на значення NULL, перевірочні обмеження, обмеження унікальності (унікальний ключ), обмеження первинного ключа і обмеження зовнішнього ключа. Останні три обмеження тісно пов'язано з поняттям ключів.
Правила
Правила використовуються для обмеження значень, що зберігаються в стовпці таблиці або в призначеному для користувача типі даних. Вони існують як самостійні об'єкти бази даних, які зв'язуються із стовпцями таблиць і призначеними для користувача типами даних. Контроль значень даних може бути реалізований і за допомогою обмежень цілісності.
Умовчання
Умовчання - самостійний об'єкт бази даних, що представляє значення, яке буде присвоєно елементу таблиці при вставці рядка, якщо в команді вставки явно не вказано значення для цього стовпця.
Створення бази даних
У різних СУБД процедура створення баз даних зазвичай закріплюється тільки за адміністратором баз даних. У розрахованих на одного користувача системах що приймається по замовчуванню база даних може бути сформована безпосередньо в процесі установки і налаштування самої СУБД. Стандарт SQL не визначає, як повинні створюватися бази даних, тому в кожному з діалектів мови SQL зазвичай використовується свій підхід. Відповідно до стандарту SQL, таблиці і інші об'єкти бази даних існують в деякому середовищі. Окрім усього іншого, кожне середовище складається з одного або більше за каталоги, а кожен каталог - з набору схем. Схема є пойменованою колекцією об'єктів бази даних, деяким чином пов'язаних один з одним (усі об'єкти у базі даних мають бути описані в тій або іншій схемі ). Об'єктами схеми можуть бути таблиці, представлення, домени, твердження, зіставлення, тлумачення і набори символів. Усі вони мають одного і того ж власника і безліч загальних значень, що приймаються за умовчанням.
Стандарт SQL залишає за розробниками СУБД право вибору конкретного механізму створення і знищення каталогів, проте механізм створення і видалення схем регламентується за допомогою операторів CREATE SCHEMA і DROP SCHEMA. У стандарті також вказано, що у рамках оператора створення схеми повинна існувати можливість визначення діапазону привілеїв, доступних користувачам створюваної схеми. Проте конкретні чини визначення подібних привілеїв в різних СУБД розрізняються.
Нині оператори CREATE SCHEMA і DROP SCHEMA реалізовані в дуже небагатьох СУБД. У інших реалізаціях, наприклад, в СУБД MS SQL Server, використовується оператор CREATE DATABASE.
Створення бази даних в середовищі MS SQL Server
Процес створення бази даних в системі SQL -сервера складається з двох етапів: спочатку організовується сама база даних, а потім журнал транзакцій, що належить їй. Інформація розміщується у відповідних файлах, що мають розширення *.mdf (для бази даних ) і *.ldf. (для журналу транзакцій ). У файлі бази даних записуються відомості про основні об'єкти ( таблицях, індексах, представленнях і так далі), а у файлі журналу транзакцій - про процес роботи з транзакціями (контроль цілісності даних, стани бази даних до і після виконання транзакцій).
Створення бази даних в системі SQL -сервер здійснюється командою CREATE DATABASE. Слід зазначити, що процедура створення бази даних в SQL -сервері вимагає наявності прав адміністратора сервера.
<визначення_бази_даних> ::=
CREATE DATABASE ім'я_бази_даних
[ON [PRIMARY]
[ <визначення_файлу> [,..n] ]
[,<визначення_групи> [,..n] ] ]
[ LOG ON {<визначення_файлу>[,..n] } ]
[ FOR LOAD | FOR ATTACH ]
Розглянемо основні параметри представленого оператора.
При виборі імені бази даних слід керуватися загальними правилами іменування об'єктів. Якщо ім'я бази даних містить пропуски або будь-які інші неприпустимі символи, воно полягає в обмежувачі (подвійні лапки або квадратні дужки). Ім'я бази даних має бути унікальним в межах сервера і не може перевищувати 128 символів.
При створенні і зміні бази даних можна вказати ім'я файлу, який буде для неї створений, змінити ім'я, шлях і початковий розмір цього файлу. Якщо в процесі використання бази даних планується її розміщення на декількох дисках, то можна створити так звані вторинні файли бази даних з розширенням *.ndf. В цьому випадку основна інформація про базу даних розташовується в первинному ( PRIMARY ) файлі, а при нестачі для нього вільного місця інформація, що додається, розміщуватиметься у вторинному файлі. Підхід, використовуваний в SQL -сервері, дозволяє розподіляти вміст бази даних по декількох дискових томах.
Параметр ON визначає список файлів на диску для розміщення інформації, що зберігається у базі даних.
Параметр PRIMARY визначає первинний файл. Якщо він опущений, то первинним є перший файл в списку.
Параметр LOG ON визначає список файлів на диску для розміщення журналу транзакцій. Ім'я файлу для журналу транзакцій генерується на основі імені бази даних, і у кінці до нього додаються символи _log.
При створенні бази даних можна визначити набір файлів, з яких вона полягатиме. Файл визначається за допомогою наступної конструкції:
<визначення_файлу>::=
( ([ NAME=логічне_ім'я_файлу,]
FILENAME='фізичне_ім'я_файлу'
[SIZE=розмір_файлу ]
[MAXSIZE={max_розмір_файлу |UNLIMITED } ]
[FILEGROWTH=величина_приросту ] )[,..n]
Тут логічне ім'я файлу - це ім'я файлу, під яким він пізнаватиметься при виконанні різних SQL -команд.
Фізичне ім'я файлу призначене для вказівки повного шляху і назви відповідного фізичного файлу, який буде створений на жорсткому диску. Це ім'я залишиться за файлом на рівні операційної системи.
Параметр SIZE визначає первинний розмір файлу; мінімальний розмір параметра - 512 Кб, якщо він не вказаний, за умовчанням приймається 1 Мб.
Параметр MAXSIZE визначає максимальний розмір файлу бази даних. При значенні параметра UNLIMITED максимальний розмір бази даних обмежується вільним місцем на диску.
При створенні бази даних можна дозволити або заборонити автоматичний ріст її розміру (це визначається параметром FILEGROWTH ) і вказати приріст за допомогою абсолютної величини в Мб або процентним співвідношенням. Значення може бути вказане в кілобайтах, мегабайтах, гігабайтах, терабайтах або відсотках (%). Якщо вказано число без суфікса МБ, КБ або %, то за умовчанням використовується значення MБ. Якщо розмір кроку росту вказаний у відсотках (%), розмір збільшується на задану частину у відсотках від розміру файлу. Вказаний розмір округляється до найближчих 64 КБ.
Додаткові файли можуть бути включені в групу:
<визначення_групи>::=FILEGROUP ім'я_групи_файлів
<визначення_файлу>[,..n]
Приклад 3.1. Створити базу даних, причому для даних визначити три файли на диску C, для журналу транзакцій - два файли на диску C.
CREATE DATABASE Archive
ON PRIMARY ( NAME=Arch1
FILENAME='c:\user\data\archdat1.mdf
SIZE=100MB, MAXSIZE=200, FILEGROWTH=20)
((NAME=Arch2,
FILENAME='c:\user\data\archdat2.mdf
SIZE=100MB, MAXSIZE=200, FILEGROWTH=20)
((NAME=Arch3,
FILENAME='c:\user\data\archdat3.mdf
SIZE=100MB, MAXSIZE=200, FILEGROWTH=20)
LOG ON
((NAME=Archlog1
FILENAME='c:\user\data\archlog1.ldf
SIZE=100MB, MAXSIZE=200, FILEGROWTH=20)
((NAME=Archlog2
FILENAME='c:\user\data\archlog2.ldf
SIZE=100MB, MAXSIZE=200, FILEGROWTH=20)
Приклад 3.1. Створення бази даних.
Зміна бази даних
Більшість дій зі зміни конфігурації бази даних виконуються за допомогою наступної конструкції:
<зміна_бази_даних> ::=
ALTER DATABASE ім'я_бази_даних
{ ADD FILE <визначення_файлу>[,..n]
[TO FILEGROUP ім'я_групи_файлів ]
| ADD LOG FILE <визначення_файлу>[,..n]
| REMOVE FILE логічне_ім'я_файлу
| ADD FILEGROUP ім'я_групи_файлів
| REMOVE FILEGROUP ім'я_групи_файлів
| MODIFY FILE <визначення_файлу>
| MODIFY FILEGROUP ім'я_групи_файлів
<властивості_групи_файлів>}
Як видно з синтаксису, за один виклик команди може бути змінено не більше за один параметр конфігурації бази даних. Якщо необхідно виконати декілька змін, доведеться розбити процес на ряд окремих кроків.
У базу даних можна додати ( ADD ) нові файли даних (у вказану групу файлів або в групу, прийняту за умовчанням) або файли журналу транзакцій.
Параметри файлів і груп файлів можна змінювати ( MODIFY ).
Для видалення з бази цих файлів або груп файлів використовується параметр REMOVE. Проте видалення файлу можливе лише за умови його звільнення від даних. Інакше сервер не дозволить видалення.
В якості властивостей групи файлів використовуються наступні:
READONLY - група файлів використовується тільки для читання; READWRITE - в групі файлів дозволяються зміни; DEFAULT - вказана група файлів приймається за умовчанням.
Видалення бази даних
Видалення бази даних здійснюється командою:
DROP DATABASE ім'я_бази_даних [,..n]
Віддаляються усі ті, що містяться у базі даних об'єкти, а також файли, в яких вона розміщується. Для виконання операції видалення бази даних користувач повинен мати відповідні права.
Створення таблиці
Після створення загальної структури бази даних можна приступити до створення таблиць, які є стосунками, що входять до складу проекту бази даних.
Таблиця - основний об'єкт для зберігання інформації в реляційній базі даних. Вона складається з тих, що містять дані рядків і стовпців, займає у базі даних фізичний простір і може бути постійною або тимчасовою.
Поле, також зване в реляційній базі даних стовпцем, є частиною таблиці, за якою закріплений певний тип даних. Кожна таблиця бази даних повинна містити хоч би один стовпець. Рядок даних - це запис в таблиці бази даних, вона включає поля, що містять дані з одного запису таблиці.
Приступаючи до створення таблиці, необхідно мати відповіді на низку запитань :
• Як називатиметься таблиця?
• Як називатимуться стовпці (поля) таблиці?
• Які типи даних будуть закріплені за кожним стовпцем?
• Який розмір пам'яті має бути виділений для зберігання кожного стовпця?
• Які стовпці таблиці вимагають обов'язкового введення?
• З яких стовпців складатиметься первинний ключ?
Базовий синтаксис оператора створення таблиці має наступний вигляд:
<визначення_таблиці> ::=
CREATE TABLE ім'я_таблиці
( (ім'я_стовпця тип_даних
[NULL | NOT NULL ] [,..n])
Приведений стандарт співпадає з реалізацією оператора створення таблиці в середовищі MS SQL Server.
Головне в команді створення таблиці - визначення імені таблиці і опис набору імен полів, які вказуються у відповідному порядку. Крім того, цією командою обмовляються типи даних і розміри полів таблиці.
Ключове слово NULL використовується для вказівки тієї, що в цьому стовпці можуть міститися значення NULL. Значення NULL відрізняється від пропуску або нуля - до нього прибігають, коли необхідно вказати, що дані недоступні, опущені або недопустимі. Якщо вказано ключове слово NOT NULL, то будуть відхилені будь-які спроби помістити значення NULL в цей стовпець. Якщо вказаний параметр NULL, приміщення значень NULL в стовпець дозволене. За умовчанням стандарт SQL припускає наявність ключового слова NULL.
Ми використовували спрощену версію оператора CREATE TABLE стандарту SQL. Його повна версія приводиться при обговоренні питань забезпечення цілісності даних.
Приклад 3.2. Створити таблицю для зберігання даних про товари, що надходять у продаж в деякій торговій фірмі. Необхідно врахувати такі відомості, як назва і тип товару, його ціна, сорт і місто, де товар робиться.
CREATE TABLE Товар
((Назва VARCHAR(50) NOT NULL
Ціна MONEY NOT NULL
Тип VARCHAR(50) NOT NULL
Сорт VARCHAR(50)
МістоТовару VARCHAR(50))
Приклад 3.2. Створення таблиці для зберігання даних про товари, що надходять у продаж в деякій торговій фірмі.
Приклад 3.3.Створити таблицю для збереження відомостей про постійних клієнтів з вказівкою назв міста і фірми, прізвища, імені і по батькові клієнта, номера його телефону.
CREATE TABLE Клієнт
( (Фірма VARCHAR(50) NOT NULL
Прізвище VARCHAR(50) NOT NULL
Ім'я VARCHAR(50) NOT NULL
По батькові VARCHAR(50)
МістоКлієнта VARCHAR(50)
Телефон CHAR(10) NOT NULL)
Приклад 3.3. Створення таблиці для збереження відомостей про постійних клієнтів.
Зміна таблиці
Структура існуючої таблиці може бути модифікована за допомогою команди ALTER TABLE, спрощений синтаксис якої представлений нижче :
ALTER TABLE ім'я_таблиці
{[ADD [COLUMN] ім'я_стовпця тип_даних [
NULL | NOT NULL ]]
| [DROP [COLUMN] ім'я_стовпця]}
У середовищі MS SQL Server спрощений синтаксис команди модифікації таблиці має вигляд:
ALTER TABLE ім'я_таблиці
{[ALTER COLUMN ім'я_стовпця
{новий_тип_даних [(точність[,масштаб])]
[ NULL | NOT NULL ]}]
| ADD { [ім'я_стовпця тип_даних]
| ім'я_стовпця AS вираження } [,..n]
| DROP {COLUMN ім'я_стовпця}[,..n]
}
Команда дозволяє додавати і видаляти стовпці, змінювати їх визначення.
Одно з основних правил при додаванні стовпців в існуючу таблицю свідчить: коли в таблиці вже містяться дані, стовпець, що додається, не може бути визначений з атрибутом NOT NULL. Цей атрибут означає, що для кожного рядка даних відповідний стовпець повинен містити деяке значення, тому додавання стовпця з атрибутом NOT NULL призводить до появи протиріччя - вже існуючі рядки даних таблиці не матимуть в новому стовпці ненульових значень.
Проте існує спосіб додавання обов'язкових полів в існуючу таблицю. Для цього необхідно:
• додати в таблицю новий стовпець, визначивши його з атрибутом NULL (тобто стовпець не зобов'язаний містити яких-небудь значень);
• ввести в новий стовпець які-небудь значення для кожного рядка даних таблиці ;
• переконавшись, що новий стовпець містить ненульові значення для кожного рядка даних, змінити структуру таблиці, замінивши атрибут цього стовпця на NOT NULL.
При зміні визначень стовпців слід брати до уваги деякі загальноприйняті правила:
• розмір стовпця може бути збільшений до максимального значення, що допускається відповідним типом даних;
• розмір стовпця може бути зменшений тільки у тому випадку, якщо найбільше значення, що міститься в нім, не перевершуватиме його нового розміру;
• кількість розрядів числового типу даних завжди може бути збільшена;
• кількість розрядів числового типу даних може бути зменшена тільки у тому випадку, якщо кількість розрядів найбільшого значення у відповідному стовпці не перевершуватиме нового числа розрядів, визначеного для цього стовпця ;
• кількість десяткових знаків числового типу даних може бути зменшена або збільшена;
• тип даних стовпця, як правило, може бути змінений.
Деякі реалізації фактично можуть обмежити розробника у використанні деяких опцій команди ALTER TABLE. Наприклад, може виявитися неприпустимим видалення стовпців з існуючої таблиці. Щоб добитися цього, спочатку потрібно буде видалити саму таблицю і тільки потім наново її побудувати з потрібними стовпцями. Причому вже внесені в таблицю дані будуть втрачені.
Можливі труднощі, пов'язані з видаленням з таблиці стовпця, який залежить від деякого стовпця іншої таблиці. У такому разі спочатку доведеться видалити обмеження стовпця, а потім сам стовпець.
Приклад 3.4. Додати в таблицю Клієнт поле для номера розрахункового рахунку.
ALTER TABLE Клієнт ADD Рас_рахунок CHAR(20)
Приклад 3.4. Додавання в таблицю Клієнт поля для номера розрахункового рахунку.
Видалення таблиці
З часом структура бази даних міняється: створюються нові таблиці, а колишні стають непотрібними і видаляються з бази даних за допомогою оператора:
DROP TABLE ім'я_таблиці [RESTRICT | CASCADE]
Слід зазначити, що ця команда видалить не лише вказану таблицю, але і усі рядки даних, що входять в неї. Якщо вимагається видалити з таблиці лише дані, зберігши структуру таблиці, слід скористатися командою DELETE.
Оператор DROP TABLE додатково дозволяє вказувати, чи слід операцію видалення виконувати каскадний. Якщо в операторові вказано ключове слово RESTRICT, то за наявності у базі даних хоч би одного об'єкту, існування якого залежить від таблиці, що видаляється, виконання оператора DROP TABLE буде скасовано. Якщо вказано ключове слово CASCADE, автоматично віддаляються і усі інші об'єкти бази даних, чиє існування залежить від таблиці, що видаляється, а також інші об'єкти, залежні від об'єктів, що видаляються. Загальний ефект від виконання оператора DROP TABLE з ключовим словом CASCADE може виявитися дуже відчутним, тому подібні оператори слід використовувати з максимальною обережністю.
Найчастіше оператор DROP TABLE використовується для виправлення помилок, допущених при створенні таблиці. Якщо таблиця була створена з некоректною структурою, можна скористатися оператором DROP TABLE для її видалення, після чого створити таблицю наново.
Індекси в стандарті мови
Індекси є структурою, що дозволяє виконувати прискорений доступ до рядків таблиці на основі значень одного або більше за її стовпці . Наявність індексу може істотно підвищити швидкість виконання деяких запитів і скоротити час пошуку необхідних даних за рахунок фізичного або логічного їх впорядковування. Індекс - це набір посилань, впорядкованих по певному стовпцю таблиці, який в даному випадку називатиметься індексованим стовпцем . Хоча індекс і пов'язаний з конкретним стовпцем (чи стовпцями ) таблиці, все ж він є самостійним об'єктом бази даних.
Фізично індекс - усього лише впорядкований набір значень з індексованого стовпця з покажчиками на місця фізичного розміщення початкових рядків в структурі бази даних. Коли користувач виконує запит, що звертається до індексованого стовпця, СУБД автоматично аналізує індекс для пошуку необхідних значень.
Проте, оскільки індекси повинні оновлюватися системою при кожному внесенні змін до їх базової таблиці, вони створюють додаткове навантаження на систему.
Індекси зазвичай створюються з метою задоволення певних критеріїв пошуку після того, як таблиця вже знаходилася деякий час в роботі і збільшилася в розмірах. Створення індексів не передбачене стандартом SQL, проте більшість діалектів підтримують як мінімум наступний оператор:
CREATE [ UNIQUE ] INDEX ім'я_індексу
ON ім'я_таблиці(ім'я_стовпця[ASC|DESC][,..n])
Вказані в операторові стовпці складають ключ індексу. Індекси можуть створюватися тільки для базових таблиць, але не для представлень. Якщо в операторові вказано ключове слово UNIQUE, унікальність значень ключа індексу автоматично підтримуватиметься системою. Вимога унікальності значень обов'язкова для первинних ключів, а також можливо і для інших стовпців таблиці (наприклад, для альтернативних ключів). Хоча створення індексу допускається у будь-який момент, при його побудові для вже заповненою даними таблиці можуть виникнути проблеми, пов'язані з дублюванням даних в різних рядках. Отже, унікальні індекси (принаймні, для первинного ключа) має сенс створювати безпосередньо при формуванні таблиці. В результаті система відразу візьме на себе контроль за унікальністю значень даних у відповідних стовпцях.
Якщо створений індекс згодом виявиться непотрібним, його можна видалити за допомогою оператора
DROP INDEX ім'я_індексу
Індекси в середовищі MS SQL Server
Індекс є засобом, що допомагає прискорити пошук необхідних даних за рахунок фізичного або логічного їх впорядковування. Індекс є набором посилань, впорядкованих по певному стовпцю таблиці, який в даному випадку називатиметься індексованим стовпцем. Індекси - це набори унікальних значень для деякої таблиці з відповідними посиланнями на дані. Вони розташовані в самій таблиці і є зручним внутрішнім механізмом системи SQL -сервера, за допомогою якого здійснюється доступ до даних найбільш оптимальним способом. У середовищі SQL Server реалізовані ефективні алгоритми пошуку потрібного значення в строго певній послідовності даних. Прискорення пошуку досягається саме за рахунок того, що дані представляються впорядкованими (хоча фізично, залежно від типу індексу, вони можуть зберігатися відповідно до черговості їх додавання в таблицю ). До теперішнього часу розроблені ефективні математичні алгоритми пошуку даних у впорядкованій послідовності. Найбільш ефективною структурою для пошуку даних в машинному представленні являються B -дерева - багаторівнева ієрархічна структура зі змінною кількістю елементів в кожному вузлі.
Створення індексу
Якщо вибірка даних з таблиці вимагає значного часу, це означає, що для неї необхідно створити індекс. Індекси можуть істотно підвищити продуктивність виконання операцій пошуку і вибірки даних. При виборі стовпця для індексу слід проаналізувати, які типи запитів найчастіше виконуються користувачами і які стовпці є ключовими, тобто задаючими критерії вибірки даних, наприклад, порядок сортування.
У середовищі SQL Server реалізовано декілька типів індексів :
•кластерні індекси ;
•некластерні індекси ;
•унікальні індекси.
Некластерний індекс
Некластерні індекси - найбільш типові представники сімейства індексів. На відміну від кластерних, вони не перебудовують фізичну структуру таблиці, а лише організовують посилання на відповідні рядки .
Для ідентифікації потрібного рядка в таблиці некластерний індекс організовує спеціальні покажчики, що включають :
• інформацію про ідентифікаційний номер файлу, в якому зберігається рядок ;
• ідентифікаційний номер сторінки відповідних даних;
• номер шуканого рядка на відповідній сторінці;
• вміст стовпця.
У більшості випадків слід обмежуватися 4-5 індексами.
Кластерний індекс
Принциповою відмінністю кластерного індексу від індексів інших типів є те, що при його визначенні в таблиці фізичне розташування даних перебудовується відповідно до структури індексу . Логічна структура таблиці в цьому випадку є швидше словником, ніж індекс. Дані в словнику фізично впорядковані, наприклад за абеткою.
Кластерні індекси можуть дати істотне збільшення продуктивності пошуку даних навіть в порівнянні із звичайними індексами. Збільшення продуктивності особливе помітно при роботі з послідовними даними. Якщо в таблиці визначений некластерний індекс, то сервер повинен спочатку звернутися до індексу, а потім знайти потрібний рядок в таблиці. При використанні кластерних індексів наступна порція даних розташовується відразу після знайдених раніше за даних. Завдяки цьому відпадають зайві операції, пов'язані із зверненням до індексу і новим пошуком потрібного рядка в таблиці.
Природно, в таблиці може бути визначений тільки один кластерний індекс. В якості такого слід вибирати найбільш часто використовувані стовпці. При цьому варто наслідувати загальні рекомендації створення індексів і не індексувати занадто довгі стовпці.
Кластерний індекс може включати декілька стовпців. Проте кількість таких стовпців рекомендується по можливості звести до мінімуму.
Необхідно уникати створення кластерного індексу для часто змінюваних стовпців, оскільки сервер повинен буде виконувати фізичне переміщення усіх даних в таблиці, щоб вони знаходилися у впорядкованому стані, як того вимагає кластерний індекс. Для інтенсивно змінюваних стовпців краще підходить некластерний індекс.
При створенні в таблиці первинного ключа ( PRIMARY KEY ) сервер автоматично створює для нього кластерний індекс, якщо його не існувало раніше або якщо при визначенні ключа не був явно вказаний інший тип індексу.
Коли ж в таблиці визначений ще і некластерний індекс, то його покажчик посилається не на фізичне положення рядка у базі даних, а на того, що відповідає елементу кластерного індексу, що описує цей рядок, що дозволяє не перебудовувати структуру некластерних індексів всякий раз, коли кластерний індекс міняє фізичний порядок рядків в таблиці.
Унікальний індекс
Унікальність значень в індексованому стовпці гарантують унікальні індекси. При їх наявності сервер не дозволить вставити нове або змінити існуюче значення так, щоб в результаті цієї операції в стовпці з'явилися два однакові значення.
Унікальний індекс є своєрідною надбудовою і може бути реалізований як для кластерного, так і для некластерного індексу . В одній таблиці може існувати один унікальний кластерний і безліч унікальних некластерних індексів.
Унікальні індекси слід визначати тільки тоді, коли це дійсно необхідно. Для забезпечення цілісності даних в стовпці можна визначити обмеження цілісності UNIQUE або PRIMARY KEY, а не прибігати до унікальних індексів. Їх використання тільки для забезпечення цілісності даних є невиправданою витратою простору у базі даних. Крім того, на їх підтримку витрачається і процесорний час.
Засоби мови SQL пропонують декілька способів визначення індексу :
• автоматичне створення індексу при створенні первинного ключа;
• автоматичне створення індексу при визначенні обмеження цілісності UNIQUE ;
• створення індексу за допомогою команди CREATE INDEX.
Остання команда має наступний формат:
<створення_індексу>::=
CREATE [ UNIQUE ]
[ CLUSTERED | NONCLUSTERED ]
INDEX ім'я_індексу ON ім'я_таблиці(ім'я_стовпця
[ASC|DESC][,..n])
[WITH [PAD_INDEX]
[[,] FILLFACTOR=чинник_заповнення]
[[,] IGNORE_DUP_KEY]
[[,] DROP_EXISTING]
[[,] STATISTICS_NORECOMPUTE] ]
[ON ім'я_групи_файлів ]
Розглянемо деякі параметри приведеної команди.
Ім'я індексу має бути унікальним в межах таблиці, а сам індекс створюється виключно для таблиці поточної бази даних.
Параметр UNIQUE використовується при необхідності введення в певне поле тільки унікальних значень. При вказівці цього ключового слова буде створений унікальний індекс. У індексованому стовпці бажано заборонити зберігання значень NULL, щоб уникнути проблем, пов'язаних з унікальністю значень. Після того, як для стовпця появиться унікальний індекс, сервер не дозволить виконання команд INSERT і UPDATE, які приведуть до появи дублюючих значень.
Параметр CLUSTERED використовує можливість фізичного індексування даних і дозволяє зробити так зване кластерне індексування, внаслідок чого будуть відсортовані дані в самій таблиці згідно з порядком цього індексу, а уся інформація, що додається, стане призводити до зміни фізичного порядку даних. Кластерним може бути тільки один індекс в таблиці.
Параметр NONCLUSTERED дозволяє створювати некластерні індекси.
Параметр FILLFACTOR здійснює налаштування розбиття індексу на сторінки і помітно оптимізує роботу SQL -сервера. Коефіцієнт FILLFACTOR визначає в процентному співвідношенні розмір створюваних індексних сторінок. При цьому є обернено пропорційна залежність частоти роботи з таблицею і коефіцієнту FILLFACTOR.
Параметр PAD_INDEX визначає заповнення внутрішнього простору індексу і застосовується спільно з FILLFACTOR.
Параметр DROP_EXISTING при використанні кластерного індексу визначає його повторне створення, що дозволяє запобігти небажаному оновленню кластерних індексів.
Параметр STATISTICS_NORECOMPUTE визначає функції автоматичного оновлення статистики для таблиці.
Параметр ім'я_групи_файлів дозволяє здійснити вибір файлової групи, в якій знаходитиметься створюваний індекс. Використання індексу з іншої файлової групи підвищує продуктивність некластерних індексів у зв'язку з паралельністю виконання процесів введення/виводу і роботи з самим індексом.
Видалення індексу
Видалення індексу виконується командою
DROP INDEX 'ім'я_індексу'[,..n]
Приклад 3.5. Створити унікальний кластерний індекс для таблиці Клієнт по стовпцю Прізвище в первинній групі файлів.
CREATE UNIQUE CLUSTERED INDEX index_klient1
ON Клієнт (Прізвище)
WITH DROP_EXISTING
ON PRIMARY
Приклад 3.5. Створення унікального кластерного індексу.
Приклад 3.6.Створити унікальний некластерний індекс для таблиці Клієнт по стовпцях Прізвище і Ім'я в первинній групі файлів. Крім того, елементи індексу будуть впорядковані по убуванню. Також заборонимо автоматичне оновлення статистики при зміні даних в таблиці і встановимо чинник заповнення індексних сторінок на рівні 30%.
CREATE UNIQUE NONCLUSTERED INDEX index_klient2
ON Клієнт (Прізвище DESC, Ім'я DESC)
WITH FILLFACTOR=30
STATISTICS_NORECOMPUTE
ON PRIMARY
Приклад 3.6. Створення унікального некластерного індексу.
Оператор SELECT - один з найбільш важливих і найпоширеніших операторів SQL. Він дозволяє робити вибірки даних з таблиць і перетворювати до потрібного виду отримані результати. Будучи дуже потужним, він здатний виконувати дії, еквівалентні операторам реляційної алгебри, причому в межах єдиної виконуваної команди. При його допомозі можна реалізувати складні і громіздкі умови відбору даних з різних таблиць.
Оператор SELECT - засіб, який повністю абстрагований від питань представлення даних, що допомагає сконцентрувати увага на проблемах доступу до даних. Приклади його використання наочно демонструють один із засадничих принципів великих (промислових) СУБД : засоби зберігання даних і доступу до них відокремлені від засобів представлення даних. Операції над даними робляться в масштабі наборів цих, а не окремих записів.
Оператор SELECT має наступний формат:
SELECT [ALL | DISTINCT ] {*|[ім'я_стовпця
[AS нове_ім'я]]} [,..n]
FROM ім'я_таблиці [[AS] псевдонім] [,..n]
[WHERE <умова_пошуку>]
[GROUP BY ім'я_стовпця [,..n]]
[HAVING <критерії вибору груп>]
[ORDER BY ім'я_стовпця [,..n]]
Оператор SELECT визначає поля (стовпці), які входитимуть в результат виконання запиту. У списку вони розділяються комами і приводяться в такій черговості, в якій мають бути представлені в результаті запиту. Якщо використовується ім'я поля, що містить пропуски або роздільники, його слід взяти в квадратних дужок. Символом* можна вибрати усі поля, а замість імені поля застосувати вираження з декількох імен.
Якщо обробляється ряд таблиць, то (за наявності однойменних полів в різних таблицях) в списку полів використовується повна специфікація поля, тобто. Ім'я_таблиці.Ім'я_поля.
Пропозиція FROM задає імена таблиць і представлень, які містять поля, перераховані в операторові SELECT. Необов'язковий параметр псевдоніма - це скорочення, що встановлюється для імені таблиці.
Обробка елементів оператора SELECT виконується в наступній послідовності:
• FROM - визначаються імена використовуваних таблиць;
• WHERE - виконується фільтрація рядків об'єкту відповідно до заданих умов;
• GROUP BY - утворюються групи рядків, що мають одно і те ж значення у вказаному стовпці;
• HAVING - фільтруються групи рядків об'єкту відповідно до вказаної умови;
• SELECT - встановлюється, які стовпці мають бути присутніми у вихідних даних;
• ORDER BY - визначається впорядкованість результатів виконання операторів.
Порядок пропозицій і фраз в операторові SELECT не може бути змінений. Тільки дві пропозиції SELECT і FROM є обов'язковими, усі інші можуть бути опущені. SELECT - закрита операція: результат запиту до таблиці є іншою таблицею. Існує безліч варіантів запису цього оператора, що ілюструється наведеними нижче прикладами.
Приклад 4.1. Скласти список відомостей про усіх клієнтів.
SELECT * FROM Клієнт
Приклад 4.1. Список відомостей про усіх клієнтів.
Параметр WHERE визначає критерій відбору записів з вхідного набору. Але в таблиці можуть бути присутніми записи (дублікати), що повторюються. Предикат ALL задає включення у вихідний набір усіх дублікатів, відібраних за критерієм WHERE. Немає необхідності вказувати ALL явно, оскільки це значення діє за умовчанням.
Приклад 4.2. Скласти список усіх фірм.
SELECT ALL Клієнт.Фірма FROM Клієнт
Чи (що еквівалентно)
SELECT Клієнт.Фірма FROM Клієнт
Приклад 4.2. Список усіх фірм.
Результат виконання запиту може містити значення, що дублюються, оскільки на відміну від операцій реляційної алгебри оператор SELECT не виключає значень, що повторюються, при виконанні вибірки даних.
Предикат DISTINCT слід застосовувати в тих випадках, коли вимагається відкинути блоки даних, що містять дублюючі записи у вибраних полях. Значення для кожного з приведених в інструкції SELECT полів мають бути унікальними, щоб запис, що утримує їх, зміг увійти до вихідного набору.
Причиною обмеження в застосуванні DISTINCT є та обставина, що її використання може різко уповільнити виконання запитів.
Відкоригований приклад 4.2 виглядає таким чином:
SELECT DISTINCT Клієнт.Фірма
FROM Клієнт
За допомогою WHERE -параметра користувач визначає, які блоки даних з приведених в списку FROM таблиць з'являться в результаті запиту. За ключовим словом WHERE слідує перелік умов пошуку, що визначають ті рядки, які мають бути вибрані при виконанні запиту. Існує п'ять основних типів умов пошуку (чи предикатів) :
• Порівняння: порівнюються результати обчислення одного вираження з результатами обчислення іншого.
• Діапазон: перевіряється, чи потрапляє результат обчислення вираження в заданий діапазон значень.
• Приналежність множині: перевіряється, чи належить результат обчислень вираження заданій безлічі значень.
• Відповідність шаблону: перевіряється, чи відповідає деяке строкове значення заданому шаблону.
• Значення NULL : перевіряється, чи містить цей стовпець визначник NULL (невідоме значення).
Порівняння
У мові SQL можна використовувати наступні оператори порівняння : = - рівність; < - менше; > - більше; <= - менше або рівно; >= - більше або рівно; <> - не рівно.
Приклад 4.3. Показати усі операції відпустки товарів об'ємом більше 20.
SELECT * FROM Угода
WHERE Кількість>20
Приклад 4.3. Операції відпустки товарів об'ємом більше 20.
SELECT * FROM Угода
WHERE Кількість>20
Приклад 4.3. Операції відпустки товарів об'ємом більше 20.
Складніші предикати можуть бути побудовані за допомогою логічних операторів AND, OR або NOT, а також дужок, використовуваних для визначення порядку обчислення вираження. Обчислення вираження в умовах виконується за наступними правилами:
• Вираження обчислюється зліва направо.
• Першими обчислюються підвирази в дужках.
• Оператори NOT виконуються до виконання операторів AND і OR.
• Оператори AND виконуються до виконання операторів OR.
Для усунення будь-якої можливої неоднозначності рекомендується використовувати дужки.
Приклад 4.4. Вивести список товарів, ціна яких більше або рівна 100 і менше або рівна 150.
SELECT Назва, Ціна
FROM Товар
WHERE Ціна>=100 And Ціна<=150
Приклад 4.4. Список товарів, ціна яких більше або рівна 100 і менше або рівна 150.
Приклад 4.5. Вивести список клієнтів з Києва або з Чернігова.
SELECT Прізвище, МістоКлієнта
FROM Клієнт
WHERE МістоКлієнта="Київ" Or
МістоКлієнта="Чернігів"
Приклад 4.5. Список клієнтів з Києва або з Чернігова.
Діапазон
Оператор BETWEEN використовується для пошуку значення усередині деякого інтервалу, визначуваного своїми мінімальним і максимальним значеннями. При цьому вказані значення включаються в умову пошуку.
Приклад 4.6. Вивести список товарів, ціна яких лежить в діапазоні від 100 до 150 (запит еквівалентний прикладу 4.4).
SELECT Назва, Ціна
FROM Товар
WHERE Ціна BETWEEN 100 And 150
Приклад 4.6. Список товарів, ціна яких лежить в діапазоні від 100 до 150.
При використанні заперечення NOT BETWEEN потрібно, щоб значення, що перевіряється, лежало поза межами заданого діапазону.
Приклад 4.7. Вивести список товарів, ціна яких не лежить в діапазоні від 100 до 150.
SELECT Товар.Назва, Товар.Ціна
FROM Товар
WHERE Товар.Ціна NOT BETWEEN 100 And 150
Чи (що еквівалентно)
SELECT Товар.Назва, Товар.Ціна
FROM Товар
WHERE (Товар.Ціна<100) OR (Товар.Ціна>150)
Приклад 4.7. Список товарів, ціна яких не лежить в діапазоні від 100 до 150.
Приналежність множині
Оператор IN використовується для порівняння деякого значення із списком заданих значень, при цьому перевіряється, чи відповідає результат обчислення вираження одному зі значень в наданому списку. За допомогою оператора IN може бути досягнутий той же результат, що і у разі застосування оператора OR, проте оператор IN виконується швидше.
Приклад 4.8. Вивести список клієнтів з Києва або з Чернігова (запит еквівалентний прикладу 4.5).
SELECT Прізвище, МістоКлієнта
FROM Клієнт
WHERE МістоКлієнта IN ("Київ", "Чернігів")
Приклад 4.8. Список клієнтів з Києва або з Чернігова
NOT IN використовується для відбору будь-яких значень, окрім тих, які вказані в представленому списку.
Приклад 4.9. Вивести список клієнтів, що проживають не в Києві і не в Чернігові.
SELECT Прізвище, МістоКлієнта
FROM Клієнт
WHERE МістоКлієнта
NOT IN ("Київ", "Чернігів")
Приклад 4.9. Список клієнтів, що проживають не в Києві і не в Чернігові.
Відповідність шаблону
За допомогою оператора LIKE можна виконувати порівняння вираження із заданим шаблоном, в якому допускається використання символів-замінників :
• Символ % - замість цього символу може бути підставлена будь-яка кількість довільних символів.
• Символ _ замінює один символ рядка.
• [] - замість символу рядка буде підставлений один з можливих символів, вказаний в цих обмежувачах.
• [^] - замість відповідного символу рядка будуть підставлені усі символи, окрім вказаних в обмежувачах.
Приклад 4.10. Знайти клієнтів, у яких в номері телефону друга цифра, - 4.
SELECT Клієнт.Прізвище, Клієнт.Телефон
FROM Клієнт
WHERE Клієнт.Телефон LIKE '_4%'
Приклад 4.10. Вибірка клієнтів, у яких в номері телефону друга цифра, - 4.
Приклад 4.11. Знайти клієнтів, у яких в номері телефону друга цифра, - 2 або 4.
SELECT Клієнт.Прізвище, Клієнт.Телефон
FROM Клієнт
WHERE Клієнт.Телефон LIKE '_[2,4]%'
Приклад 4.11. Вибірка клієнтів, у яких в номері телефону друга цифра, - 2 або 4.
Приклад 4.12. Знайти клієнтів, у яких в номері телефону друга цифра 2, 3 або 4.
SELECT Клієнт.Прізвище, Клієнт.Телефон
FROM Клієнт
WHERE Клієнт.Телефон LIKE '_[2-4]%'
Приклад 4.12. Вибірка клієнтів, у яких в номері телефону друга цифра 2, 3 або 4.
Приклад 4.13. Знайти клієнтів, у яких в прізвищі зустрічається склад "ро".
SELECT Клієнт.Прізвище
FROM Клієнт
WHERE Клієнт.Прізвище LIKE "%ро%"
Приклад 4.13. Вибірка клієнтів, у яких в прізвищі зустрічається склад "ро".
Значення NULL
Оператор IS NULL використовується для порівняння поточного значення зі значенням NULL - спеціальним значенням, що вказує на відсутність будь-якого значення. NULL - це не те ж саме, що знак пропуску (пропуск - допустимий символ) або нуль (0 - допустиме число). NULL відрізняється і від рядка нульової довжини (порожнього рядка).
Приклад 4.14. Знайти співробітників, у яких немає телефону (поле Телефон не містить ніякого значення).
SELECT Прізвище, Телефон
FROM Клієнт
WHERE Телефон IS NULL
Приклад 4.14. Вибірка співробітників, у яких немає телефону (поле Телефон не містить ніякого значення).
IS NOT NULL використовується для перевірки присутності значення в полі.
Приклад 4.15. Вибірка клієнтів, у яких є телефон (поле Телефон містить яке-небудь значення).
SELECT Клієнт.Прізвище, Клієнт.Телефон
FROM Клієнт
WHERE Клієнт.Телефон Is Not Null
Приклад 4.15. Знайти клієнтів, у яких є телефон (поле Телефон містить яке-небудь значення).
У загальному випадку рядка в результуючій таблиці SQL -запиту ніяк не впорядковані. Проте їх можна необхідним чином відсортувати, для чого в оператор SELECT вміщується фраза ORDER BY, яка сортує дані вихідного набору в заданій послідовності. Сортування може виконуватися по декількох полях, в цьому випадку вони перераховуються за ключовим словом ORDER BY через кому. Спосіб сортування задається ключовим словом, що вказується у рамках параметра ORDER BY слідом за назвою поля, по якій виконується сортування. За умовчанням реалізується сортування за збільшенням. Явно вона задається ключовим словом ASC. Для виконання сортування в зворотній послідовності необхідно після імені поля, по якому вона виконується, вказати ключове слово DESC. Фраза ORDER BY дозволяє упорядкувати вибрані записи в порядку зростання або убування значень будь-якого стовпця або комбінації стовпців, незалежно від того, є присутніми ці стовпці в таблиці результату або ні. Фраза ORDER BY завжди має бути останнім елементом в операторові SELECT.
Приклад 4.16.Вивести список клієнтів в алфавітному порядку.
SELECT Клієнт.Прізвище, Клієнт.Фірма
FROM Клієнт
ORDER BY Клієнт.Прізвище
Приклад 4.16. Список клієнтів в алфавітному порядку.
У фразі ORDER BY може бути вказане і більше одного елементу. Головний (перший) ключ сортування визначає загальну впорядкованість рядків результуючої таблиці. Якщо в усіх рядках результуючої таблиці значення головного ключа сортування є унікальними, немає необхідності використовувати додаткові ключі сортування. Проте, якщо значення головного ключа не унікальні, в результуючій таблиці буде присутніми декілька рядків з одним і тим же значенням старшого ключа сортування. В цьому випадку, можливо, доведеться упорядкувати рядки з одним і тим же значенням головного ключа по якому-небудь додатковому ключу сортування.
Приклад 4.17. Вивести список фірм і клієнтів. Назви фірм упорядкувати в алфавітному порядку, імена клієнтів в кожній фірмі відсортувати в зворотному порядку.
SELECT Клієнт.Фірма, Клієнт.Прізвище
FROM Клієнт
ORDER BY Клієнт.Фірма, Клієнт.Прізвище DESC
Приклад 4.17. Список фірм і клієнтів. Назви фірм в алфавітному порядку, імена клієнтів в кожній фірмі в зворотному порядку.
Розглянемо основні операції над відношеннями, які можуть представляти інтерес з точки зору витягання даних з реляційних таблиць. Це об'єднання, перетин, різниця, розширене декартовий добуток відношень, а також спеціальні операції над відношеннями: вибірка, проекція і з'єднання.
Для ілюстрації теоретико-множинних операцій над відношеннями введемо абстрактні відношення (таблиці) з деякими атрибутами (полями).
Відношення R |
|
R.a1 |
R.a2 |
A |
1 |
A |
2 |
B |
1 |
B |
3 |
B |
4 |
CREATE TABLE R
((a1 CHAR(1), a2 INT, PRIMARY KEY(a1, a2))
Відношення R |
|
R.a1 |
R.a2 |
A |
1 |
A |
2 |
B |
1 |
B |
3 |
B |
4 |
CREATE TABLE S
((b1 INT PRIMARY KEY, b2 CHAR(1))
Операції вибірки і проекції є унарними, оскільки вони працюють з одним відношенням.
Операція вибірки - побудова горизонтальної підмножини, тобто підмножини кортежів, що мають задані властивості.
Операція вибірки працює з одним відношенням R і визначає результуюче відношення, яке містить тільки ті кортежі (рядки) відношення R, які задовольняють заданій умові F (предикату).
чи .
Приклад 5.1. Операція вибірки в SQL.
Вибірка записується таким чином:
SELECT a1, a2
FROM R
WHERE a2=1
Приклад 5.1. Операція вибірки в SQL.
Операція проекції - побудова вертикальної підмножини відношення, тобто підмножини кортежів, що отримується вибором одних і виключенням інших атрибутів.
Операція проекції працює з одним відношенням R і визначає нове відношення, яке містить вертикальну підмножину відношення R, що створюється за допомогою витягання значень вказаних атрибутів і виключення з результату рядків-дублікатів.
Приклад 5.2. Операція проекції в SQL.
Проекція записується таким чином:
SELECT DISTINCT b2
FROM S
Приклад 5.2. Операція проекції в SQL.
До основних операцій над відношеннями відноситься декартовий добуток.
Декартовий добуток RxS двох відношень (двох таблиць) визначає нове відношення - результат конкатенації (тобто зчеплення) кожного кортежу (кожному запису) з відношення R з кожним кортежем (кожним записом) з відношення S .
RxS={(a, 1, 1, h) (a, 2, 1, h),
( (b, 1, 1, h), .. }
SELECT R.a1, R.a2, S.b1, S.b2
FROM R, S
Приклад 5.3. Декартовий добуток відношень в SQL.
Результат декартового добутку двох відношень показаний в таблиці.
Таблиця 5.1. |
|||
R x S |
|||
R.a1 |
R.a2 |
S.b1 |
S.b2 |
a |
1 |
1 |
h |
a |
1 |
2 |
g |
a |
1 |
3 |
h |
a |
2 |
1 |
h |
a |
2 |
2 |
g |
a |
2 |
3 |
h |
b |
1 |
1 |
h |
b |
1 |
2 |
g |
b |
1 |
3 |
h |
b |
3 |
1 |
h |
b |
3 |
2 |
g |
b |
3 |
3 |
h |
b |
4 |
1 |
h |
b |
4 |
2 |
g |
b |
4 |
3 |
h |
Якщо одно відношення має N записів і K полів, а інше M записів і L полів, то відношення з їх декартовим добутком міститиме NxM записів і K+L полів. Початкові відношення можуть містити поля з однаковими іменами, тоді імена полів міститимуть назви таблиць у вигляді префіксів для забезпечення унікальності імен полів у відношенні, отриманому як результат виконання декартового добутку.
Проте у такому вигляді (приклад 5.3.) відношення містить більше інформації, чим зазвичай необхідно користувачеві. Як правило, користувачів цікавить лише деяка частина усіх комбінацій записів в декартовому добутку, що задовольняє деякій умові. Тому замість декартового добутку зазвичай використовується одна з найважливіших операцій реляційної алгебри - операція з'єднання, яка є похідною від операції декартового добутку. З точки зору ефективності реалізації в реляційних СУБД ця операція - одна з найважчих і часто входить до числа головних причин, що викликають властиві усім реляційним системам проблеми з продуктивністю.
З'єднання - це процес, коли дві або більше за таблицю об'єднуються в одну. Здатність об'єднувати інформацію з декількох таблиць або запитів у вигляді одного логічного набору даних обумовлює широкі можливості SQL.
У мові SQL для завдання типу з'єднання таблиць в логічний набір записів, з якого вибиратиметься необхідна інформація, використовується операція JOIN в пропозиції FROM.
Формат операції :
FROM ім'я_таблиці_1 {INNER | LEFT | RIGHT}
JOIN ім'я_таблиці_2
ON умова_з'єднання
Існують різні типи операцій з'єднання :
• тета-зєднання ;
• з'єднання по еквівалентності ;
• природне з'єднання ;
• зовнішнє з'єднання , ;
• напівз'єднання .
Операція тета-зєднання
Операція тета-зєднання визначає відношення, яке містить кортежі з декартових добутків відношень R і S, що задовольняють предикату F. Предикат F має вигляд , де замість може бути вказаний один з операторів порівняння ( >,<=, =, <> ).
Якщо предикат F містить тільки оператор рівності ( = ), то з'єднання називається з'єднанням по еквівалентності.
Таблиця 5.2. |
|||
R.a1 |
R.a2 |
S.b1 |
S.b2 |
a |
1 |
1 |
h |
a |
2 |
2 |
g |
b |
3 |
3 |
h |
b |
1 |
1 |
h |
Операція тета-зєднання в мові SQL називається INNER JOIN (внутрішнє з'єднання) і використовується, коли треба включити усі рядки з обох таблиць, що задовольняють умові об'єднання. Внутрішнє з'єднання має місце і тоді, коли в пропозиції WHERE порівнюються значення полів з різних таблиць. В цьому випадку будується декартовий добуток рядків першою і другою таблиць, а з отриманого набору даних відбираються записи, що задовольняють умовам об'єднання.
В умовах об'єднання можуть брати участь поля, що відносяться до одного і тому ж типу даних і таких, що містять один і той же вид даних, але вони не обов'язково повинні мати однакові імена.
Блоки даних з двох таблиць об'єднуються, як тільки у вказаних полях будуть знайдені співпадаючі значення.
Якщо в пропозиції FROM перераховано декілька таблиць і при цьому не вживається специфікація JOIN, а для вказівки відповідності полів з таблиць використовується умова в пропозиції WHERE, то деякі реляційні СУБД (наприклад, Access) оптимізують виконання запиту, інтерпретуючи його як з'єднання.
Якщо перераховувати ряд таблиць або запитів і не вказувати умови об'єднання, в якості початкової таблиці буде вибрано декартовий (прямий) добуток усіх таблиць.
SELECT R.a1, R.a2, S.b1, S.b2
FROM R, S
WHERE R.a2=S.b1
чи
SELECT R.a1, R.a2, S.b1, S.b2
FROM R INNER JOIN S ON R.a2=S.b1
Приклад 5.4. Тета-з'єднання відношень в SQL.
Природне з'єднання
Природним з'єднанням називається з'єднання по еквівалентності двох відношень R і S, виконане по усіх загальних атрибутах, з результатів якого виключається по одному екземпляру кожного загального атрибуту.
Таблиця 5.3. |
||
R.a1 |
R.a2 або S.b1 |
S.b2 |
a |
1 |
h |
a |
2 |
g |
b |
3 |
h |
b |
1 |
h |
SELECT R.a1, R.a2, S.b2
FROM R, S
WHERE R.a2=S.b1
чи
SELECT R.a1, S.b1, S.b2
FROM R INNER JOIN S ON R.a2=S.b1
Приклад 5.5. Природне з'єднання відношень в SQL.
Приклад 5.6. Вивести інформацію про продані товари.
SELECT *
FROM Угода, Товар
WHERE Угода.КодТовару=Товар.КодТовару
Чи (що еквівалентно)
SELECT *
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
Приклад 5.6. Вибірка інформації про продані товари.
Можна створити вкладені об'єднання, додавши третю таблицю до результату об'єднання двох інших таблиць.
Приклад 5.7. Отримати відомості про товари, дату угод, кількість проданого товару і покупців.
SELECT Товар.Назва, Угода.Кількість, Угода.
Дата, Клієнт.Фірма
FROM Клієнт INNER JOIN
( (Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару)
ON Клієнт.КодКлієнта=Угода.КодКлієнта
Приклад 5.7. Вибірка відомостей про товари, дату угод, кількість проданого товару і покупців.
Використання загальних імен таблиць для ідентифікації стовпців незручно із-за їх громіздкості. Кожній таблиці можна присвоїти яке-небудь коротке позначення, псевдонім.
Приклад 5.8. Отримати відомості про товари, дату угод, кількість проданого товару і покупців. У запиті використовуються псевдоніми таблиць.
SELECT Т. Назва, С. Кількість,
С. Дата, До.Фірма
FROM Клієнт AS До INNER JOIN
( (Товар AS Т INNER JOIN
Угода AS З
ON Т. КодТовару=С. КодТовару)
ON ДО.КодКлієнта=С. КодКлієнта;
Приклад 5.8. Вибірка відомостей про товари, дату угод, кількість проданого товару і покупців з використанням псевдоніма.
Зовнішнє з'єднання схоже на внутрішнє, але в результуючий набір даних включаються також записи провідної таблиці з'єднання, які об'єднуються з порожньою безліччю записів іншої таблиці.
Яка з таблиць буде такою, що веде, визначає вид з'єднання. LEFT - ліве зовнішнє з'єднання, ведучою є таблиця, розташована зліва від виду з'єднання ; RIGHT, - праве зовнішнє з'єднання, провідна таблиця розташована праворуч від виду з'єднання.
Ліве зовнішнє з'єднання
Лівим зовнішнім з'єднанням називається з'єднання, при якому кортежі відношення R, що не мають співпадаючих значень в загальних стовпцях відношення S, також включаються в результуюче відношення.
Таблиця 5.4. |
|||
R.a1 |
R.a2 |
S.b1 |
S.b2 |
a |
1 |
1 |
h |
a |
2 |
2 |
g |
b |
1 |
1 |
h |
b |
3 |
3 |
h |
b |
4 |
null |
null |
SELECT R.a1, R.a2, S.b1, S.b2
FROM R LEFT JOIN S ON R.a2=S.b1
Приклад 5.9. Ліве зовнішнє з'єднання відношень в SQL.
Існує і праве зовнішнє з'єднання , зване так тому, що в результуючому відношенні містяться усі кортежі правого відношення. Крім того, є і повне зовнішнє з'єднання, в його результуюче відношення поміщаються усі кортежі з обох відношень, а для позначення неспівпадаючих значень кортежів в нім використовуються визначники NULL.
SELECT R.a1, R.a2, S.b1, S.b2
FROM R RIGHT JOIN S ON R.a2=S.b1
Приклад 5.10. Праве зовнішнє з'єднання відношень в SQL.
Приклад 5.11. Вивести інформацію про усі товари. Для проданих товарів буде вказана дата угоди і кількість. Для непроданих ці поля залишаться порожніми.
SELECT Товар.*, Угода.*
FROM Товар LEFT JOIN Угода
ON Товар.КодТовару=Угода.КодТовару;
Приклад 5.11. Вибірка інформації про усі товари.
Напівз'єднання
Операція напівз'єднання визначає відношення, що містить ті кортежі відношення R, які входять в з'єднання відношень R і S .
Таблиця 5.5. |
|
R.a1 |
R.a2 |
a |
1 |
a |
2 |
b |
3 |
b |
1 |
SELECT R.a1, R.a2
FROM R, S
WHERE R.a2=S.b1
чи
SELECT R.a1, R.a2
FROM R INNER JOIN S ON R.a2=S.b1
Приклад 5.12. Напівз'єднання відношень в SQL.
Об'єднання ( UNION ) відношень R і S можна отримати в результаті їх конкатенації з утворенням одного відношення з виключенням кортежів-дублікатів. При цьому відношення R і S мають бути сумісні, тобто мати однакову кількість полів із співпадаючими типами даних. Інакше кажучи, відношення мають бути сумісні по об'єднанню.
Об'єднанням двох таблиць R і S є таблиця, що містить усі рядки, які є в першій таблиці R, в другій таблиці S або в обох таблицях відразу.
SELECT R.a1, R.a2
FROM R
UNION
SELECT S.b2, S.b1
FROM S
Приклад 5.13. Об'єднання відношень в SQL.
Операція перетину ( INTERSECT ) визначає відношення, яке містить кортежі, присутні як відносно R, так і відносно S. Відношення R і S мають бути сумісні по об'єднанню .
Перетином двох таблиць R і S є таблиця, що містить усі рядки, присутні в обох початкових таблицях одночасно.
SELECT R.a1, R.a2
FROM R, S
WHERE R.a1=S.b1 AND R.a2=S.b2
чи
SELECT R.a1, R.a2
FROM R
WHERE R.a1 IN
( (SELECT S.b1 FROM S
WHERE S.b1=R.a1) AND R.a2 IN
( (SELECT S.b2
FROM S
WHERE S.b2=R.a2)
Приклад 5.14. Перетин відношень в SQL.
Різниця ( EXCEPT ) R - S двох відношень R і S складається з кортежів, які є відносно R, але відсутні відносно S. Причому відношення R і S мають бути сумісні по об'єднанню.
Різницею двох таблиць R і S є таблиця, що містить усі рядки, які є присутніми в таблиці R, але відсутні в таблиці S.
SELECT R.a1, R.a2
FROM R
WHERE NOT EXISTS
( (SELECT S.b1, S.b2
FROM S
WHERE S.b1=R.a2 AND S.b2=R.a1)
Приклад 5.15. Різниця відношень в SQL.
Нехай A ={ім'я, підлога, ріст, вік, вага}; B ={ім'я, підлога, вік}; C ={ріст, вага}.
Таблиця 5.6. |
||||
Відношення R |
||||
ім'я |
пів |
ріст |
вік |
вага |
a |
ж |
160 |
20 |
60 |
b |
м |
180 |
30 |
70 |
c |
ж |
150 |
16 |
40 |
Відношення S |
||||
ім'я |
пів |
вік |
||
a |
ж |
20 |
T1=ПC(R) |
||||
ріст |
вага |
|||
160 |
60 |
|||
180 |
70 |
|||
150 |
40 |
|||
TT=(S X T1) - R |
||||
ім'я |
пів |
вік |
ріст |
вага |
a |
ж |
20 |
180 |
70 |
a |
ж |
20 |
150 |
40 |
T2=ПC((S X T1)-R) |
|
ріст |
вага |
180 |
70 |
150 |
40 |
T=T1 - T2 |
|
ріст |
вага |
160 |
60 |
Приклад 5.16. Ділення відношень в SQL.
• Створення відношення R
• CREATE TABLE R
• ((i int primary key
• ім'я varchar(3)
• пів varchar(3)
• ріст int
• вік int
вага int)
Приклад 5.16a. Ділення відношень в SQL.
• Створення відношення S
• CREATE TABLE S
• ((i int primary key
• ім'я varchar(3)
• пів varchar(3)
вік int)
Приклад 5.16b. Ділення відношень в SQL.
• Створення відношення T1
• CREATE VIEW T1
• AS
• SELECT ріст, вага
FROM R
Приклад 5.16c. Ділення відношень в SQL.
• Створення відношення TT
• CREATE VIEW TT AS
• SELECT S.ім'я, S.пів, S.вік,
• T1.ріст, T1.вага
FROM S, T1
Приклад 5.16d. Ділення відношень в SQL.
• Створення відношення T2
• CREATE VIEW T2
• AS
• SELECT TT.ріст, TT.вага
• FROM TT
• WHERE NOT EXISTS
• ( (SELECT R.ріст, R.вага
• FROM R
• WHERE TT.ім'я=R.ім'я AND TT.пів=R.пів
• AND TT.вік=R.вік
• AND TT.ріст=R.ріст
AND TT.вага=R.вага)
Приклад 5.16e. Ділення відношень в SQL.
• Створення відношення T
• SELECT T1.ріст, T1.вага
• FROM T1
• WHERE NOT EXISTS
• ( (SELECT T2.ріст, T2.вага
• FROM T2
WHERE T1.ріст=T2.ріст AND T1.вага=T2.вага)
Приклад 5.16f. Ділення відношень в SQL.
У загальному випадку для створення обчислюваного (похідного) поля в списку SELECT слід вказати деяке вираження мови SQL. У цих виразах застосовуються арифметичні операції складання, віднімання, множення і ділення, а також вбудовані функції мови SQL. Можна вказати ім'я будь-якого стовпця (поля) таблиці або запиту, але використовувати ім'я стовпця тільки тієї таблиці або запиту, які вказані в списку пропозиції FROM відповідної інструкції. При побудові складних виразів можуть знадобитися дужки.
Стандарти SQL дозволяють явним чином задавати імена стовпців результуючої таблиці, для чого застосовується фраза AS.
Приклад 6.1. Розрахувати загальну вартість для кожної угоди. Цей запит використовує розрахунок результуючих стовпців на основі арифметичних виразів.
SELECT Товар.Назва, Товар.Ціна,
Угода.Кількість
Товар.Ціна*Угода.Кількість AS Вартість
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
Приклад 6.1. Розрахунок загальної вартості для кожної угоди.
Приклад 6.2. Отримати список фірм з вказівкою прізвища і ініціалів клієнтів.
SELECT Фірма, Прізвище+" "+
Left(Ім'я, 1)+"" .+Left(По батькові, 1)+"".AS ПІБ
FROM Клієнт
Приклад 6.2. Отримання списку фірм з вказівкою прізвища і ініціалів клієнтів.
У запиті використана вбудована функція Left, що дозволяє вирізувати в текстовій змінній один символ ліворуч в даному випадку.
Приклад 6.3. Отримати список товарів з вказівкою року і місяця продажу.
SELECT Товар.Назва, Year(Угода.Дата)
AS Рік, Month(Угода.Дата) AS Місяць
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
Приклад 6.3. Отримання списку товарів з вказівкою року і місяця продажу.
У запиті використані вбудовані функції Year і Month для виділення року і місяця з дати.
За допомогою підсумкових (агрегатних) функцій у рамках SQL -запиту можна отримати ряд узагальнювальних статистичних відомостей про безліч відібраних значень вихідного набору.
Користувачеві доступні наступні основні підсумкові функції:
• Count (Вираження) - визначає кількість записів у вихідному наборі SQL -запиту;
• Min/Max (Вираження) - визначають найменше і найбільше з безлічі значень в деякому полі запиту;
• Avg (Вираження) - ця функція дозволяє розрахувати середнє значення безлічі значень, що зберігаються в певному полі відібраних запитом записів. Воно є арифметичним середнім значенням, тобто сумою значень, що ділиться на їх кількість.
• Sum (Вираження) - обчислює суму безлічі значень, що містяться в певному полі відібраних запитом записів.
Найчастіше вираженням виступають імена стовпців. Вираження може обчислюватися і по значеннях декількох таблиць.
Усі ці функції оперують зі значеннями в єдиному стовпці таблиці або з арифметичним вираженням і повертають єдине значення. Функції COUNT, MIN і MAX застосовані як до числових, так і до нечислових полів, тоді як функції SUM і AVG можуть використовуватися тільки у разі числових полів, за винятком COUNT(*). При обчисленні результатів будь-яких функцій спочатку виключаються усі порожні значення, після чого необхідна операція застосовується тільки до конкретних значень стовпця, що залишилися. Варіант COUNT(*) - особливий випадок використання функції COUNT, його призначення полягає в підрахунку усіх рядків в результуючій таблиці, незалежно від того, містяться там порожні, такі, що дублюються або будь-які інші значення.
Якщо до застосування узагальнювальної функції необхідно виключити значення, що дублюються, слід перед ім'ям стовпця у визначенні функції помістити ключове слово DISTINCT. Воно не має сенсу для функцій MIN і MAX, проте його використання може вплинути на результати виконання функцій SUM і AVG, тому необхідно заздалегідь обдумати, чи повинне воно бути присутнім у кожному конкретному випадку. Крім того, ключове слово DISTINCT може бути вказане у будь-якому запиті не більше одного разу.
Дуже важливо відмітити, що підсумкові функції можуть використовуватися тільки в списку пропозиції SELECT і у складі пропозиції HAVING. У усіх інших випадках це неприпустимо. Якщо список в пропозиції SELECT містить підсумкові функції, а в тексті запиту відсутня фраза GROUP BY, що забезпечує об'єднання даних в групи, то жоден з елементів списку пропозиції SELECT не може включати яких-небудь посилань на поля, за винятком ситуації, коли поля виступають аргументами підсумкових функцій.
Приклад 6.4. Визначити першу за абеткою назву товару.
SELECT Min(Товар.Назва) AS Min_Назва
FROM Товар
Приклад 6.4. Визначення першої за абеткою назви товару.
Приклад 6.5. Визначити кількість угод.
SELECT Count(*) AS Кількість_угод
FROM Угода
Приклад 6.5. Визначити кількість угод.
Приклад 6.6. Визначити сумарну кількість проданого товару.
SELECT Sum(Угода.Кількість)
AS Кількість_товару
FROM Угода
Приклад 6.6. Визначення сумарної кількості проданого товару.
Приклад 6.7. Визначити середню ціну проданого товару.
SELECT Avg(Товар.Ціна) AS Avg_Ціна
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару;
Приклад 6.7. Визначення середньої ціни проданого товару.
Приклад 6.8. Підрахувати загальну вартість проданих товарів.
SELECT Sum(Товар.Ціна*Угода.Кількість)
AS Вартість
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
Приклад 6.8. Підрахунок загальної вартості проданих товарів.
Часто в запитах вимагається формувати проміжні підсумки, що зазвичай відображається появою в запиті фрази "для кожного.". Для цієї мети в операторові SELECT використовується пропозиція GROUP BY. Запит, в якому є присутнім GROUP BY, називається групуючим запитом, оскільки в нім групуються дані, отримані в результаті виконання операції SELECT, після чого для кожної окремої групи створюється єдиний сумарний рядок. Стандарт SQL вимагає, щоб пропозиція SELECT і фраза GROUP BY були тісно пов'язані між собою. За наявності в операторові SELECT фрази GROUP BY кожен елемент списку в пропозиції SELECT повинен мати єдине значення для усієї групи. Більше того, пропозиція SELECT може включати тільки наступні типи елементів : імена полів, підсумкові функції, константи і вирази, що включають комбінації перелічених вище елементів.
Усі імена полів, приведені в списку пропозиції SELECT, мають бути присутніми і у фразі GROUP BY - за винятком випадків, коли ім'я стовпця використовується в підсумковій функції. Зворотне правило не є справедливим - у фразі GROUP BY можуть бути імена стовпців, відсутні в списку пропозиції SELECT.
Якщо спільно з GROUP BY використовується пропозиція WHERE, то воно обробляється першим, а групуванню піддаються тільки ті рядки, які задовольняють умові пошуку.
Стандартом SQL визначено, що при проведенні групування усі відсутні значення розглядаються як рівні. Якщо два рядки таблиці в одному і тому ж групованому стовпці містять значення NULL і ідентичні значення в усіх інших непорожніх групованих стовпцях, вони поміщаються в одну і ту ж групу.
Приклад 6.9. Вичислити середній об'єм покупок, здійснених кожним покупцем.
SELECT Клієнт.Прізвище, Avg(Угода.Кількість)
AS Середня_кількість
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта
GROUP BY Клієнт.Прізвище
Приклад 6.9. Обчислення середнього об'єму покупок, здійснених кожним покупцем.
Фраза "кожним покупцем" знайшла своє віддзеркалення в SQL -запиті у вигляді пропозиції GROUP BY Клиент.Прізвище.
Приклад 6.10. Визначити, на яку суму був проданий товар кожного найменування.
SELECT Товар.Назва,
Sum(Товар.Ціна*Угода.Кількість)
AS Вартість
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
GROUP BY Товар.Назва
Приклад 6.10. Визначення, на яку суму був проданий товар кожного найменування.
Приклад 6.11. Підрахувати кількість угод, здійснених кожною фірмою.
SELECT Клієнт.Фірма, Count(Угода.КодУгоди)
AS Кількість_угод
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта
GROUP BY Клієнт.Фірма
Приклад 6.11. Підрахунок кількості угод, здійснених кожною фірмою.
Приклад 6.12. Підрахувати загальну кількість купленого для кожної фірми товару і його вартість.
SELECT Клієнт.Фірма, Sum(Угода.Кількість)
AS Загальна_Кількість,
Sum(Товар.Ціна*Угода.Кількість)
AS Вартість
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
GROUP BY Клієнт.Фірма
Приклад 6.12. Підрахунок загальної кількості купленого для кожної фірми товару і його вартості.
Приклад 6.13. Визначити сумарну вартість кожного товару за кожен місяць.
SELECT Товар.Назва, Month(Угода.Дата)
AS Місяць
Sum(Товар.Ціна*Угода.Кількість)
AS Вартість
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
GROUP BY Товар.Назва, Month(Угода.Дата)
Приклад 6.13. Визначення сумарної вартості кожного товару за кожен місяць.
Приклад 6.14. Визначити сумарну вартість кожного товару першого сорту за кожен місяць.
SELECT Товар.Назва, Month(Угода.Дата)
AS Місяць
Sum(Товар.Ціна*Угода.Кількість)
AS Вартість
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
WHERE Товар.Сорт="Перший"
GROUP BY Товар.Назва, Month(Угода.Дата)
Приклад 6.14. Визначення сумарної вартості кожного товару першого сорту за кожен місяць.
За допомогою HAVING відбиваються усі попередньо згруповані за допомогою GROUP BY блоки даних, задовольняючі заданим в HAVING умовам. Це додаткова можливість "профільтрувати" вихідний набір.
Умови в HAVING відрізняються від умов в WHERE:
• HAVING виключає з результуючого набору даних групи з результатами агрегованих значень;
• WHERE виключає з розрахунку агрегатних значень по угрупуванню записи, що не задовольняють умові;
• у умові пошуку WHERE не можна задавати агрегатні функції.
Приклад 6.15. Визначити фірми, у яких загальна кількість угод перевищила три.
SELECT Клієнт.Фірма, Count(Угода.Кількість)
AS Кількість_угод
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта
GROUP BY Клієнт.Фірма
HAVING Count(Угода.Кількість)>3
Приклад 6.15. Визначення фірм, у яких загальна кількість угод перевищила три.
Приклад 6.16. Вивести список товарів, проданих на суму більше 10000 грн.
SELECT Товар.Назва,
Sum(Товар.Ціна*Угода.Кількість)
AS Вартість
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
GROUP BY Товар.Назва
HAVING Sum(Товар.Ціна*Угода.Кількість)>10000
Приклад 6.16. Виведення списку товарів, проданих на суму більше 10000 грн.
Приклад 6.17. Вивести список товарів, проданих на суму більше 10000 без вказівки суми.
SELECT Товар.Назва
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
GROUP BY Товар.Назва
HAVING Sum(Товар.Ціна*Угода.Кількість)>10000
Приклад 6.17. Виведення списку товарів, проданих на суму більше 10000 без вказівки суми.
Часто неможливо вирішити поставлене завдання шляхом одного запиту. Це особливо актуально, коли при використанні умови пошуку в пропозиції WHERE значення, з яким потрібно порівнювати, заздалегідь не визначене і має бути вичислене у момент виконання оператора SELECT. У такому разі приходять на допомогу закінчені оператори SELECT, впроваджені в тіло іншого оператора SELECT. Внутрішній підзапит є також оператор SELECT, а кодування його пропозицій підкоряється тим же правилам, що і основного оператора SELECT. Зовнішній оператор SELECT використовує результат виконання внутрішнього оператора для визначення змісту остаточного результату усієї операції. Внутрішні запити можуть бути поміщені безпосередньо після оператора порівняння ( =,<=, >=, <> ) в пропозиції WHERE і HAVING зовнішнього оператора SELECT - вони отримують назву підзапитів або вкладених запитів. Крім того, внутрішні оператори SELECT можуть застосовуватися в операторах INSERT, UPDATE і DELETE.
Підзапит - це інструмент створення тимчасової таблиці, вміст якої витягається і обробляється зовнішнім оператором. Текст підзапиту має бути поміщений в дужки. До підзапитів застосовуються наступні правила і обмеження :
• фраза ORDER BY не використовується, хоча і може бути присутньою в зовнішньому підзапиті ;
• список в пропозиції SELECT складається з імен окремих стовпців або складених з них виразів - за винятком випадку, коли в підзапиті є присутнім ключове слово EXISTS ;
• за умовчанням імена стовпців в підзапиті відносяться до таблиці, ім'я якої вказане в пропозиції FROM. Проте допускається посилання і на стовпці таблиці, вказаної у фразі FROM зовнішнього запиту, для чого застосовуються кваліфіковані імена стовпців (тобто з вказівкою таблиці);
• якщо підзапит є одним з двох операндів, що беруть участь в операції порівняння, то запит повинен вказуватися в правій частині цієї операції.
Існує два типи підзапитів :
• Скалярний підзапит повертає єдине значення. В принципі, він може використовуватися скрізь, де вимагається вказати єдине значення.
• Табличний підзапит повертає безліч значень, тобто значення одного або декількох стовпців таблиці, розміщені у більш ніж одному рядку. Він можливий скрізь, де допускається наявність таблиці.
Приклад 7.1. Визначити дату продажу максимальної партії товару.
SELECT Дата, Кількість
FROM Угода
WHERE Кількість=(SELECT Max(Кількість) FROM Угода)
Приклад 7.1. Визначення дати продажу максимальної партії товару.
У вкладеному підзапиті визначається максимальна кількість товару. У зовнішньому підзапиті - дата, для якої кількість товару виявилася рівною максимальному. Необхідно відмітити, що не можна прямо використовувати пропозицію WHERE Кількість=Max(Кількість), оскільки застосовувати узагальнювальні функції в пропозиціях WHERE заборонено. Для досягнення бажаного результату слідує створити підзапит, що обчислює максимальне значення кількості, а потім використовувати його в зовнішньому операторові SELECT, призначеному для вибірки дат угод, де кількість товару співпала з максимальним значенням.
Приклад 7.2. Визначити дати угод, що перевищили по кількості товару середнє значення і вказати для цих угод перевищення над середнім рівнем.
SELECT Дата, Кількість,
Кількість-(SELECT Avg(Кількість)
FROM Угода) AS Перевищення
FROM Угода
WHERE Кількість>
( (SELECT Avg(Кількість)
FROM Угода)
Приклад 7.2. Визначення дати угод, що перевищили по кількості товару середнє значення і вказати для цих угод перевищення над середнім рівнем.
У наведеному прикладі результат підзапиту, що є середнім значенням кількості товару по усіх угодах взагалі, використовується в зовнішньому операторові SELECT як для обчислення відхилення кількості від середнього рівня, так і для відбору відомостей про дати.
Приклад 7.3. Визначити клієнтів, що зробили угоди з максимальною кількістю товару.
SELECT Клієнт.Прізвище
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта
WHERE Угода.Кількість=
( (SELECT Max(Угода.Кількість)
FROM Угода)
Приклад 7.3. Визначення клієнтів, що зробили угоди з максимальною кількістю товару.
Тут показаний приклад використання підзапиту при вибірці даних з різних таблиць.
Приклад 7.4. Визначити клієнтів, в угодах яких кількість товару відрізняється від максимального не більше ніж на 10%.
SELECT Клієнт.Прізвище,
Угода.Кількість
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=
Угода.КодКлієнта
WHERE Угода.Кількість>=0.9*
( (SELECT Max(Угода.Кількість)
FROM Угода)
Приклад 7.4. Визначення клієнтів, в угодах яких кількість товару відрізняється від максимального не більше ніж на 10%.
Покажемо, як застосовуються підзапити в пропозиції HAVING.
Приклад 7.5. Визначити дати, коли середня кількість проданого за день товару виявилася більше 20 одиниць.
SELECT Угода.Дата, Avg(Угода.Кількість) AS
Середнє_за_день
FROM Угода
GROUP BY Угода.Дата
HAVING Avg(Угода.Кількість)>20
Приклад 7.5. Визначення дати, коли середня кількість проданого за день товару виявилася більше 20 одиниць.
За кожен день визначається середня кількість товару, яка порівнюється з числом 20. Додамо в запит підзапит.
Приклад 7.6. Визначити дати, коли середня кількість проданого за день товару виявилася більше середнього показника по усіх угодах взагалі.
SELECT Угода.Дата,
Avg(Угода.Кількість)
AS Середнє_за_день
FROM Угода
GROUP BY Угода.Дата
HAVING Avg(Угода.Кількість)>
( (SELECT Avg(Угода.Кількість)
FROM Угода)
Приклад 7.6. Визначення дати, коли середня кількість проданого за день товару виявилася більше середнього показника по усіх угодах взагалі.
Внутрішній підзапит визначає середній по усіх угодах показник, з яким в зовнішньому запиті порівнюється середня за кожен день кількість товару.
У багатьох випадках значення, підмет порівнянню в пропозиціях WHERE або HAVING, є не одно, а декілька значень. Вкладені підзапити генерують непойменоване проміжне відношення, тимчасову таблицю. Воно може використовуватися тільки в тому місці, де з'являється в підзапиті. До такого відношення неможливо звернутися по імені з якого-небудь іншого місця запиту. Застосовувані до підзапиту операції засновані на тих операціях, які, у свою чергу, застосовуються до множини, а саме:
• { WHERE | HAVING } вираження [ NOT ] IN ( підзапит );
• { WHERE | HAVING } вираження оператор_порівняння { ALL | SOME | ANY } ( підзапит );
• {WHERE | HAVING } [ NOT ] EXISTS ( підзапит );
Використання операцій IN і NOT IN
Оператор IN використовується для порівняння деякого значення із списком значень, при цьому перевіряється, чи входить значення в наданий список або порівнюване значення не є елементом представленого списку.
Приклад 7.7. Визначити список товарів, які є на складі.
SELECT Назва
FROM Товар
WHERE КодТовару In
( (SELECT КодТовару FROM Склад)
Приклад 7.7. Визначення списку товарів, які є на складі.
Приклад 7.8. Визначити список відсутніх на складі товарів.
SELECT Назва
FROM Товар
WHERE КодТовару Not In (SELECT КодТовару
FROM Склад)
Приклад 7.8. Визначення списку відсутніх на складі товарів.
Приклад 7.9. Визначити товари, які купують клієнти з Києва.
SELECT DISTINCT Товар.Назва,
Клієнт.МістоКлієнта
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
WHERE Клієнт.МістоКлієнта='Київ'
Приклад 7.9. Визначення товарів, які купують клієнти з Києва.
У результат включаються товари, придбані клієнтами з Києва, проте не виключено, що покупцями таких товарів були і клієнти з інших міст.
Введення в запит фрази "тільки" вимагає використання операції NOT IN.
Приклад 7.10. Визначити товари, купівлю яких здійснюють тільки клієнти з Києва, і ніхто інший.
SELECT DISTINCT Товар.Назва,
Клієнт.МістоКлієнта
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
WHERE Товар.Назва NOT IN
( (SELECT Товар.Назва
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
WHERE Клієнт.МістоКлієнта<>'Київ')
Приклад 7.10. Визначення товарів, купівлю яких здійснюють тільки клієнти з Києва, і ніхто інший.
Приклад 7.11. Які товари жодного разу не купили київські клієнти?
SELECT DISTINCT Товар.Назва,
Клієнт.МістоКлієнта
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
WHERE Товар.Назва NOT IN
( (SELECT Товар.Назва
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
WHERE Клієнт.МістоКлієнта='Київ')
Приклад 7.11. Визначення товарів, які жодного разу не купили київські клієнти
У вкладеному запиті визначається список товарів, що придбавалися клієнтами з Києва. У зовнішньому запиті вибираються тільки ті товари, які не входять в цей список.
Приклад 7.12. Визначити фірми, що купують товари місцевого виробництва.
SELECT DISTINCT Клієнт.Фірма, Клієнт.МістоКлієнта
Товар.МістоТовару
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
WHERE Клієнт.МістоКлієнта=Товар.МістоТовару
Приклад 7.12. Визначення фірм, що купують товари місцевого виробництва.
В результаті виконання запиту перераховуються угоди, коли клієнтові був проданий товар, виготовлений в його місті, що зовсім не виключає наявність угод цих же клієнтів, пов'язаних з придбанням товару з іншого міста.
Введемо в запит фразу "тільки" - відразу знадобиться залучення операції NOT IN.
Приклад 7.13. Визначити фірми, які купують тільки товари, вироблені у своєму місті, і ніякі інші.
SELECT DISTINCT Клієнт.Фірма,
Клієнт.МістоКлієнта
Товар.МістоТовару
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
WHERE Клієнт.МістоКлієнта NOT IN
( (SELECT DISTINCT Клієнт.МістоКлієнта
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
WHERE Клієнт.МістоКлієнта<>
Товар.МістоТовару)
Приклад 7.13. Визначення фірм, які купують тільки товари, вироблені у своєму місті, і ніякі інші.
У вкладеному запиті визначається безліч фірм, що зробили хоч би одну купівлю товару з чужого міста. Потім визначаються фірми, що не входять в цю множину.
Використання ключових слів ANY і ALL
Ключові слова ANY і ALL можуть використовуватися з підзапитами, що повертають один стовпець чисел.
Якщо підзапиту передуватиме ключове слово ALL, умова порівняння вважається виконаною, тільки коли воно виконується для усіх значень в результуючому стовпці підзапиту.
Якщо запису підзапиту передує ключове слово ANY, то умова порівняння вважається виконаною, коли воно виконується хоч би для одного зі значень в результуючому стовпці підзапиту.
Якщо в результаті виконання підзапиту отримано порожнє значення, то для ключового слова ALL умова порівняння вважатиметься виконаною, а для ключового слова ANY - невиконаним. Ключове слово SOME є синонімом слова ANY.
Приклад 7.14. Визначити клієнтів, що зробили угоди з максимальною кількістю товару (еквівалентно запиту 7.3.)
SELECT Клієнт.Прізвище, Угода.Кількість
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта
WHERE Угода.Кількість>=ALL(SELECT Кількість
FROM Угода)
Приклад 7.14. Визначення клієнтів, що зробили угоди з максимальною кількістю товару.
У прикладі визначені клієнти, в угодах яких кількість товару більше або дорівнює кількості товару в кожній з усіх угод.
Приклад 7.15. Знайти фірму, що купила товарів на суму, що перевищує 10000 грн.
SELECT Клієнт.Фірма,
Sum(Товар.Ціна*Угода.Кількість)
AS Общ_вартість
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
GROUP BY Клієнт.Фірма
HAVING Sum(Товар.Ціна*Угода.Кількість)>10000
Приклад 7.15. Визначення фірми, що купила товарів на суму, що перевищує 10000 грн.
Додамо в запит підзапит.
Приклад 7.16. Знайти фірму, яка придбала товарів на найбільшу суму.
SELECT Клієнт.Фірма,
Sum(Товар.Ціна*Угода.Кількість)
AS Общ_вартість
FROM Товар INNER JOIN
( (Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта)
ON Товар.КодТовару=Угода.КодТовару
GROUP BY Клієнт.Фірма
HAVING Sum(Товар.Ціна*Угода.Кількість)>=
ALL(SELECT Sum(Товар.Ціна*Угода.Кількість)
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
GROUP BY Угода.КодКлієнта)
Приклад 7.16. Визначення фірми, яка придбала товарів на найбільшу суму.
Вкладений підзапит підраховує загальну вартість покупок кожного клієнта. Зовнішній підзапит також підраховує загальну вартість покупок кожного клієнта і визначає тих, для кого ця сума, в порівнянні з іншими покупцями, виявилася більше або такий самий же.
Приклад 7.17. Знайти фірми, в угодах яких кількість товару перевищує такий же показник хоч би в одній угоді клієнтів з Чернігова.
SELECT Клієнт.Фірма, Угода.Кількість
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта
WHERE Угода.Кількість>
ANY(SELECT Угода.Кількість
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта
WHERE Клієнт.МістоКлієнта='Чернігів')
Приклад 7.17. Визначення фірм, в угодах яких кількість товару перевищує такий же показник хоч би в одній угоді клієнтів з Чернігова.
Використання операцій EXISTS і NOT EXISTS
Ключові слова EXISTS і NOT EXISTS призначені для використання тільки спільно з підзапитами. Результат їх обробки є логічним значенням TRUE або FALSE. Для ключового слова EXISTS результат рівний TRUE в тому і тільки у тому випадку, якщо в поверненій підзапитом результуючій таблиці є присутнім хоч би один рядок. Якщо результуюча таблиця підзапиту порожня, результатом обробки операції EXISTS буде значення FALSE. Для ключового слова NOT EXISTS використовуються правила обробки, зворотні по відношенню до ключового слова EXISTS . Оскільки за ключовими словами EXISTS і NOT EXISTS перевіряється лише наявність рядків в результуючій таблиці підзапиту, то ця таблиця може містити довільну кількість стовпців.
Приклад 7.18. Визначити список наявних на складі товарів (запит еквівалентний прикладу 7.7).
SELECT Назва
FROM Товар
WHERE EXISTS (SELECT КодТовару
FROM Склад
WHERE Товар.КодТовару=Склад.КодТовару)
Приклад 7.18. Визначення списку наявних на складі товарів.
Приклад 7.19. Визначити список відсутніх на складі товарів (запит еквівалентний прикладу 7.8).
SELECT Назва
FROM Товар
WHERE NOT EXISTS (SELECT КодТовару
FROM Склад
WHERE Товар.КодТовару=Склад.КодТовару)
Приклад 7.19. Визначення списку відсутніх на складі товарів.
Мова SQL орієнтована на виконання операцій над групами записів, хоча в деяких випадках їх можна проводити і над окремим записом.
Запити дії є досить потужним засобом, оскільки дозволяють оперувати не лише окремими рядками, але і набором рядків. За допомогою запитів дії користувач може додати, видалити або відновити блоки даних. Існує три види запитів дії:
• INSERT INTO - запит додавання ;
• DELETE - запит видалення ;
• UPDATE - запит оновлення.
Оператор INSERT застосовується для додавання записів в таблицю. Формат оператора:
<оператор_вставки>::=INSERT INTO <ім'я_таблиці>
[(ім'я_стовпця [,..n])]
{VALUES (значення[,..n])|
<SELECT_оператор>}
Тут параметром ім'я_таблиці є або ім'я таблиці бази даних, або ім'я оновлюваного представлення.
Перша форма оператора INSERT з параметром VALUES призначена для вставки єдиного рядка у вказану таблицю. Список стовпців вказує стовпці, яким будуть присвоєні значення в записах, що додаються. Список може бути опущений, тоді маються на увазі усі стовпці таблиці (окрім оголошених як лічильник), причому в певному порядку, встановленому при створенні таблиці. Якщо в операторові INSERT вказується конкретний список імен полів, то будь-які пропущені в нім стовпці мають бути оголошені при створенні таблиці як що допускають значення NULL, за винятком тих випадків, коли при описі стовпця використовувався параметр DEFAULT. Список значень повинен таким чином відповідати списку стовпців :
• кількість елементів в обох списках має бути однаковою;
• повинна існувати пряма відповідність між позицією одного і того ж елементу в обох списках, тому перший елемент списку значень повинен відноситися до першого стовпця в списку стовпців, другий - до другого стовпця і так далі
• типи цих елементів в списку значень мають бути сумісні з типами цих відповідних стовпців таблиці.
Приклад 8.1. Додати в таблицю ТОВАР новий запис.
INSERT INTO Товар (Назва, Тип, Ціна)
VALUES(" Слов'янський ", " шоколад ", 12)
Приклад 8.1. Додавання в таблицю ТОВАР нового запису.
Якщо стовпці таблиці ТОВАР вказані у повному складі і в тому порядку, в якому вони перераховані при створенні таблиці ТОВАР, оператор можна спростити.
INSERT INTO Товар VALUES (" Слов'янський
" " шоколад ", 12)
Друга форма оператора INSERT з параметром SELECT дозволяє скопіювати безліч рядків з однієї таблиці в іншу. Пропозиція SELECT може бути будь-який допустимий оператор SELECT. Рядки, що вставляються у вказану таблицю, в точності повинні відповідати рядкам результуючої таблиці, створеної при виконанні вкладеного запиту. Усі обмеження, вказані вище для першої форми оператора SELECT, застосовні і в цьому випадку.
Оскільки оператор SELECT в загальному випадку повертає безліч записів, то оператор INSERT в такій формі призводить до додавання в таблицю аналогічного числа нових записів.
Приклад 8.2. Додати в підсумкову таблицю зведення про загальну суму щомісячних продажів кожного найменування товару.
INSERT INTO Підсумок
( (Назва, Місяць, Вартість )
SELECT Товар.Назва, Month(Угода.Дата)
AS Місяць, Sum(Товар.Ціна*Угода.Кількість)
AS Вартість
FROM Товар INNER JOIN Угода
ON Товар.КодТовару= Угода.КодТовару
GROUP BY Товар.Назва, Month(Угода.Дата)
Приклад 8.2. Додавання в підсумкову таблицю зведення про загальну суму щомісячних продажів кожного найменування товару.
Оператор DELETE призначений для видалення групи записів з таблиці.
Формат оператора :
<оператор_видалення> ::=DELETE
FROM <ім'я_таблиці>[WHERE <умова_відбору>]
Тут параметром ім'я_таблиці є або ім'я таблиці бази даних, або ім'я оновлюваного представлення.
Якщо пропозиція WHERE є присутньою, віддаляються записи з таблиці, що задовольняють умові відбору. Якщо опустити пропозицію WHERE, з таблиці будуть видалені усі записи, проте сама таблиця збережеться.
Приклад 8.3. Видалити усі торішні угоди.
DELETE
FROM Угода
WHERE Year(Угода.Дата)=Year(GETDATE()) 1
Приклад 8.3. Видалення усіх торішніх угод.
У наведеному прикладі умова відбору формується з урахуванням року (функція Year ) від поточної дати (функція GETDATE() ).
Оператор UPDATE застосовується для зміни значень в групі записів або в одному записі вказаної таблиці.
Формат оператора :
<оператор_зміни> ::=
UPDATE ім'я_таблиці SET ім'я_стовпця=
<вираження>[,..n]
[WHERE <умова_відбору>]
Параметр ім'я_таблиці - це або ім'я таблиці бази даних, або ім'я оновлюваного представлення. У пропозиції SET вказуються імена одного і більше за стовпці, дані в яких необхідно змінити. Пропозиція WHERE є необов'язковою. Якщо воно опущене, значення вказаних стовпців будуть змінені в усіх рядках таблиці. Якщо пропозиція WHERE є присутньою, то оновлені будуть тільки ті рядки, які задовольняють умові відбору. Вираження є новим значенням відповідного стовпця і має бути сумісне з ним за типом даних.
Приклад 8.4. Для товарів першого сорту встановити ціну в значення 140 і залишок - в значення 20 одиниць.
UPDATE Товар SET Товар.Ціна=140, Товар.Залишок=20
WHERE Товар.Сорт=" Перший "
Приклад 8.4. Оновлення вибраних записів.
Приклад 8.5. Збільшити ціну товарів першого сорту на 25%.
UPDATE Товар SET Товар.Ціна=Товар.Ціна*1.25
WHERE Товар.Сорт=" Перший "
Приклад 8.5. Оновлення вибраних записів.
Приклад 8.6. У угоді з максимальною кількістю товару збільшити число товарів на 10%.
UPDATE Угода SET Угода.Кількість=
Угода.Кількість*1.1
WHERE Угода.Кількість=
( (SELECT Max(Угода.Кількість) FROM Угода)
Приклад 8.6. Оновлення вибраних записів.
Виконання операторів модифікації даних в таблицях бази даних INSERT, DELETE і UPDATE може привести до порушення цілісності даних і їх коректності, тобто до втрати їх достовірності і несуперечності.
Щоб інформація, що зберігається у базі даних, була однозначною і несуперечливою, в реляційній моделі встановлюються деякі обмежувальні умови - правила, що визначають можливі значення даних і таких, що забезпечують логічну основу для підтримки коректних значень. Обмеження цілісності дозволяють звести до мінімуму помилки, що виникають при оновленні і обробці даних.
У базі даних, побудованій на реляційній моделі, задається ряд правил цілісності, які, по суті, є обмеженнями для усіх допустимих станів бази даних і гарантують коректність даних. Розглянемо наступні типи обмежень цілісності даних :
• обов'язкові дані;
• обмеження для доменів полів;
• корпоративні обмеження;
• цілісність сутностей;
• посилальна цілісність.
Обов'язкові дані
Деякі поля завжди повинні містити одно з допустимих значень, іншими словами, ці поля не можуть мати порожнього значення.
Обмеження для доменів полів
Кожне поле має свій домен, що є набором його допустимих значень.
Корпоративні обмеження цілісності
Існує поняття "корпоративні обмеження цілісності " як додаткові правила підтримки цілісності даних, визначувані користувачами, прийняті на підприємстві або адміністраторами баз даних. Обмеження підприємства називаються бізнес-правилами.
Цілісність сутностей
Це обмеження цілісності торкається первинних ключів базових таблиць. За визначенням, первинний ключ - мінімальний ідентифікатор (одно або декілька полів), який використовується для унікальної ідентифікації записів в таблиці. Таким чином, ніяка підмножина первісного ключа не може бути достатньою для унікальної ідентифікації записів.
Цілісність сутностей визначає, що у базовій таблиці жодне поле первинного ключа не може містити відсутніх значень, позначених NULL.
Якщо допустити присутність визначника NULL у будь-якій частині первинного ключа, це рівносильно твердженню, що не усі його поля потрібні для унікальної ідентифікації записів, і суперечить визначенню первинного ключа.
Цілісність посилання
Вказане обмеження цілісності торкається зовнішніх ключів. Зовнішній ключ - це поле (чи безліч полів) однієї таблиці, що є ключем іншої (чи тій же самій) таблиці. Зовнішні ключі використовуються для встановлення логічних зв'язків між таблицями. Зв'язок встановлюється шляхом привласнення значень зовнішнього ключа однієї таблиці значенням ключа інший.
Між двома або більше таблицями бази даних можуть існувати стосунки підлеглості, які визначають, що для кожного запису головної таблиці (званою ще батьківською ) може існувати одна або декілька записів в підпорядкованій таблиці (званою так же дочірньої ).
Існує три різновиди зв'язку між таблицями бази даних :
• ""один-до-багатьох";
• ""один-до-одного";
• ""багато-до-багатьох".
Відношення "один-до-одного" має місце, коли одному запису батьківської таблиці може відповідати декілька записів дочірньої. Зв'язок "один-до-багатьох" іноді називають зв'язком "багато-до-одного". І у тому, і в іншому випадку суть зв'язку між таблицями залишається незмінною.
Зв'язок "один-до-багатьох" найбільш поширений для реляційних баз даних. Вона дозволяє моделювати також ієрархічні структури даних.
Відношення "один-до-одного" має місце, коли одному запису у батьківській таблиці відповідає один запис в дочірній. Це відношення зустрічається набагато рідше, ніж відношення "один-до-багатьох". Його використовують, якщо не хочуть, щоб таблиця БД "розпухала" від другорядної інформації. Використання зв'язку "один-до-одного" призводить до того, що для читання пов'язаної інформації в декількох таблицях доводиться робити декілька операцій читання замість однієї, коли дані зберігаються в одній таблиці.
Відношення "багато-до-багатьох" має місце в наступних випадках:
• одному запису у батьківській таблиці відповідає більше за один запис в дочірній таблиці ;
• одному запису в дочірній таблиці відповідає більше за один запис у батьківській таблиці.
Вважається, що всякий зв'язок "багато-до-багатьох" може бути замінений на зв'язок "один-до-багатьох" (один або декілька).
Часто зв'язок між таблицями встановлюється по первинному ключу, тобто значення зовнішнього ключа однієї таблиці привласнюються значенню первісного ключа іншої. Проте це не є обов'язковим - в загальному випадку зв'язок може встановлюватися і за допомогою вторинних ключів. Крім того, при встановленні зв'язків між таблицями не потрібно неодмінну унікальність ключа, що забезпечує встановлення зв'язку. Поля зовнішнього ключа не зобов'язані мати тих же імен, що і імена ключів, яким вони відповідають. Зовнішній ключ може посилатися на свою власну таблицю - у такому разі зовнішній ключ називається рекурсивним.
Посилальна цілісність визначає: якщо в таблиці існує зовнішній ключ, то його значення повинне або відповідати значенню первісного ключа деякого запису у базовій таблиці, або задаватися визначником NULL.
Існує декілька важливих моментів, пов'язаних із зовнішніми ключами. По-перше, слід проаналізувати, чи допустиме використання в зовнішніх ключах порожніх значень. У загальному випадку, якщо участь дочірньої таблиці в зв'язку є обов'язковою, то рекомендується забороняти застосування порожніх значень у відповідному зовнішньому ключі. В той же час, якщо має місце часткова участь дочірньої таблиці в зв'язку, то приміщення порожніх значень в поле зовнішнього ключа має бути дозволене. Наприклад, якщо в операції фіксації угод деякої торгової фірми необхідно вказати покупця, то поле КодКлієнта повинне мати атрибут NOT NULL. Якщо допускається продаж або купівля товару без вказівки клієнта, то для поля КодКлієнта можна вказати атрибут NULL.
Наступна проблема пов'язана з організацією підтримки посилальної цілісності при виконанні операцій модифікації даних у базі. Тут можливі наступні ситуації:
1. Вставка нового рядка в дочірню таблицю. Для забезпечення посилальної цілісності необхідно переконатися, що значення зовнішнього ключа нового рядка дочірньої таблиці рівно порожньому значенню або деякому конкретному значенню, присутньому в поле первісного ключа одного з рядків батьківської таблиці.
2. Видалення рядка з дочірньої таблиці. Ніяких порушень посилальної цілісності не відбувається.
3. Оновлення зовнішнього ключа в рядку дочірньої таблиці. Цей випадок подібний до описаної вище першої ситуації. Для збереження цілісності посилання необхідно переконатися, що значення зовнішнього ключа в оновленому рядку дочірньої таблиці рівно порожньому значенню або деякому конкретному значенню, присутньому в полі первинного ключа одного з рядків батьківської таблиці.
4. Вставка рядка у батьківську таблицю. Така вставка не може викликати порушення посилальної цілісності. Доданий рядок просто стає батьківським об'єктом, що не має дочірніх об'єктів.
5. Видалення рядка з батьківської таблиці. Посилальна цілісність виявиться порушеною, якщо в дочірній таблиці існуватимуть рядки, що посилаються на видалений рядок батьківської таблиці. В цьому випадку може використовуватися одна з наступних стратегій :
o NO ACTION. Видалення рядка з батьківської таблиці забороняється, якщо в дочірній таблиці існує хоч би один рядок, що посилається на неї.
o CASCADE. При видаленні рядка з батьківської таблиці автоматично видаляються усі рядки дочірньої таблиці, що посилаються на неї. Якщо будь-який з рядків дочірньої таблиці, що видаляються, виступає батьківською стороною в якому-небудь іншому зв'язку, то операція видалення застосовується до усіх рядків дочірньої таблиці цього зв'язку і так далі. Іншими словами, видалення рядка батьківської таблиці автоматично поширюється на будь-які дочірні таблиці.
o SET NULL. При видаленні рядка з батьківської таблиці в усіх рядках дочірнього відношення, що посилаються на неї, в поле зовнішнього ключа, що відповідає первинному ключу видаленого рядка, записується порожнє значення. Отже, видалення рядків з батьківської таблиці викличе занесення порожнього значення у відповідне поле дочірньої таблиці. Ця стратегія може використовуватися, тільки коли в полі зовнішнього ключа дочірньої таблиці дозволяється поміщати порожні значення.
o SET DEFAULT. При видаленні рядка з батьківської таблиці в поле зовнішнього ключа усіх рядків дочірньої таблиці, що посилаються на неї, автоматично поміщається значення, вказане для цього поля як значення за умовчанням. Таким чином, видалення рядка з батьківської таблиці викликає приміщення значення, що набуває за умовчанням, в поле зовнішнього ключа усіх рядків дочірньої таблиці, що посилаються на видалений рядок. Ця стратегія застосовна лише в тих випадках, коли полю зовнішнього ключа дочірньої таблиці призначено деяке значення, що приймається за умовчанням.
o NO CHECK. При видаленні рядка з батьківської таблиці ніяких дій зі збереження посилальної цілісності даних не робиться.
6. Оновлення первинного ключа в рядку батьківської таблиці. Якщо значення первинного ключа деякого рядка батьківської таблиці буде оновлено, порушення посилальної цілісності станеться за тієї умови, що в дочірньому відношенні існують рядки, що посилаються на початкове значення первинного ключа. Для збереження посилальної цілісності може застосовуватися будь-яка з описаних вище стратегій. При використанні стратегії CASCADE оновлення значення первинного ключа в рядку батьківської таблиці буде відображене у будь-якому рядку дочірньої таблиці, що посилається на цей рядок.
Існує і інший вид цілісності - смислова (семантична) цілісність бази даних. Вимога смислової цілісності визначає, що дані у базі даних повинні змінюватися так, щоб не порушувався смисловий зв'язок, що склався між ними.
Рівень підтримки цілісності даних в різних системах істотно варіюється.
Ідеологія архітектури клієнт-сервер вимагає перенесення максимально можливого числа правил цілісності даних на сервер. До переваг такого підходу відносяться:
• гарантія цілісності бази даних, оскільки усі правила зосереджені в одному місці (у базі даних);
• автоматичне застосування визначених на сервері обмежень цілісності для будь-яких застосувань;
• відсутність різних реалізацій обмежень в різних клієнтських застосуваннях, працюючих з базою даних;
• швидке спрацьовування обмежень, оскільки вони реалізовані на сервері і, отже, немає необхідності посилати дані клієнтові, збільшуючи при цьому мережевий трафік;
• доступність внесених в обмеження на сервері змін для усіх клієнтських застосувань, працюючих з базою даних, і відсутність необхідності повторного поширення змінених додатків клієнтів серед користувачів.
До недоліків зберігання обмежень цілісності на сервері можна віднести:
• відсутність у клієнтського додатка можливості реагувати на деякі помилкові ситуації, що виникають на сервері при реалізації тих або інших правил (наприклад, помилок при виконанні процедур, що зберігаються, на сервері);
• обмеженість можливостей мови SQL і мови процедур, що зберігаються, і тригерів для реалізації усіх виникаючих потреб визначення цілісності даних.
На практиці в клієнтських застосуваннях реалізують лише такі правила, які важко або неможливо реалізувати із застосуванням засобів сервера. Усі інші обмеження цілісності даних переносяться на сервер.
При створенні баз даних велика увага має бути приділена засобам підтримки даних в цілісному стані. Розглянемо передбачені стандартом мови SQL функції, які призначені для підтримки цілісності даних. Ця підтримка включає засоби завдання обмежень, вони вводяться з метою захисту бази даних від порушення узгодженості що зберігаються в ній даних. До таких типів підтримки цілісності даних відносяться:
• обов'язкові дані;
• обмеження для доменів полів;
• цілісність сутностей;
• посилальна цілісність ;
• вимоги конкретного підприємства.
Велика частина перерахованих обмежень задається в операторах CREATE TABLE і ALTER TABLE.
Створення таблиці
У стандарті SQL дано декілька варіантів визначення оператора створення таблиці, проте його базовий формат має наступний вигляд:
<визначення_таблиці> ::=
CREATE TABLE ім'я_таблиці
{(ім'я_стовпця тип_даних [ NOT NULL ][ UNIQUE]
[DEFAULT <значення>]
[ CHECK (<умова_вибору>)][,..n]}
[CONSTRAINT ім'я_обмеження]
[PRIMARY KEY (ім'я_стовпця [,..n])
{[UNIQUE (ім'я_стовпця [,..n])}
[FOREIGN KEY (ім'я_стовпця_зовнішнього_ключа
[,..n])
REFERENCES ім'я_рід_таблиці
[(ім'я_стовпця_рід_таблиці [,..n])],
[MATCH {PARTIAL | FULL}]
[ON UPDATE {CASCADE| SET NULL |SET DEFAULT
|NO ACTION}]
[ON DELETE {CASCADE| SET NULL |SET DEFAULT
|NO ACTION}]
{[CHECK(<умова_вибору>)][,..n]})
Обмеження
Представлена версія оператора створення таблиці включає засоби визначення вимог цілісності даних, а також інші конструкції. Є дуже великі варіації в наборі функціональних можливостей цього оператора, реалізованих в різних діалектах мови SQL. Розглянемо призначення параметрів команди, використовуваних для підтримки цілісності даних.
Обов'язкові дані
Для деяких стовпців потрібно наявність в кожному рядку таблиці конкретного і допустимого значення, відмінного від опущеного значення або значення NULL. Для завдань обмежень подібного типу стандарт SQL передбачає використання специфікації NOT NULL.
Вимоги конкретного підприємства
Оновлення даних в таблицях можуть бути обмежені існуючими в організації вимогами (бізнес-правилами). Стандарт SQL дозволяє реалізувати бізнес-правила підприємств за допомогою пропозиції CHECK і ключового слова UNIQUE.
Обмеження для доменів полів
Кожен стовпець має власний домен - деякий набір допустимих значень. Стандарт SQL передбачає два різні механізми визначення доменів. Перший полягає у використанні пропозиції CHECK, що дозволяє задати необхідні обмеження для стовпця або таблиці в цілому, а другою припускає застосування оператора CREATE DOMAIN.
Цілісність сутностей
Первинний ключ таблиці повинен мати унікальне не порожнє значення в кожному рядку. Стандарт SQL дозволяє задавати подібні вимоги підтримки цілісності даних за допомогою фрази PRIMARY KEY. В межах таблиці вона може вказуватися тільки один раз. Проте існує можливість гарантувати унікальність значень і для будь-яких альтернативних ключів таблиці, що забезпечує ключове слово UNIQUE. Крім того, при визначенні альтернативних ключів рекомендується використовувати і специфікатори NOT NULL.
Посилальна цілісність
Зовнішні ключі є стовпцями або наборами стовпців, призначеними для зв'язування кожної з рядків дочірньої таблиці, що містить цей зовнішній ключ, з рядком батьківської таблиці, що містить відповідне значення потенційного ключа. Стандарт SQL передбачає механізм визначення зовнішніх ключів за допомогою пропозиції FOREIGN KEY, а фраза REFERENCES визначає ім'я батьківської таблиці, тобто таблиці, де знаходиться відповідний потенційний ключ. При використанні цієї пропозиції система відхилить виконання будь-яких операторів INSERT або UPDATE, за допомогою яких буде зроблена спроба створити в дочірній таблиці значення зовнішнього ключа, що не відповідає одному із вже існуючих значень потенційного ключа батьківської таблиці. Коли дії системи виконуються при вступі операторів UPDATE і DELETE, що містять спробу відновити або видалити значення потенційного ключа у батьківській таблиці, якому відповідає одна або більше за рядки дочірньої таблиці, то вони залежать від правил підтримки посилальної цілісності, вказаних у фразах ON UPDATE і ON DELETE пропозиції FOREIGN KEY. Якщо користувач робить спробу видалити з батьківської таблиці рядок, на який посилається одна або більше за рядки дочірньої таблиці, мова SQL надає наступні можливості:
• CASCADE - виконується видалення рядка з батьківської таблиці, що супроводжується автоматичним видаленням усіх рядків дочірньої таблиці, що посилаються на неї;
• SET NULL - виконується видалення рядка з батьківської таблиці, а в зовнішні ключі усіх рядків дочірньої таблиці, що посилаються на неї, записується значення NULL ;
• SET DEFAULT - виконується видалення рядка з батьківської таблиці, а в зовнішні ключі усіх рядків дочірньої таблиці, що посилаються на неї, заноситься значення, що приймається за умовчанням;
• NO ACTION - операція видалення рядка з батьківської таблиці відміняється. Саме це значення використовується за умовчанням в тих випадках, коли в описі зовнішнього ключа фраза ON DELETE опущена.
Ті ж самі правила застосовуються в мові SQL і тоді, коли значення потенційного ключа батьківської таблиці оновлюється.
Визначник MATCH дозволяє уточнити спосіб обробки значення NULL в зовнішньому ключі.
При визначенні таблиці пропозиція FOREIGN KEY може вказуватися довільна кількість разів.
У операторові CREATE TABLE використовується необов'язкова фраза DEFAULT, яка призначена для задання по замовчуванні значення, коли в операторі INSERT значення в цьому стовпці буде відсутнє.
Фраза CONSTRAINT дозволяє задати ім'я обмеженню, що дозволить згодом відмінити те або інше обмеження за допомогою оператора ALTER TABLE.
Зміна і видалення таблиці
Для внесення змін до вже створених таблиць стандартом SQL передбачений оператор ALTER TABLE, призначений для виконання наступних дій :
• додавання в таблицю нового стовпця;
• видалення стовпця з таблиці;
• додавання у визначення таблиці нового обмеження;
• видалення з визначення таблиці існуючого обмеження;
• завдання для стовпця значення за умовчанням;
• відміна для стовпця значення за умовчанням.
Оператор зміни таблиці має наступний узагальнений формат:
<зміна_таблиці> ::=
ALTER TABLE ім'я_таблиці
[ADD [COLUMN]ім'я_стовпця тип_даних
[ NOT NULL ][UNIQUE]
[DEFAULT <значення>][ CHECK (<умова_вибору>)]]
[DROP [COLUMN] ім'я_стовпця [RESTRICT | CASCADE ]]
[ADD [CONSTRAINT [ім'я_обмеження]]
[{PRIMARY KEY (ім'я_стовпця [,..n])
|[UNIQUE (ім'я_стовпця [,..n])}
|[FOREIGN KEY (ім'я_стовпця_зовнішнього_ключа [,..n])
REFERENCES ім'я_рід_таблиці
[(ім'я_стовпця_рід_таблиці [,..n])],
[ MATCH {PARTIAL | FULL}
[ON UPDATE {CASCADE| SET NULL |
SET DEFAULT | NO ACTION}]
[ON DELETE {CASCADE| SET NULL |
SET DEFAULT | NO ACTION}]
|[CHECK(<умова_вибору>)][,..n]}]
[DROP CONSTRAINT ім'я_обмеження
[RESTRICT | CASCADE]]
[ALTER [COLUMN] SET DEFAULT <значення>]
[ALTER [COLUMN] DROP DEFAULT]
Тут параметри мають те ж саме призначення, що і у визначенні оператора CREATE TABLE.
Оператор ALTER TABLE реалізований не в усіх діалектах мови SQL. У деяких діалектах він підтримується, проте не дозволяє видаляти з таблиці вже існуючі стовпці.
Для видалення таблиці використовується команда DROP TABLE.
Створення таблиці
В процесі проектування бази даних приймається рішення про те, які таблиці повинні входити у базу даних, які у них будуть імена (ідентифікатори), які типи даних знадобляться для побудови таблиць і які користувачі отримають доступ до кожної з них. Крім того, для ефективного створення таблиць необхідно відповісти на наступні питання:
• Стовпці якого типу і розміру складатимуть кожну з таблиць, які вимагається вибрати імена для стовпців таблиць?
• Які стовпці можуть містити значення NULL?
• Чи будуть використані обмеження цілісності, значення за умовчанням і правила для стовпців?
• Чи потрібне індексування стовпців, які типи індексів будуть застосовані для конкретних стовпців?
• Які стовпці входитимуть в первинні і зовнішні ключі.
Для створення таблиць в середовищі MS SQL Server використовується команда:
<визначення_таблиці> ::=
CREATE TABLE [ ім'я_бази_даних.[власник].
| власник. ]ім'я_таблиці
( (<елемент_таблиці>[,..n])
де
<елемент_таблиці> ::=
{<визначення_стовпця>}
| <ім'я_стовпця> AS <вираження>
| <обмеження_таблиці>
Зазвичай власником таблиці (dbo) є той, хто її створив.
<Вираження> задає значення для обчислюваного стовпця. Обчислювані стовпці - це віртуальні стовпці, т. е. фізично в таблиці вони не зберігаються і обчислюються з використанням значень стовпців тієї ж таблиці. У вираженні для обчислюваного стовпця можуть бути присутніми імена звичайних стовпців, константи і функції, пов'язані одним або декількома операторами. Підзапити в такому вираженні брати участь не можуть. Обчислювані стовпці можуть бути включені в розділ SELECT при вказівці списку стовпців, які мають бути повернені в результаті виконання запиту. Обчислювані стовпці не можуть входити в зовнішній ключ, для них не використовуються значення за умовчанням. Крім того, обчислювані стовпці не можуть брати участь в операціях INSERT і DELETE.
<визначення_стовпця> ::=
{ ім'я_стовпця <тип_даних>}
[ [ DEFAULT <вираження> ]
| [ IDENTITY (початок, крок)[NOT FOR REPLICATION]]]]
[ROWGUIDCOL][<обмеження_стовпця>][..n]]
У визначенні стовпця звернемо увагу на параметр IDENTITY, який вказує, що відповідний стовпець буде стовпцем-лічильником. Для таблиці може бути визначений тільки один стовпець з такою властивістю. Можна додатково вказати початкове значення і крок приросту. Якщо ці значення не вказуються, то за умовчанням вони обоє рівні 1. Якщо з ключовим словом IDENTITY вказане NOT FOR REPLICATION, то сервер не виконуватиме автоматичного генерування значень для цього стовпця, а дозволить вставку в стовпець довільних значень.
В якості обмежень використовуються обмеження стовпця і обмеження таблиці. Відмінність між ними в тому, що обмеження стовпця застосовується тільки до певного поля, а обмеження таблиці - до груп з одного або більше за поля.
<обмеження_стовпця>::=
[ CONSTRAINT ім'я_обмеження ]
{ [ NULL | NOT NULL ]
| [ {PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
[ WITH FILLFACTOR=чинник_заповнення ]
[ ON {ім'я_групи_файлів | DEFAULT } ] ] ]
| [ [ FOREIGN KEY ]
REFERENCES ім'я_рід_таблиці
[(ім'я_стовпця_рід_таблиці) ]
[ ON DELETE { CASCADE | NO ACTION } ]
[ ON UPDATE { CASCADE | NO ACTION } ]
[ NOT FOR REPLICATION ]]
| CHECK [ NOT FOR REPLICATION](<балка_вираження>) }
<обмеження_таблиці>::=
[CONSTRAINT ім'я_обмеження ]
{ [ {PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
{(ім'я_стовпця [ASC | DESC][,..n])}
[WITH FILLFACTOR=чинник_заповнення ]
[ON {ім'я_групи_файлів | DEFAULT } ]]
|FOREIGN KEY[(ім'я_стовпця [,..n])]
REFERENCES ім'я_рід_таблиці
[(ім'я_стовпця_рід_таблиці [,..n])]
[ ON DELETE { CASCADE | NO ACTION } ]
[ ON UPDATE { CASCADE | NO ACTION } ]
| NOT FOR REPLICATION ]
| CHECK [ NOT FOR REPLICATION ] (балка_вираження)}
Розглянемо окремі параметри представлених конструкцій, пов'язані з обмеженнями цілісності даних. Обмеження цілісності мають пріоритет над тригерами, правилами і значеннями за умовчанням. До обмежень цілісності відносяться обмеження первинного ключа PRIMARY KEY, обмеження зовнішнього ключа FOREIGN KEY, обмеження унікальності UNIQUE, обмеження значення NULL, обмеження на перевірку CHECK .
Обмеження первинного ключа (PRIMARY KEY)
Таблиця зазвичай має стовпець або комбінацію стовпців, значення яких унікально ідентифікують кожен рядок в таблиці. Цей стовпець (чи стовпці) називається первісним ключем таблиці і потрібний для забезпечення її цілісності. Якщо в первинний ключ входить більше за один стовпець, то значення в межах одного стовпця можуть дублюватися, але будь-яка комбінація значень усіх стовпців первинного ключа має бути унікальна.
При створенні первинного ключа SQL Server автоматично створює унікальний індекс для стовпців, що входять в первинний ключ. Він прискорює доступ до даних цих стовпців при використанні первинного ключа в запитах.
Таблиця може мати тільки одно обмеження PRIMARY KEY, причому жоден з включених в первинний ключ стовпців не може набувати значення NULL. При спробі використовувати як первинний ключ стовпець (чи групу стовпців), для якого обмеження первинного ключа не виконуються, первинний ключ створений не буде, а система видасть повідомлення про помилку.
Оскільки обмеження PRIMARY KEY гарантує унікальність даних, воно часто визначається для стовпців-лічильників. Створення обмеження цілісності PRIMARY KEY можливо як при створенні, так і при зміні таблиці. Одним з призначень первинного ключа є забезпечення посилальної цілісності даних декількох таблиць. Природно, це може бути реалізовано тільки при визначенні відповідних зовнішніх ключів в інших таблицях.
Обмеження зовнішнього ключа (FOREIGN KEY)
Обмеження зовнішнього ключа - це основний механізм для підтримки посилальної цілісності між таблицями реляційної бази даних. Стовпець дочірньої таблиці, визначений в якості зовнішнього ключа в параметрі FOREIGN KEY, застосовується для посилання на стовпець батьківської таблиці, що є в ній первинним ключем. Ім'я батьківської таблиці і стовпці її первинного ключа вказуються в пропозиції REFERENCES. Дані в стовпцях, визначених в якості зовнішнього ключа, можуть приймати тільки такі ж значення, які знаходяться в пов'язаних з ним стовпцях первинного ключа батьківської таблиці. Збіг імен стовпців для зв'язку дочірньої і батьківської таблиць необов'язково. Первинний ключ може бути визначений для стовпця з одним ім'ям, тоді як стовпець, на який накладено обмеження FOREIGN KEY, може мати абсолютно інше ім'я. Єдиною вимогою залишається відповідність стовпців за типом і розміром даних.
На первинний ключ можуть посилатися не лише стовпці інших таблиць, але і стовпці, розташовані в тій же таблиці, що і власне первинний ключ ; це дозволяє створювати рекурсивні структури.
Зовнішній ключ може бути пов'язаний не лише з первинним ключем іншої таблиці. Він може бути визначений і для стовпців з обмеженням UNIQUE другої таблиці або будь-яких інших стовпців, але таблиці повинні знаходитися в одній базі даних.
Стовпці зовнішнього ключа можуть містити значення NULL, проте перевірка на обмеження FOREIGN KEY ігнорується. Зовнішній ключ може бути проіндексований, тоді сервер швидше відшукуватиме потрібні дані. Зовнішній ключ визначається як при створенні, так і при зміні таблиць.
Обмеження посилальної цілісності задає вимогу, згідно з якою для кожного запису в дочірній таблиці має бути запис у батьківській таблиці. При цьому зміна значення стовпця зв'язку в записі батьківської таблиці за наявності дочірнього запису блокується, так само як і видалення батьківського запису (заборона каскадної зміни і видалення), що гарантується параметрами ON DELETE NO ACTION і ON UPDATE NO ACTION, прийнятими за умовчанням. Для дозволу каскадної дії слід використовувати параметри ON DELETE CASCADE і ON UPDATE CASCADE.
Обмеження унікального ключа (UNIQUE)
Це обмеження задає вимогу унікальності значення поля (стовпця) або групи полів (стовпців), що входять в унікальний ключ, по відношенню до інших записів. Обмеження UNIQUE для стовпця таблиці схоже на первинний ключ: для кожного рядка даних в нім повинні міститися унікальні значення. Встановивши для деякого стовпця обмеження первинного ключа, можна одночасно встановити для іншого стовпця обмеження UNIQUE. Відмінність в обмеженні первинного і унікального ключа полягає в тому, що первинний ключ служить як для впорядкування даних в таблиці, так і для з'єднання пов'язаних між собою таблиць. Крім того, при використанні обмеження UNIQUE допускається існування значення NULL, але лише єдиний раз.
Обмеження на значення (NOT NULL)
Для кожного стовпця таблиці можна встановити обмеження NOT NULL, що забороняє введення в цей стовпець нульового значення.
Обмеження перевірочне (CHECK) і правила
Це обмеження використовується для перевірки допустимості даних, що вводяться в конкретний стовпець таблиці, тобто обмеження CHECK забезпечує ще один рівень захисту даних.
Обмеження цілісності CHECK задають діапазон можливих значень для стовпця або стовпців. У основі обмежень цілісності CHECK лежить використання логічних виразів.
Допускається застосування декількох обмежень CHECK до одного і тому ж стовпця. В цьому випадку вони будуть застосовні в тій послідовності, в якій відбувалося їх створення. Можливе застосування одного і того ж обмеження до різних стовпців і використання в логічних виразах значень інших стовпців. Вказівка параметра NOT FOR REPLICATION наказує не виконувати перевірочних дій, якщо вони виконуються підсистемою реплікації.
Перевірочні обмеження можуть бути реалізовані і за допомогою правил. Правило є самостійним об'єктом бази даних, який зв'язується із стовпцем таблиці або призначеним для користувача типом даних. Причому одно і те ж правило може бути одночасно пов'язане з декількома стовпцями і призначеними для користувача типами даних, що є безперечною перевагою. Проте істотний недолік полягає в тому, що з кожним стовпцем або типом даних може бути пов'язано тільки одне правило. Дозволяється комбінування обмежень цілісності CHECK з правилами. В цьому випадку виконується перевірка відповідності значення, що вводиться, як обмеженням цілісності, так і правилам.
Правило може бути створене командою:
CREATE RULE ім'я_правила AS вираження
Щоб зв'язати правило з тим або іншим стовпцем якої-небудь таблиці, необхідно використовувати системну процедуру, що зберігається :
sp_bindrule [@rulename=] 'rule'
[@objname=] 'object_name'
[,[@futureonly=['futureonly_flag']
Щоб відмінити правила, слід виконати наступну процедуру:
sp_unbindrule [@objname=] 'object_name'
[,[@futureonly=['futureonly_flag']
Видалення правила робиться командою
DROP RULE {ім'я_правила} [,..n].
Обмеження за умовчанням (DEFAULT)
Стовпцю може бути присвоєне значення за умовчанням. Воно буде актуальним у тому випадку, якщо користувач не введе в стовпець ніякого іншого значення.
Окремо необхідно відмітити користь від використання значень за умовчанням при додаванні нового стовпця в таблицю. Якщо для стовпця, що додається, не дозволено зберігання значень NULL і не визначено значення за умовчанням, то операція додавання стовпця закінчиться невдачею.
При визначенні в таблиці стовпця з параметром ROWGUIDCOL сервер автоматично визначає для нього значення за умовчанням у вигляді функції NEWID(). Таким чином, для кожного нового рядка автоматично генеруватиметься глобальний унікальний ідентифікатор.
Додатковим механізмом використання значень за умовчанням є об'єкти бази даних, створені командою:
CREATE DEFAULT ім'я_умовчання AS константа
Умовчання зв'язується з тим або іншим стовпцем якої-небудь таблиці за допомогою процедури:
sp_bindefault [@defname=] 'default
[@objname=] 'object_name'
[,[@futureonly=] 'futureonly_flag']
де
''object_name'
може бути представлений як
''ім'я_таблиці.ім'я_стовпця'
Видалення обмеження за умовчанням виконується командою
DROP DEFAULT {ім'я_умовчання} [,..n]
якщо заздалегідь це обмеження було видалене з усіх таблиць процедурою
sp_unbindefault [@objname=] 'object_name'
[,[@futureonly=] 'futureonly_flag']
При створенні таблиці, окрім розглянутих прийомів, можна вказати необов'язкове ключове слово CONSTRAINT, щоб присвоїти обмеженню ім'я, унікальне в межах бази даних.
Ключові слова CLUSTERED і NONCLUSTERED дозволяють створити для стовпця кластерний або некластерний індекс. Для обмеження PRIMARY KEY за умовчанням створюється кластерний індекс, а для обмеження UNIQUE - некластерний. У кожній таблиці може бути створений лише один кластерний індекс, відмітною особливістю якого є те, що відповідно до нього змінюється фізичний порядок рядків в таблиці. ASC і DESC визначають метод впорядкування даних в індексі.
За допомогою параметра WITH FILLFACTOR=чинник_заповнення задається міра заповнення індексних сторінок при створенні індексу. Значення чинника заповнення вказується у відсотках і може змінюватися в проміжку від 0 до 100.
Параметр ON ім'я_групи_файлів означає групу, в якій передбачається зберігати таблицю.
Зміна таблиці
Зміни в таблицю можна внести командою:
<зміна_таблиці> ::=
ALTER TABLE ім'я_таблиці
{[ALTER COLUMN ім'я_стовпця
{ тип_даних [(точність[,масштаб])]
[ NULL | NOT NULL ]
| {ADD | DROP } ROWGUIDCOL }]
| ADD { [<визначення_стовпця>]
| ім'я_стовпця AS вираження } [,..n]
| [WITH CHECK | WITH NOCHECK ]
ADD { <обмеження-таблиці> } [,..n]
| DROP
{ [CONSTRAINT ] ім'я_обмеження
| COLUMN ім'я_стовпця}[,..n]
| {CHECK | NOCHECK } CONSTRAINT
{ALL | ім'я_обмеження[,..n]}
| {ENABLE | DISABLE } TRIGGER
{ALL | ім'я_тригера [,..n]}}
На додаток до вже названих параметрів визначимо параметр {ENABLE | DISABLE } TRIGGER ALL, приписуючий задіювати або відключити конкретний тригер або усі тригера, пов'язані з таблицею.
Видалення таблиці
Видалення таблиці виконується командою:
DROP TABLE ім'я_таблиці
Видалити можна будь-яку таблицю, навіть системну. До цього питання треба підходити дуже обережно. Проте видаленню не підлягають таблиці, якщо існують об'єкти, що посилаються на них. До таких об'єктів відносяться таблиці, пов'язані з таблицею, що видаляється, за допомогою зовнішнього ключа. Тому, перш ніж видаляти батьківську таблицю, необхідно видалити або обмеження зовнішнього ключа, або дочірні таблиці. Якщо з таблицею пов'язано хоч би одно представлення, то таблицю також видалити не вдасться. Крім того, зв'язок з таблицею може бути встановлений з боку функцій і процедур. Отже, перед видаленням таблиці необхідно видалити усі об'єкти бази даних, які на неї посилаються, або змінити їх так, щоб посилань на таблицю, що видаляється, не було.
CREATE TABLE Товар
((КодТовару INT IDENTITY(1,1) PRIMARY KEY
Назва VARCHAR(50) NOT NULL UNIQUE
Ціна MONEY NOT NULL
Тип VARCHAR(50) NOT NULL
Сорт VARCHAR(50) NOT NULL
CHECK(сорт in('перший','другий','третій'))
Місто VARCHAR(50) NOT NULL
Залишок INT
CHECK(залишок>=0))
Приклад 9.1. Створення батьківської таблиці Товар з обмеженнями.
CREATE TABLE Клієнт
((КодКлієнта INT IDENTITY(1,1) PRIMARY KEY
Фірма VARCHAR(50) NOT NULL
Прізвище VARCHAR(50) NOT NULL
Місто VARCHAR(50) NOT NULL
Телефон CHAR(10) NOT NULL
CHECK(Телефон LIKE
' '[1-9][0-9]-[0-9][0-9]-[0-9][0-9]'))
Приклад 9.2. Створення батьківської таблиці Клієнт з обмеженнями.
CREATE TABLE Угода
((КодУгоди INT IDENTITY(1,1) PRIMARY KEY
КодТовару INT NOT NULL
КодКлієнта INT NOT NULL,
Кількість INT NOT NULL DEFAULT 0
Дата DATETIME NOT NULL DEFAULT
GETDATE()
CONSTRAINT fk_Товар
FOREIGN KEY(КодТовару) REFERENCES Товар
CONSTRAINT fk_Клієнт
FOREIGN KEY(КодКлієнта) REFERENCES Клієнт)
Приклад 9.3. Створення дочірньої таблиці Угода з обмеженнями.
CREATE TABLE Склад
((КодТовару INT PRIMARY KEY
Залишок INT)
Приклад 9.4. Створення таблиці Склад.
ALTER TABLE Угода DROP CONSTRAINT fk_Товар
Приклад 9.5. Видалення обмеження зовнішнього ключа.
ALTER TABLE Угода ADD CONSTRAINT fk_Товар
FOREIGN KEY (КодТовару) REFERENCES товар
ON UPDATE NO ACTION ON DELETE NO ACTION
Приклад 9.6. Додавання обмеження зовнішнього ключа, що реалізовує декларативну посилальну цілісність.
ALTER TABLE Угода ADD CONSTRAINT fk_Товар
FOREIGN KEY (КодТовару) REFERENCES Товар
ON UPDATE CASCADE ON DELETE CASCADE
Приклад 9.7. Додавання обмеження зовнішнього ключа, що реалізовує каскадні оновлення і зміни.
ALTER TABLE Товар ADD Податок AS Ціна*0.05
ALTER TABLE Товар DROP COLUMN Податок
Приклад 9.8. Приклад створення і видалення обчислюваного поля.
Нехай створена таблиця без обмежень:
CREATE TABLE Товар
((КодТовару INT
Назва VARCHAR(20)
Тип VARCHAR(20)
Дата DATETIME
Ціна MONEY
Залишок INT)
Розглянемо приклади внесення в таблицю всіляких обмежень.
Приклад 9.9. Поле КодТовару необхідно зробити первинним ключем. Виконання наступної команди буде знехтувано, оскільки поле КодТовару допускає внесення значень NULL.
ALTER TABLE Товар ADD CONSTRAINT pk1
PRIMARY KEY(КодТовару)
Приклад 9.9. Поле КодТовару необхідно зробити первинним ключем.
Спочатку треба змінити оголошення стовпця КодТовару, заборонивши внесення значень NULL :
ALTER TABLE Товар
ALTER COLUMN КодТовару INT NOT NULL
І тільки потім створити обмеження первинного ключа :
ALTER TABLE Товар ADD CONSTRAINT pk1
PRIMARY KEY(КодТовару)
Приклад 9.10. Видалити стовпець цілого типу і додати стовпець-лічильник.
ALTER TABLE Товар DROP COLUMN КодТовару
ALTER TABLE Товар ADD
КодТовару INT IDENTITY(1,1)
Приклад 9.10. Видалення стовпця цілого типу і додавання стовпця-лічильника.
Приклад 9.11. Додати обмеження первинного ключа.
ALTER TABLE Товар ADD CONSTRAINT pk1
PRIMARY KEY(КодТовару)
Приклад 9.11. Додавання обмежень первинного ключа.
Приклад 9.12. Змінити стовпець, додавши обмеження NOT NULL.
ALTER TABLE Товар ALTER COLUMN
Назва VARCHAR(40) NOT NULL
Приклад 9.12. Додавання обмеження NOT NULL.
Приклад 9.13. Додати обмеження унікальності значення.
ALTER TABLE Товар ADD CONSTRAINT
u1 UNIQUE(Назва)
Приклад 9.13. Додавання обмеження унікальності значення.
Приклад 9.14. Створити умовчання і додати умовчання стовпцю.
CREATE DEFAULT df1 AS 0
sp_bindefault 'df1 ', 'Товар.Залишок'
CREATE DEFAULT df2 AS GETDATE()
sp_bindefault 'df2 ', 'Товар.Дата'
Приклад 9.14. Створення і додавання умовчання стовпцю.
Приклад 9.15. Створити правило і додати правило стовпцю.
CREATE RULE r1 AS @m IN
(' ('меблі','побутова хімія','косметика')
sp_bindrule 'r1 ','Товар.Тип'
Приклад 9.15. Створення і додавання правила стовпцю.
Представлення, або перегляди ( VIEW ), є тимчасовими, похідними (інакше - віртуальні) таблицями і є об'єктами бази даних, інформація в яких не зберігається постійно, як у базових таблицях, а формується динамічно при зверненні до них. Звичайні таблиці відносяться до базових, тобто що містить дані і постійно знаходиться на пристрої зберігання інформації. Представлення не може існувати само по собі, а визначається тільки в термінах однієї або декількох таблиць. Застосування представлень дозволяє розробникові бази даних забезпечити кожному користувачеві або групі користувачів найбільш відповідні способи роботи з даними, що вирішує проблему простоти їх використання і безпеки. Вміст представлень вибирається з інших таблиць за допомогою виконання запиту, причому при зміні значень в таблицях дані в представленні автоматично міняються. Представлення - це фактично той же запит, який виконується всякий раз при участі в якій-небудь команді. Результат виконання цього запиту в кожен момент часу стає змістом представлення. У користувача створюється враження, що він працює із справжньою, реально існуючою таблицею.
У СУБД є дві можливості реалізації представлень. Якщо його визначення просте, то система формує кожен запис представлення в міру необхідності, поступово прочитуючи початкові дані з базових таблиць. У разі складного визначення СУБД доводиться спочатку виконати таку операцію, як матеріалізація представлення, тобто зберегти інформацію, з якої складається представлення, в тимчасовій таблиці. Потім система приступає до виконання призначеної для користувача команди і формування її результатів, після чого тимчасова таблиця віддаляється.
Представлення - це зумовлений запит, що зберігається у базі даних, який виглядає подібно до звичайної таблиці і не вимагає для свого зберігання дискової пам'яті. Для зберігання представлення використовується тільки оперативна пам'ять. На відміну від інших об'єктів бази даних представлення не займає дискової пам'яті за винятком пам'яті, необхідної для зберігання визначення самого представлення.
Створення і зміни представлень в стандарті мови і реалізації в MS SQL Server співпадають і представлені наступною командою:
<визначення_представлення> ::=
{ CREATE| ALTER} VIEW ім'я_представлення
[(ім'я_стовпця [,..n])]
[WITH ENCRYPTION]
AS SELECT_оператор
[WITH CHECK OPTION]
Розглянемо призначення основних параметрів.
За умовчанням імена стовпців в представленні відповідають іменам стовпців в початкових таблицях. Явну вказівку імені стовпця потрібно для обчислюваних стовпців або при об'єднанні декількох таблиць, що мають стовпці з однаковими іменами. Імена стовпців перераховуються через кому, відповідно до порядку їх дотримання в представленні.
Параметр WITH ENCRYPTION наказує серверу шифрувати SQL -код запиту, що гарантує неможливість його несанкціонованого перегляду і використання. Якщо при визначенні представлення необхідно приховати імена початкових таблиць і стовпців, а також алгоритм об'єднання даних, необхідно застосувати цей аргумент.
Параметр WITH CHECK OPTION наказує серверу виконувати перевірку змін, вироблюваних через представлення, на відповідність критеріям, визначеним в операторові SELECT. Це означає, що не допускається виконання змін, які приведуть до зникнення рядка з представлення. Таке трапляється, якщо для представлення встановлений горизонтальний фільтр і зміна даних призводить до невідповідності рядка встановленим фільтрам. Використання аргументу WITH CHECK OPTION гарантує, що зроблені зміни будуть відображені в представленні. Якщо користувач намагається виконати зміни, що призводять до виключення рядка із представлення, при заданому аргументі WITH CHECK OPTION сервер видасть повідомлення про помилку і усі зміни будуть відхилені.
Приклад 10.1. Показати в представленні клієнтів з Києва.
Створення представлення :
CREATE VIEW view1 AS
SELECT КодКлієнта, Прізвище, МістоКлієнта
FROM Клієнт
WHERE МістоКлієнта='Київ'
Приклад 10.1. Представлення клієнтів з Києва.
Вибірка даних з представлення:
SELECT * FROM view1
Звернення до представлення здійснюється за допомогою оператора SELECT як до звичайної таблиці.
Представлення можна використовувати в команді так само, як і будь-яку іншу таблицю. До представлення можна будувати запит, модифікувати його (якщо воно відповідає певним вимогам), сполучати з іншими таблицями. Зміст представлення не фіксований і оновлюється кожного разу, коли на нього посилаються в команді. Представлення значно розширюють можливості управління даними. Зокрема, це прекрасний спосіб дозволити доступ до інформації в таблиці, приховавши частину даних.
Так, в прикладі 10.1 представлення просто обмежує доступ користувача до даних таблиці Клієнт, дозволяючи бачити тільки частину значень.
Виконаємо команду:
INSERT INTO view1 VALUES (12,'Петров', 'Чернігів')
Це допустима команда в представленні, і рядок буде доданий за допомогою представлення view1 в таблицю Клієнт. Проте, коли інформація буде додана, рядок зникне з представлення, оскільки назва міста відмінна від Києва. Іноді такий підхід може стати проблемою, оскільки дані вже знаходяться в таблиці, але користувач їх не бачить і не в змозі виконати їх видалення або модифікацію. Для виключення подібних моментів служить WITH CHECK OPTION у визначенні представлення. Фраза розміщується у визначенні представлення, і усі команди модифікації піддаватимуться перевірці.
ALTER VIEW view1
SELECT КодКлієнта, Прізвище, МістоКлієнта
FROM Клієнт
WHERE МістоКлієнта='Київ'
WITH CHECK OPTION
Приклад 10.2. Створення представлення з перевіркою команд модифікації.
Для такого представлення вищезгадана вставка значень буде відхилена системою.
Таким чином, представлення може змінюватися командами модифікації DML, але фактично модифікація впливає не на само представлення, а на базову таблицю.
Представлення віддаляється командою:
DROP VIEW ім'я_представлення [,..n]
Не усі представлення в SQL можуть бути модифіковані. Представлення, що модифікується, визначається наступними критеріями:
• грунтується тільки на одній базовій таблиці;
• містить первинний ключ цієї таблиці;
• не містить DISTINCT у своєму визначенні;
• не використовує GROUP BY або HAVING у своєму визначенні;
• по можливості не застосовує у своєму визначенні підзапити;
• не використовує константи або вираження значень серед вибраних полів виводу;
• у перегляд має бути включений кожен стовпець таблиці, атрибут NOT NULL, що має ;
• оператор SELECT перегляду не використовує агрегуючі (підсумкові) функції, з'єднання таблиць, Збережені процедури, і функції, визначені користувачем;
• грунтується на поодинокому запиті, тому об'єднання UNION не дозволене.
Якщо перегляд задовольняє цим умовам, до нього можуть застосовуватися оператори INSERT, UPDATE, DELETE. Відмінності між представленнями і представленнями, призначеними тільки для читання, що модифікуються, не випадкові. Цілі, для яких їх використовують, різні. З представленнями, що модифікуються, в основному обходяться точно так, як і з базовими таблицями. Фактично, користувачі не можуть навіть усвідомити, чи являється об'єкт, який вони просять, базовою таблицею або представленням, тобто передусім цей засіб захисту для приховання конфіденційних або таких, що не відносяться до потреб цього користувача частин таблиці. Представлення в режимі <тільки для читання> дозволяють отримувати і форматувати дані раціональніше. Вони створюють цілий арсенал складних запитів, які можна виконати і повторити знову, зберігаючи отриману інформацію. Результати цих запитів можуть потім використовуватися в інших запитах, що дозволить уникнути складних предикатів і понизити вірогідність помилкових дій.
CREATE VIEW view2 AS
SELECT Клієнт.Прізвище, Клієнт.Фірма,
Угода.Кількість
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта
Приклад 10.3. представлення, що не модифікується, з даними з різних таблиць.
CREATE VIEW view3(Тип, Заг_залишок) AS
SELECT Тип, Sum(Залишок)
FROM Товар
GROUP BY Тип
Приклад 10.4. представлення, що Не модифікується, з угрупуванням і підсумковими функціями.
Зазвичай в представленнях використовуються імена, отримані безпосередньо з імен полів основної таблиці. Проте іноді необхідно дати стовпцям нові імена, наприклад, у разі підсумкових функцій або обчислюваних стовпців.
CREATE VIEW view4(Код, Назва,
Тип, Ціна, Податок) AS
SELECT КодТовару, Назва,
Тип, Ціна, Ціна*0.05 FROM Товар
Приклад 10.5. Представлення, що модифікується, з обчисленнями.
Механізм представлення - потужний засіб СУБД, що дозволяє приховати реальну структуру БД від деяких користувачів за рахунок визначення представлень. Будь-яка реалізація представлення повинна гарантувати, що стан відношення, що представляється, точно відповідає стану даних, на яких визначено це представлення. Звичайне обчислення представлення робиться кожного разу при його використанні. Коли представлення створюється, інформація про нього записується в каталог БД під власним ім'ям. Будь-які зміни в даних адекватно відобразяться в представленні - в цьому його відмінність від дуже схожого на нього запиту до БД. В той же час запит є як би <миттєвою фотографією> даних і при зміні останніх запит до БД необхідно повторити. Наявність представлень у БД потрібна для забезпечення логічної незалежності даних. Якщо система забезпечує фізичну незалежність даних, то зміни у фізичній структурі БД не впливають на роботу призначених для користувача програм. Логічна незалежність має на увазі той факт, що при зміні логічної структури даних вплив на призначені для користувача програми також не виявляється, а значить, система повинна уміти вирішувати проблеми, пов'язані з ростом і реструктуризацією БД. Очевидно, що зі збільшенням кількості даних, що зберігаються у БД, виникає необхідність її розширення за рахунок додавання нових атрибутів або стосунків - це називається ростом БД. Реструктуризація даних має на увазі збереження тієї ж самої інформації, але змінюється її розташування, наприклад, за рахунок перегрупування атрибутів в стосунках. Припустимо, деяке відношення через які-небудь причини необхідно розділити на два. З'єднання отриманих стосунків в представленні відтворює початкове відношення, а у користувача складається враження, що ніякої реструктуризації не робилася. Окрім вирішення проблеми реструктуризації представлення можна застосовувати для перегляду одних і тих же даних різними користувачами і в різних варіантах. За допомогою представлень користувач має можливість обмежити об'єм даних для зручності роботи. Нарешті, механізм уявлень дозволяє приховати службові дані, не цікаві користувачам.
У разі виконання СУБД на персональному комп'ютері, що окремо стоїть, використання представлень зазвичай має на меті лише спрощення структури запитів до бази даних. Проте у разі розрахованої на багато користувачів мережевої СУБД представлення грають ключову роль у визначенні структури бази даних і організації захисту інформації. Розглянемо основні переваги застосування представлень в подібному середовищі.
Незалежність від даних
За допомогою представлень можна створити погоджену, незмінну картину структури бази даних, яка залишатиметься стабільною навіть у разі зміни формату початкових таблиць (наприклад, додавання або видалення стовпців, зміни зв'язків, розподілу таблиць, їх реструктуризації або перейменування). Якщо в таблицю додаються або з неї видаляються не використовувані в представленні стовпці, то змінювати визначення цього представлення не потрібно буде. Якщо структура початкової таблиці переупорядковується або таблиця розділяється, можна створити представлення, що дозволяє працювати з віртуальною таблицею колишнього формату. У разі розподілу початкової таблиці, колишній формат може бути віртуально відтворений за допомогою представлення, побудованого на основі з'єднання знову створених таблиць, - звичайно, якщо це виявиться можливим. Останню умову можна забезпечити за допомогою приміщення в усі знову створені таблиці первинного ключа колишньої таблиці.
Актуальність
Зміни даних у будь-якій з таблиць бази даних, вказаних у визначальному запиті, негайно відображається на вмісті представлення.
Підвищення захищеності даних
Права доступу до даних можуть бути надані виключно через обмежений набір представлень, що містять тільки ту підмножину даних, яка потрібна користувачеві. Подібний підхід дозволяє істотно посилити контроль за доступом окремих категорій користувачів до інформації у базі даних.
Зниження вартості
Представлення дозволяють спростити структуру запитів за рахунок об'єднання даних з декількох таблиць в єдину віртуальну таблицю. В результаті багатотабличні запити зводяться до простих запитів до одного представлення.
Додаткові зручності
Створення представлень може забезпечувати користувачів додатковими зручностями - наприклад, можливістю роботи тільки з дійсно потрібною частиною даних. В результаті можна добитися максимального спрощення тієї моделі даних, яка знадобиться кожному кінцевому користувачеві.
Можливість налаштування
Представлення є зручним засобом налаштування індивідуального образу бази даних. В результаті одні і ті ж таблиці можуть бути пред'явлені користувачам в абсолютно різному виді.
Забезпечення цілісності даних
Якщо в операторові CREATE VIEW буде вказана фраза WITH CHECK OPTION, то СУБД стане здійснювати контроль за тим, щоб в початкові таблиці бази даних не була введена жоден з рядків, що не задовольняють пропозиції WHERE у визначальному запиті. Цей механізм гарантує цілісність даних в представленні.
Практика обмеження доступу деяких користувачів до даних за допомогою створення спеціалізованих представлень, безумовно, має значні переваги перед наданням їм прямого доступу до таблиць бази даних.
Проте використання представлень в середовищі SQL не позбавлене недоліків.
Обмежені можливості оновлення
В деяких випадках представлення не дозволяють вносити зміни в ті, що містяться в них дані.
Структурні обмеження
Структура представлення встановлюється у момент його створення. Якщо визначальний запит представлений у формі SELECT * FROM_, то символ * посилається на усі стовпці, існуючі в початковій таблиці на момент створення представлення. Якщо згодом в початкову таблицю бази даних додадуться нові стовпці, то вони не з'являться в цьому представленні до тих пір, поки це представлення не буде видалено і знову створене.
Зниження продуктивності
Використання представлень пов'язане з певним зниженням продуктивності. У одних випадках вплив цього чинника абсолютно трохи, тоді як в інших воно може послужити джерелом істотних проблем. Наприклад, представлення, визначене за допомогою складного багатотабличного запиту, може зажадати значних витрат часу на обробку, оскільки при його дозволі потрібно буде виконувати з'єднання таблиць всякий раз, коли знадобиться доступ до даного представлення. Виконання дозволу представлень пов'язане з використанням додаткових обчислювальних ресурсів.
При реалізації на мові SQL складних алгоритмів, які можуть знадобитися більше одного разу, відразу постає питання про збереження розробленого коду для подальшого застосування. Цю задачу можна було б реалізувати за допомогою збережених процедур , однак їх архітектура не дозволяє використовувати процедури безпосередньо у виразах, тому вони вимагають проміжного присвоєння повернутого значення змінної, яка потім і вказується в вираженні. Природно, подібний метод застосування програмного коду не дуже зручний. Багато розробники вже давно хотіли мати можливість виклику розроблених алгоритмів безпосередньо в виразах.
Можливість створення призначених для користувача функцій була надана в середовищі MS SQL Server 2000. В інших реалізаціях SQL в розпорядженні користувача є тільки вбудовані функції , які забезпечують виконання найбільш поширених алгоритмів: пошук максимального чи мінімального значення і ін
Функції користувача являють собою самостійні об'єкти бази даних, такі, наприклад, як збережені процедури або тригери. Функція користувача розташовується в певній базі даних і доступна тільки в її контексті.
У SQL Server є наступні класи функцій користувача :
• Scalar - функції повертають звичайне скалярний значення, кожна може включати безліч команд, що об'єднуються в один блок за допомогою конструкції BEGIN ... END;
• Inline - функції містять всього одну команду SELECT і повертають користувачеві набір даних у вигляді значення типу даних TABLE ;
• Multi-statement - функції також повертають користувачеві значення типу даних TABLE , що містить набір даних, проте в тілі функції знаходиться безліч команд SQL ( INSERT , UPDATE і т.д.). Саме з їх допомогою і формується набір даних, який має бути повернуто після виконання функції .
Користувальницькі функції схожі з збереженими процедурами , але, на відміну від них, можуть застосовуватися в запитах так само, як і системні вбудовані функції . Користувальницькі функції , що повертають таблиці, можуть стати альтернативою переглядам. Перегляди обмежені одним виразом SELECT , а користувальницькі функції здатні включати додаткові вирази, що дозволяє створювати більш складні і потужні конструкції.
Створення та зміна функції даного типу виконується за допомогою команди:
<Визначення_скаляр_функціі> :: =
{CREATE | ALTER} FUNCTION [власник.]
імя_функції
([{@ імя_параметра скаляр_тип_даних
[= default]} [, ... n]])
RETURNS скаляр_тип_даних
[WITH {ENCRYPTION | SCHEMABINDING}
[, .. . n]]
[AS]
BEGIN
<тіло_функціі>
RETURN скаляр_вираз
END
Розглянемо призначення параметрів команди.
Функція може містити один або декілька вхідних параметрів або не містити жодного. Кожен параметр повинен мати унікальне в межах створюваної функції ім'я і починатися з символу " @ ". Після імені вказується тип даних параметра. Додатково можна вказати значення, яке буде автоматично присвоюватися параметру ( DEFAULT ), якщо користувач явно не вказав значення відповідного параметра при виклику функції .
За допомогою конструкції RETURNS скаляр_тип_даних вказується, який тип даних буде мати повертане функцією значення.
Додаткові параметри, з якими повинна бути створена функція , можуть бути зазначені за допомогою ключового слова WITH . Завдяки ключовим словом ENCRYPTION код команди, використовуваний для створення функції , буде зашифровано, і ніхто не зможе переглянути його. Ця можливість дозволяє приховати логіку роботи функції . Крім того, в тілі функції може виконуватися звернення до різних об'єктів бази даних, а тому зміна або видалення відповідних об'єктів може призвести до порушення роботи функції . Щоб уникнути цього, потрібно заборонити внесення змін, вказавши при створенні цієї функції ключове слово SCHEMABINDING .
Між ключовими словами BEGIN ... END вказується набір команд, вони й будуть тілом функції .
Коли в ході виконання коду функції зустрічається ключове слово RETURN , виконання функції завершується і як результат її обчислення повертається значення, вказане безпосередньо після слова RETURN . Відзначимо, що в тілі функції дозволяється використання безлічі команд RETURN , які можуть повертати різні значення. В якості значення, що повертається допускаються як звичайні константи, так і складні вирази. Єдина умова - тип даних значення, що повертається повинен збігатися з типом даних, зазначених після ключового слова RETURNS .
Приклад 11.1 . Створити і застосувати функцію скалярного типу для обчислення сумарної кількості товару, що надійшов за певну дату. Власник функції - користувач з ім'ям user1 .
CREATE FUNCTION
user1.sales (@ data DATETIME)
Returns INT
AS
BEGIN
DECLARE @ C INT
SET @ c = (SELECT SUM (кількість)
FROM Угода
WHERE дата = @ data)
RETURN (@ c)
END
Приклад 11.1. Створення функції скалярного типу для обчислення сумарної кількості товару, що надійшов за певну дату.
В якості вхідного параметра використовується дата. Функція повертає значення цілого типу, отримане з оператора SELECT шляхом підсумовування кількості товару з таблиці Угода . Умовою відбору записів для підсумовування є рівність дати угоди значенню вхідного параметра функції .
Проілюструємо звернення до функції користувача : визначимо кількість товару, що надійшов за 02.11.01:
DECLARE @ Kіl INT
SET @ kіl = user1.sales ('02 .11.01 ')
SELECT @ kіl
Створення та зміна функції цього типу виконується за допомогою команди:
<Визначен_табл_функціі> :: =
{CREATE | ALTER} FUNCTION [власник.]
імя_функції
([{@ імя_параметра скаляр_тип_даних
[= default]} [, ... n]])
RETURNS TABLE
[WITH {ENCRYPTION | SCHEMABINDING}
[, .. . n]]
[AS]
RETURN [(] SELECT_оператор [)]
Основна частина параметрів, використовуваних при створенні табличних функцій , аналогічна параметрам скалярної функції . Проте створення табличних функцій має свою специфіку.
Після ключового слова RETURNS завжди повинно вказуватися ключове слово TABLE . Таким чином, функція даного типу повинна строго повертати значення типу даних TABLE . Структура значення, що повертається типу TABLE не вказується явно при описі власне типу даних. Замість цього сервер буде автоматично використовувати для значення, що повертається TABLE структуру, повертану запитом SELECT , який є єдиною командою функції .
Особливість функції даного типу полягає в тому, що структура значення TABLE створюється автоматично в ході виконання запиту, а не вказується явно при визначенні типу після ключового слова RETURNS .
Повертане функцією значення типу TABLE може бути використано безпосередньо у запиті, тобто в розділі FROM .
Приклад 11.2 . Створити і застосувати функцію табличного типу для визначення двох найменувань товару з найбільшим залишком.
CREATE FUNCTION user1.itog ()
Returns TABLE
AS
RETURN (SELECT TOP 2 Товар.Назва
FROM Товар INNER JOIN Склад
ON Товар.КодТовару = Склад.КодТовару
ORDER BY Склад.Залишок DESC)
Приклад 11.2. Створення функції табличного типу для визначення двох найменувань товару з найбільшим залишком.
Використовувати функцію для отримання двох найменувань товару з найбільшим залишком можна наступним чином:
SELECT Назва
FROM user1.itog ()
Створення та зміна функцій типу Multi-statement виконується за допомогою наступної команди:
<Визначення_мульти_функціі> :: =
{CREATE | ALTER} FUNCTION [власник.]
імя_функції
([{@ імя_параметра скаляр_тип_даних
[= default]} [, ... n]])
RETURNS @ імя_параметра TABLE
<визначення_таблиці>
[WITH {ENCRYPTION | SCHEMABINDING }
[, ... n]]
[AS]
BEGIN
<тіло_функціі>
RETURN
END
Використання більшої частини параметрів розглядалося при описі попередніх функцій .
Відзначимо, що функції даного типу, як і табличні , повертають значення типу TABLE . Однак, на відміну від табличних функцій , при створенні функцій Multi-statement необхідно явно задати структуру значення, що повертається. Вона зазначається безпосередньо після ключового слова TABLE і, таким чином, є частиною визначення повертаного типу даних. Синтаксис конструкції <визначен_таблиці> повністю відповідає однойменним структурам, використовуваним при створенні звичайних таблиць за допомогою команди CREATE TABLE .
Набір повертаних даних повинен формуватися за допомогою команд INSERT , виконуваних в тілі функції . Крім того, в тілі функції допускається використання різних конструкцій мови SQL, які можуть контролювати значення, що розміщуються у вихідному наборі рядків. При роботі з командою INSERT потрібно явно вказати ім'я того об'єкта, куди необхідно вставити рядки. Тому в функціях типу Multi-statement , на відміну від табличних , необхідно присвоїти якесь ім'я об'єкту з типом даних TABLE - воно і вказується як повернене значення.
Завершення роботи функції відбувається у двох випадках: якщо виникають помилки виконання і якщо з'являється ключове слово RETURN . На відміну від функцій скалярного типу , при використанні команди RETURN не потрібно вказувати повернене значення. Сервер автоматично поверне набір даних типу TABLE , ім'я та структура якого була вказана після ключового слова RETURNS . У тілі функції може бути вказано більше однієї команди RETURN .
Необхідно відзначити, що робота функції завершується тільки при наявності команди RETURN . Це твердження вірне і в тому випадку, коли мова йде про досягнення кінця тіла функції - самої останньої командою повинна бути команда RETURN .
Приклад 11.3 . Створити і застосувати функцію (типу multi-statement), яка для деякого співробітника виводить список всіх його підлеглих (підпорядкованих як безпосередньо йому, так і опосередковано через інших співробітників).
Список співробітників із зазначенням кожного керівника представлений в таблиці emp_mgr з наступною структурою:
CREATE TABLE emp_mgr
(emp CHAR (2) PRIMARY KEY, - співробітник
mgr CHAR (2)) керівник
Приклад даних у таблиці emp_mgr показаний нижче. Для спрощення ілюстрації імена співробітників і їхніх начальників представлені буквами латинського алфавіту. У директора організації начальника немає ( NULL ).
emp mgr
---------
A NULL
BA
CA
DA
EF
FB
GB
IC
KD
CREATE FUNCTION fn_findReports (@ id_emp
CHAR (2))
RETURNS @ report TABLE (empid CHAR (2)
PRIMARY KEY,
mgrid CHAR (2) )
AS
BEGIN
DECLARE @ R INT
DECLARE @ t TABLE (empid CHAR (2)
PRIMARY KEY,
mgrid CHAR (2),
pr INT DEFAULT 0)
INSERT @ t SELECT emp, mgr, 0
FROM emp_mgr
WHERE EMP = @ id_emp
SET @ r = @ @ ROWCOUNT
WHILE @ r> 0
BEGIN
UPDATE @ t SET pr = 1 WHERE pr = 0
INSERT @ t SELECT e.emp, e.mgr, 0
FROM emp_mgr e, @ TT
WHERE e.mgr = t.empid
AND T . pr = 1
SET @ r = @ @ ROWCOUNT
UPDATE @ t SET pr = 2 WHERE pr = 1
END
INSERT @ report SELECT empid, mgrid
FROM @ T
RETURN
END
Приклад 11.3. Створення функції, яка для деякого співробітника виводить список всіх його підлеглих.
Застосуємо створену функцію для визначення списку підлеглих співробітника 'b' :
SELECT * FROM fn_findReports ('b')
Оператор повертає наступні значення:
emp mgr
-----------
BA
EF
FB
GB
Список підлеглих співробітника 'a' створюється за допомогою оператора
SELECT * FROM fn_findReports ('a')
emp mgr
---------
A NULL
BA
CA
DA
EF
FB
GB
IC
KD
Інший оператор формує список підлеглих співробітника 'e' :
SELECT * FROM fn_findReports ('e')
emp mgr
--------
ef
Список підлеглих співробітника 'c' створює наступний оператор:
SELECT * FROM fn_findReports ('c')
emp mgr
--------
CA
IC
Видалення будь функції здійснюється командою:
DROP FUNCTION {[власник.] Імя_функції}
[, ... n]
Вбудовані функції , наявні в розпорядженні користувачів при роботі з SQL, можна умовно розділити на наступні групи:
• математичні функції ;
• рядкові функції ;
• функції для роботи з датою і часом ;
• функції конфігурування;
• функції системи безпеки;
• функції управління метаданими;
• статистичні функції.
Математичні функції
Короткий огляд математичних функцій представлений в таблиці.
Таблиця 11.1. |
|
ABS |
обчислює абсолютне значення числа |
ACOS |
обчислює арккосинус |
ASIN |
обчислює арксинус |
ATAN |
обчислює арктангенс |
ATN2 |
обчислює арктангенс з урахуванням квадратів |
CEILING |
виконує округлення вгору |
COS |
обчислює косинус кута |
COT |
повертає котангенс кута |
DEGREES |
перетворить значення кута з радіан в градуси |
EXP |
повертає експоненту |
FLOOR |
виконує округлення вниз |
LOG |
обчислює натуральний логарифм |
LOG10 |
обчислює десятковий логарифм |
PI |
повертає значення "пі" |
POWER |
зводить число до степеня |
RADIANS |
перетворить значення кута з градуса в радіани |
RAND |
повертає випадкове число |
ROUND |
виконує округлення із заданою точністю |
SIGN |
визначає знак числа |
SIN |
обчислює синус кута |
SQUARE |
виконує зведення числа в квадрат |
SQRT |
витягує квадратний корінь |
TAN |
повертає тангенс кута |
SELECT Товар.Назва,
Податок
FROM Товар INNER JOIN Операція
ON Товар.КодТовару =
Сделка.КодТовару
Приклад 11.4. Використання функції округлення до одного знака після коми для розрахунку податку.
Строкові функції
Короткий огляд строкових функцій представлений в таблиці.
Таблиця 11.2. |
|
ASCII |
повертає код ASCII лівого символу рядка |
CHAR |
за кодом ASCII повертає символ |
CHARINDEX |
визначає порядковий номер символу, з якого починається входження підрядка в рядок |
DIFFERENCE |
повертає показник збігу рядків |
LEFT |
повертає вказану кількість символів з початку рядка |
LEN |
повертає довжину рядка |
LOWER |
переводить всі символи рядка в нижній регістр |
LTRIM |
видаляє пробіли на початку рядка |
NCHAR |
повертає за кодом символ Unicode |
PATINDEX |
виконує пошук підрядка в рядку за вказаною шаблоном |
REPLACE |
замінює входження підрядка на вказане значення |
QUOTENAME |
конвертує рядок в формат Unicode |
REPLICATE |
виконує тиражування рядки певне число разів |
REVERSE |
повертає рядок, символи якої записані у зворотному порядку |
RIGHT |
повертає вказану кількість символів з кінця рядка |
RTRIM |
видаляє пробіли в кінці рядка |
SOUNDEX |
повертає код звучання рядка |
SPACE |
повертає вказану кількість пробілів |
STR |
виконує конвертування значення числового типу в символьний формат |
STUFF |
видаляє вказане число символів, замінюючи нової підрядком |
SUBSTRING |
повертає для рядка підрядок зазначеної довжини з заданого символу |
UNICODE |
повертає Unicode-код лівого символу рядка |
UPPER |
переводить всі символи рядка в верхній регістр |
SELECT Фірма, [Прізвище] + ""
+ Left ([Ім'я], 1) + "."
+ Left ([По батькові], 1)
+ "." AS ПІБ
FROM Клієнт
Приклад 11.5. Використання функції LEFT для отримання ініціалів клієнтів.
Короткий огляд основних функцій для роботи з датою і часом представлений в таблиці.
Таблиця 11.3. |
|
DATEADD |
додає до дати зазначена значення днів, місяців, годин і т.д. |
DATEDIFF |
повертає різницю між зазначеними частинами двох дат |
DATENAME |
виділяє з дати вказану частину і повертає її в символьному форматі |
DATEPART |
виділяє з дати вказану частину і повертає її в числовому форматі |
DAY |
повертає число з вказаної дати |
GETDATE |
повертає поточний системний час |
ISDATE |
перевіряє правильність виразу на відповідність одному з можливих форматів вводу дати |
MONTH |
повертає значення місяця з вказаної дати |
YEAR |
повертає значення року з вказаної дати |
SELECT Year (Дата) AS Рік, Month (Дата)
AS Місяць,
Sum (Кількість) AS Заг_Кількість
FROM Угода
GROUP BY Year (Дата), Month (Дата)
Приклад 11.6. Використання функцій YEAR і MONTH для визначення загальної кількості товару, проданого за кожний місяць кожного року.
DECLARE @ D DATETIME
DECLARE @ Y INT
SET @ d = '29 .10.03 '
SET @ y = DATEPART (yy, @ d)
SELECT @ y
Приклад 11.7. Приклад виділення з дати значення року.
Збережені процедури, є групами пов'язаних між собою операторів SQL, застосування яких робить роботу програміста легшою і гнучкішою, оскільки виконати процедуру, що зберігається, часто виявляється набагато простіше, ніж послідовність окремих операторів SQL. Збережені процедури, є набором команд, що складається з одного або декількох операторів SQL або функцій і зберігається у базі даних у виді, що відкомпілювався. Виконання у базі даних процедур замість окремих операторів SQL, що зберігаються, дає користувачеві наступні переваги:
• необхідні оператори вже містяться у базі даних;
• усі вони пройшли етап синтаксичного аналізу і знаходяться у виконуваному форматі; перед виконанням збереженої процедури, SQL Server генерує для неї план виконання, виконує її оптимізацію і компіляцію;
• Збережені процедури, підтримують модульне програмування, оскільки дозволяють розбивати великі завдання на самостійні, дрібніші і зручніші в управлінні частини;
• Збережені процедури, можуть викликати інші Збережені процедури, і функції;
• Збережені процедури, можуть бути викликані з прикладних програм інших типів;
• як правило, Збережені процедури, виконуються швидше, ніж послідовність окремих операторів;
• Збережені процедури, простіше використовувати: вони можуть складатися з десятків і сотень команд, але для їх запуску досить вказати усього лише ім'я потрібної збереженої процедури. Це дозволяє зменшити розмір запиту, що посилається від клієнта на сервер, а значить, і навантаження на мережу.
Зберігання процедур в тому ж місці, де вони виконуються, забезпечує зменшення об'єму передаваних по мережі даних і підвищує загальну продуктивність системи. Застосування процедур, що зберігаються, спрощує супровід програмних комплексів і внесення змін в них. Зазвичай усі обмеження цілісності у вигляді правил і алгоритмів обробки даних реалізуються на сервері баз даних і доступні кінцевому застосуванню у вигляді набору процедур, що зберігаються, які і представляють інтерфейс обробки даних. Для забезпечення цілісності даних, а також в цілях безпеки, додаток зазвичай не дістає прямого доступу до даних - уся робота з ними ведеться шляхом виклику тих або інших процедур, що зберігаються.
Подібний підхід робить дуже просту модифікацію алгоритмів обробки даних, що негайно ж стають доступними для усіх користувачів мережі, і забезпечує можливість розширення системи без внесення змін до самозастосування: досить змінити процедуру, що зберігається, на сервері баз даних. Розробникові не треба перекомпілювати додаток, створювати його копії, а також інструктувати користувачів про необхідність роботи з новою версією. Користувачі взагалі можуть не підозрювати про те, що в систему внесені зміни.
Збережені процедури, існують незалежно від таблиць або яких-небудь інших об'єктів баз даних. Вони викликаються клієнтською програмою, іншою процедурою, що зберігається, або тригером. Розробник може управляти правами доступу до збереженої процедури, дозволяючи або забороняючи її виконання. Змінювати код збереженої процедури, дозволяється тільки її власникові або членові фіксованої ролі бази даних. При необхідності можна передати права володіння нею від одного користувача до іншого.
При роботі з SQL Server користувачі можуть створювати власні процедури, що реалізовують ті або інші дії. Збережені процедури, є повноцінними об'єктами бази даних, а тому кожна з них зберігається в конкретній базі даних. Безпосередній виклик збереженої процедури, можливий, тільки якщо він здійснюється в контексті тієї бази даних, де знаходиться процедура.
Типи процедур, що зберігаються
У SQL Server є декілька типів процедур, що зберігаються.
• Системні збережені процедури, призначені для виконання різних адміністративних дій. Практично усі дії з адміністрування сервера виконуються з їх допомогою. Можна сказати, що системні Збережені процедури, є інтерфейсом, що забезпечує роботу з системними таблицями, яка, кінець кінцем, зводиться до зміни, додавання, видалення і вибірки даних з системних таблиць як призначених для користувача, так і системних баз даних. Системні збережені процедури мають префікс sp_, зберігаються в системній базі даних і можуть бути викликані в контексті будь-якої іншої бази даних.
• Призначені для користувача Збережені процедури, реалізують ті або інші дії. Збережені процедури, - повноцінний об'єкт бази даних. Внаслідок цього кожна процедура, що зберігається, розташовується в конкретній базі даних, де і виконується.
• Тимчасові збережені процедури, існують лише деякий час, після чого автоматично знищуються сервером. Вони діляться на локальні і глобальні. Локальні тимчасові Збережені процедури, можуть бути викликані тільки з того з'єднання, в якому створені. При створенні такої процедури їй необхідно дати ім'я, що починається з одного символу #. Як і усі тимчасові об'єкти, процедури цього типу, що зберігаються, автоматично віддаляються при відключенні користувача, перезапуску або зупинці сервера. Глобальні тимчасові Збережені процедури, доступні для будь-яких з'єднань сервера, на якому є така ж процедура. Для її визначення досить дати їй ім'я, що починається з символів ##. Віддаляються ці процедури при перезапуску або зупинці сервера, а також при закритті з'єднання, в контексті якого вони були створені.
Створення, зміна і видалення процедур, що зберігаються
Створення збереженої процедури, припускає рішення наступних завдань :
• визначення типу створюваної збереженої процедури : тимчасова або призначена для користувача. Окрім цього, можна створити свою власну системну процедуру, що зберігається, призначивши їй ім'я з префіксом sp_ і помістивши її в системну базу даних. Така процедура буде доступна в контексті будь-якої бази даних локального сервера;
• планування прав доступу. При створенні збереженої процедури, слід враховувати, що вона матиме ті ж права доступу до об'єктів бази даних, що і користувач, що створив її;
• визначення параметрів збереженої процедури. Подібно до процедур, що входять до складу більшості мов програмування, Збережені процедури, можуть бути наділені вхідними і вихідними параметрами ;
• розробка коду збереженої процедури. Код процедури може містити послідовність будь-яких команд SQL, включаючи виклик інших процедур, що зберігаються.
Створення нової і зміна наявної збереженої процедури, здійснюється за допомогою наступної команди:
<визначення_процедури>::=
{CREATE | ALTER } [PROCEDURE] ім'я_процедури
[;номер]
[{@ім'я_параметра тип_даних } [VARYING ]
[=default][OUTPUT] ][,..n]
[WITH { RECOMPILE | ENCRYPTION | RECOMPILE
ENCRYPTION }]
[FOR REPLICATION]
AS
sql_оператор [..n]
Розглянемо параметри цієї команди.
Використовуючи префікси sp_, #, ##, створювану процедуру можна визначити в якості системної або тимчасової. Як видно з синтаксису команди, не допускається вказувати ім'я власника, якому належатиме створювана процедура, а також ім'я бази даних, де вона має бути розміщена. Так, щоб розмістити утворюючу збережену процедуру в конкретній базі даних, необхідно виконати команду CREATE PROCEDURE в контексті цієї бази даних. При зверненні з тіла збереженої процедури, до об'єктів тієї ж бази даних можна використовувати укорочені імена, т. е. без вказівки імені бази даних. Коли ж вимагається звернутися до об'єктів, розташованих в інших базах даних, вказівка імені бази даних обов'язково.
Номер в імені - це ідентифікаційний номер збереженої процедури, що однозначно визначає її в групі процедур. Для зручності управління процедурами логічно однотипні Збережені процедури, можна групувати, привласнюючи їм однакові імена, але різні ідентифікаційні номери.
Для передачі вхідних і вихідних даних в створюваній процедурі, що зберігається, можуть використовуватися параметри, імена яких, як і імена локальних змінних, повинні починатися з символу @. В одній процедурі, що зберігається, можна задати безліч параметрів, розділених комами. У тілі процедури не повинні застосовуватися локальні змінні, чиї імена співпадають з іменами параметрів цієї процедури.
Для визначення типу даних, який матиме відповідний параметр збереженої процедури, годяться будь-які типи даних SQL, включаючи визначені користувачем. Проте тип даних CURSOR може бути використаний тільки як вихідний параметр збереженої процедури, тобто з вказівкою ключового слова OUTPUT.
Наявність ключового слова OUTPUT означає, що відповідний параметр призначений для повернення даних з збереженої процедури. Проте це зовсім не означає, що параметр не підходить для передачі значень в процедуру, що зберігається. Вказівка ключового слова OUTPUT наказує серверу при виході з збереженої процедури, присвоїти поточне значення параметра локальної змінної, яка була вказана при виклику процедури в якості значення параметра. Відмітимо, що при вказівці ключового слова OUTPUT значення відповідного параметра при виклику процедури може бути задане тільки за допомогою локальної змінної. Не дозволяється використання будь-яких виразів або констант, допустиме для звичайних параметрів.
Ключове слово VARYING застосовується спільно з параметром OUTPUT, що має тип CURSOR. Воно визначає, що вихідним параметром буде результуюча множина.
Ключове слово DEFAULT є значенням, яке прийматиме відповідний параметр за умовчанням. Таким чином, при виклику процедури можна не вказувати явно значення відповідного параметра.
Оскільки сервер кешує план виконання запиту і код, що компілює, при наступному виклику процедури використовуватимуться вже готові значення. Проте в деяких випадках все ж вимагається виконувати перекомпіляцію коду процедури. Вказівка ключового слова RECOMPILE наказує системі створювати план виконання збереженої процедури, при кожному її виклику.
Параметр FOR REPLICATION затребуваний при реплікації даних і включенні створюваної збереженої процедури, в якості статті в публікацію.
Ключове слово ENCRYPTION наказує серверу виконати шифрування коду збереженої процедури, що може забезпечити захист від використання авторських алгоритмів, що реалізовують роботу збереженої процедури.
Ключове слово AS розміщується на початку власне тіла збереженої процедури, тобто набору команд SQL, за допомогою яких і реалізовуватиметься те або інша дія. У тілі процедури можуть застосовуватися практично усі команди SQL, оголошуватися транзакції, встановлюватися блокування і викликатися інші Збережені процедури. Вихід зі збереженої процедури можна здійснити за допомогою команди RETURN.
Видалення збереженої процедури, здійснюється командою:
DROP PROCEDURE {ім'я_процедури} [,..n]
Виконання збереженої процедури
Для виконання збереженої процедури, використовується команда:
[[ EXEC [ UTE] ім'я_процедури [;номер]
[[@ім'я_параметра=]{значення | @ім'я_змінної}
[OUTPUT ]|[DEFAULT ]][,..n]
Якщо виклик збереженої процедури, не є єдиною командою в пакеті, то присутність команди EXECUTE обов'язкова. Більше того, цю команду потрібно для виклику процедури з тіла іншої процедури або тригера.
Використання ключового слова OUTPUT при виклику процедури дозволяється тільки для параметрів, які були оголошені при створенні процедури з ключовим словом OUTPUT.
Коли ж при виклику процедури для параметра вказується ключове слово DEFAULT, то буде використано значення за умовчанням. Природно, вказане слово DEFAULT дозволяється тільки для тих параметрів, для яких визначено значення за умовчанням.
З синтаксису команди EXECUTE видно, що імена параметрів можуть бути опущені при виклику процедури. Проте в цьому випадку користувач повинен вказувати значення для параметрів в тому ж порядку, в якому вони перераховувалися при створенні процедури. Присвоїти параметру значення за умовчанням, просто пропустивши його при перерахуванні не можна. Якщо ж вимагається опустити параметри, для яких визначено значення за умовчанням, досить явної вказівки імен параметрів при виклику збереженої процедури. Більше того, у такий спосіб можна перераховувати параметри і їх значення в довільному порядку.
Відмітимо, що при виклику процедури вказуються або імена параметрів зі значеннями, або тільки значення без імені параметра. Їх комбінування не допускається.
Приклад 12.1. Процедура без параметрів. Розробити процедуру для отримання назв і вартості товарів, придбаних Івановим.
CREATE PROC my_proc1
AS
SELECT Товар.Назва,
Товар.Ціна*Угода.Кількість
AS Вартість, Клієнт.Прізвище
FROM Клієнт INNER JOIN
( (Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару)
ON Клієнт.КодКлієнта=Угода.КодКлієнта
WHERE Клієнт.Прізвище='Іванов'
Приклад 12.1. Процедура для отримання назв і вартості товарів, придбаних Івановим.
Для звернення до процедури можна використовувати команди:
EXEC my_proc1 або my_proc1
Процедура повертає набір даних.
Приклад 12.2. Процедура без параметрів. Створити процедуру для зменшення ціни товару першого сорту на 10%.
CREATE PROC my_proc2
AS
UPDATE Товар SET Ціна=Ціна*0.9
WHERE Сорт='перший'
Приклад 12.2. Процедура для зменшення ціни товару першого сорту на 10%.
Для звернення до процедури можна використовувати команди:
EXEC my_proc2 або my_proc2
Процедура не повертає ніяких даних.
Приклад 12.3. Процедура з вхідним параметром. Створити процедуру для отримання назв і вартості товарів, які придбав заданий клієнт.
CREATE PROC my_proc3
@k VARCHAR(20)
AS
SELECT Товар.Назва,
Товар.Ціна*Угода.Кількість
AS Вартість, Клієнт.Прізвище
FROM Клієнт INNER JOIN
( (Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару)
ON Клієнт.КодКлієнта=Угода.КодКлієнта
WHERE Клієнт.Прізвище=@k
Приклад 12.3. Процедура для отримання назв і вартості товарів, які придбав заданий клієнт.
Для звернення до процедури можна використовувати команди:
EXEC my_proc3 'Іванов' або
my_proc3 @k='Іванов'
Приклад 12.4. Процедура з вхідними параметрами. Створити процедуру для зменшення ціни товару заданого типу відповідно до вказаного %.
CREATE PROC my_proc4
@t VARCHAR(20), @p FLOAT
AS
UPDATE Товар SET Ціна=Ціна*(1 -@p)
WHERE Тип=@t
Приклад 12.4. Процедура для зменшення ціни товару заданого типу відповідно до вказаного %.
Для звернення до процедури можна використовувати команди:
EXEC my_proc4 'Вафлі', 0.05 або
EXEC my_proc4 @t='Вафлі', @p=0.05
Приклад 12.5. Процедура з вхідними параметрами і значеннями за умовчанням. Створити процедуру для зменшення ціни товару заданого типу відповідно до вказаного %.
CREATE PROC my_proc5
@t VARCHAR(20)='Цукерки'
@p FLOAT=0.1
AS
UPDATE Товар SET Ціна=Ціна*(1 -@p)
WHERE Тип=@t
Приклад 12.5. Процедура з вхідними параметрами і значеннями за умовчанням. Створити процедуру для зменшення ціни товару заданого типу відповідно до вказаного %.
Для звернення до процедури можна використовувати команди:
EXEC my_proc5 'Вафлі', 0.05 або
EXEC my_proc5 @t='Вафлі', @p=0.05 або
EXEC my_proc5 @p=0.05
В цьому випадку зменшується ціна цукерок (значення типу не вказане при виклику процедури і береться за умовчанням).
EXEC my_proc5
У останньому випадку обидва параметри (і тип, і відсотки) не вказано при виклику процедури, їх значення беруться за умовчанням.
Приклад 12.6. Процедура з вхідними і вихідними параметрами. Створити процедуру для визначення загальної вартості товарів, проданих за конкретний місяць.
CREATE PROC my_proc6
@m INT
@s FLOAT OUTPUT
AS
SELECT @s=Sum(Товар.Ціна*Угода.Кількість)
FROM Товар INNER JOIN Угода
ON Товар.КодТовару=Угода.КодТовару
GROUP BY Month(Угода.Дата)
HAVING Month(Угода.Дата)=@m
Приклад 12.6. Процедура з вхідними і вихідними параметрами. Створити процедуру для визначення загальної вартості товарів, проданих за конкретний місяць.
Для звернення до процедури можна використовувати команди:
DECLARE @st FLOAT
EXEC my_proc6 1,@st OUTPUT
SELECT @st
Цей блок команд дозволяє визначити вартість товарів, проданих в січні ( вхідний параметр місяць вказаний рівним 1).
Створити процедуру для визначення загальної кількості товарів, придбаних фірмою, в якій працює заданий співробітник.
Спочатку розробимо процедуру для визначення фірми, де працює співробітник.
CREATE PROC my_proc7
@n VARCHAR(20)
@f VARCHAR(20) OUTPUT
AS
SELECT @f=Фірма
FROM Клієнт
WHERE Прізвище=@n
Приклад 12.7. Використання вкладених процедур. Створити процедуру для визначення загальної кількості товарів, придбаних фірмою, в якій працює заданий співробітник.
Потім створимо процедуру, що підраховує загальну кількість товару, який закуплений фірмою, що цікавить нас.
CREATE PROC my_proc8
@fam VARCHAR(20)
@kol INT OUTPUT
AS
DECLARE @firm VARCHAR(20)
EXEC my_proc7 @fam,@firm OUTPUT
SELECT @kol=Sum(Угода.Кількість)
FROM Клієнт INNER JOIN Угода
ON Клієнт.КодКлієнта=Угода.КодКлієнта
GROUP BY Клієнт.Фірма
HAVING Клієнт.Фірма=@firm
Приклад 12.7. Створення процедури для визначення загальної кількості товарів, придбаних фірмою, в якій працює заданий співробітник.
Виклик процедури здійснюється за допомогою команди:
DECLARE @k INT
EXEC my_proc8 'Іванов',@k OUTPUT
SELECT @k
Запит до реляційної бази даних зазвичай повертає декілька рядів (записів) даних, але додаток за один раз обробляє лише один запис. Навіть якщо воно має справу одночасно з декількома рядами (наприклад, виводить дані у формі електронних таблиць), їх кількість як і раніше обмежена. Крім того, при модифікації, видаленні або додаванні даних робочою одиницею являється ряд. У цій ситуації на перший план виступає концепція курсору, і в такому контексті курсор - покажчик на ряд.
Курсор в SQL - це область в пам'яті бази даних, яка призначена для зберігання останнього оператора SQL. Якщо поточний оператор - запит до бази даних, в пам'яті зберігається і рядок даних запиту, званий поточним значенням, або поточним рядком курсору. Вказана область в пам'яті пойменована і доступна для прикладних програм.
Зазвичай курсори використовуються для вибору з бази даних деякої підмножини інформації, що зберігається в ній. У кожен момент часу прикладною програмою може бути перевірений один рядок курсору. Курсори часто застосовуються в операторах SQL, вбудованих в написані на мовах процедурного типу прикладні програми. Деякі з них неявно створюються сервером бази даних, тоді як інші визначаються програмістами.
Відповідно до стандарту SQL при роботі з курсорами можна виділити наступні основні дії:
• створення або оголошення курсору ;
• відкриття курсору, тобто наповнення його даними, які зберігаються у багаторівневій пам'яті ;
• вибірка з курсору і зміна з його допомогою рядків даних;
• закриття курсору, після чого він стає недоступним для призначених для користувача програм;
• звільнення курсору, тобто видалення курсору як об'єкту, оскільки його закриття необов'язково звільняє асоційовану з ним пам'ять.
У різних реалізаціях визначення курсору може мати деякі відмінності. Так, наприклад, іноді розробник повинен явним чином звільнити память, що виділяється для курсору. Після звільнення курсору асоційована з ним пам'ять також звільняється. При цьому стає можливим повторне використання його імені. У інших реалізаціях при закритті курсору звільнення пам'яті відбувається неявним чином. Відразу після відновлення вона стає доступною для інших операцій: відкриття іншого курсору і так далі
В деяких випадках застосування курсору неминуче. Проте по можливості цього слід уникати і працювати із стандартними командами обробки даних : SELECT, UPDATE, INSERT, DELETE. Окрім того, що курсори не дозволяють проводити операції зміни над усім об'ємом даних, швидкість виконання операцій обробки даних за допомогою курсору помітно нижче, ніж у стандартних засобів SQL.
SQL Server підтримує три види курсорів :
• курсори SQL застосовуються в основному усередині тригерів, процедур, що зберігаються, і сценаріїв;
• курсори сервера діють на сервері і реалізують програмний інтерфейс додатків для ODBC, OLE DB, DB_Library;
• курсори клієнта реалізуються на самому клієнтові. Вони вибирають увесь результуючий набір рядків з сервера і зберігають його локально, що дозволяє прискорити операції обробки даних за рахунок зниження втрат часу на виконання мережевих операцій.
Різні типи розрахованих на багато користувачів застосувань вимагають і різних типів організації паралельного доступу до даних. Деяким застосуванням потрібний негайний доступ до інформації про зміни у базі даних. Це характерно для систем резервування квитків. У інших випадках, наприклад, в системах статистичної звітності, важлива стабільність даних, адже якщо вони постійно модифікуються, програми не зможуть ефективно відображати інформацію. Різним застосуванням потрібні різні реалізації курсорів.
У середовищі SQL Server типи курсорів розрізняються по можливостях, що надаються. Тип курсору визначається на стадії його створення і не може бути змінений. Деякі типыкурсоров можуть виявляти зміни, зроблені іншими користувачами в рядках, включених в результуючий набір. Проте SQL Server відстежує зміни таких рядків тільки на стадії звернення до рядка і не дозволяє відстежувати зміни, коли рядок вже лічений.
Курсори діляться на дві категорії: послідовні і прокручувані. Послідовні дозволяють вибирати дані тільки в одному напрямі - від початку до кінця. Прокручувані ж курсори надають велику свободу дій - допускається переміщення в обох напрямах і перехід до довільного рядка результуючого набору курсору. Якщо програма здатна модифікувати дані, на які вказує курсор, він називається прокручуваним і таким, що модифікується. Говорячи про курсори, не слід забувати про ізольованість транзакцій. Коли один користувач модифікує запис, інший читає її за допомогою власного курсору, більше того, він може модифікувати той же запис, що робить необхідним дотримання цілісності даних.
SQL Server підтримує курсори статичні, динамічні, послідовні і керовані набором ключів.
У схемі із статичним курсором інформація читається з бази даних один раз і зберігається у вигляді моментального знімка (за станом на деякий момент часу), тому зміни, внесені у базу даних іншим користувачем, не видно. На час відкриття курсору сервер встановлює блокування на усі рядки, включені в його повний результуючий набір. Статичний курсор не змінюється після створення і завжди відображає той набір даних, який існував на момент його відкриття.
Якщо інші користувачі змінять в початковій таблиці включені в курсор дані, це ніяк не вплине на статичний курсор.
У статичний курсор внести зміни неможливо, тому він завжди відкривається в режимі "тільки для читання".
Динамічний курсор підтримує дані в "живому" стані, але це вимагає витрат мережевих і програмних ресурсів. При використанні динамічних курсорів не створюється повна копія початкових даних, а виконується динамічна вибірка з початкових таблиць тільки при зверненні користувача до тих або інших даних. На час вибірки сервер блокує рядки, а усі зміни, що вносяться користувачем в повний результуючий набір курсору, будуть видні в курсорі. Проте якщо інший користувач вніс зміни вже після вибірки даних курсором, то вони не відіб'ються в курсорі .
Курсор, керований набором ключів, знаходиться посередині між цими крайнощами. Записи ідентифікуються на момент вибірки, і тим самим відстежуються зміни . Такий тип курсору корисний при реалізації прокрутки назад - тоді додавання і видалення рядів не видно, поки інформація не оновиться, а драйвер вибирає нову версію запису, якщо в неї були внесені зміни.
Послідовні курсори не дозволяють виконувати вибірку даних у зворотному напрямі. Користувач може вибирати рядки тільки від початку до кінця курсору . Послідовний курсор не зберігає набір усіх рядків. Вони прочитуються з бази даних, як тільки вибираються в курсорі, що дозволяє динамічно відбивати усі зміни, що вносяться користувачами у базу даних за допомогою команд INSERT, UPDATE, DELETE. У курсорі видно самий останній стан даних.
Статичні курсори забезпечують стабільний погляд на дані. Вони хороші для систем "складування" інформації : додатків для систем звітності або для статистичних і аналітичних цілей. Крім того, статичний курсор краще за інших справляється з вибіркою великої кількості даних. Навпаки, в системах електронних покупок або резервування квитків потрібне динамічне сприйняття оновлюваної інформації у міру внесення змін. У таких випадках використовується динамічний курсор. У цих застосуваннях об'єм передаваних даних, як правило, невеликий, а доступ до них здійснюється на рівні рядів (окремих записів). Груповий доступ зустрічається дуже рідко.
Управління курсором реалізується шляхом виконання наступних команд :
• DECLARE - створення або оголошення курсору ;
• OPEN - відкриття курсору, тобто наповнення його даними;
• FETCH - вибірка з курсору і зміна рядків даних за допомогою курсору;
• CLOSE - закриття курсору ;
• DEALLOCATE - звільнення курсору, тобто видалення курсору як об'єкту.
Оголошення курсору
У стандарті SQL для створення курсору передбачена наступна команда:
<створення_курсору>::=
DECLARE ім'я_курсору
[INSENSITIVE][SCROLL] CURSOR
FOR SELECT_оператор
[FOR { READ_ONLY | UPDATE
[OF ім'я_стовпця[,..n]]}]
При використанні ключового слова INSENSITIVE буде створений статичний курсор. Зміни даних не дозволяються, крім того, не відображаються зміни, зроблені іншими користувачами. Якщо ключове слово INSENSITIVE відсутнє, створюється динамічний курсор.
При вказівці ключового слова SCROLL створений курсор можна прокручувати у будь-якому напрямі, що дозволяє застосовувати будь-які команди вибірки. Якщо цей аргумент опускається, то курсор виявиться послідовним, тобто його перегляд буде можливий тільки в одному напрямі - від початку до кінця.
SELECT -оператор задає тіло запиту SELECT, за допомогою якого визначається результуючий набір рядків курсору.
При вказівці аргументу FOR READ_ONLY створюється курсор "тільки для читання", і ніякі модифікації даних не дозволяються. Він відрізняється від статичного, хоча останній також не дозволяє міняти дані. В якості курсору "тільки для читання" може бути оголошений динамічний курсор, що дозволить відображати зміни, зроблені іншим користувачем.
Створення курсору з аргументом FOR UPDATE дозволяє виконувати в курсорі зміну даних або у вказаних стовпцях, або, за відсутності аргументу OF ім'я_стовпця, в усіх стовпцях.
У середовищі MS SQL Server прийнятий наступний синтаксис команди створення курсору :
<створення_курсору>::=
DECLARE ім'я_курсору CURSOR [LOCAL | GLOBAL]
[FORWARD_ONLY | SCROLL]
[STATIC | KEYSET | DYNAMIC | FAST_FORWARD]
[READ_ONLY | SCROLL_LOCKS | OPTIMISTIC]
[TYPE_WARNING]
FOR SELECT_оператор
[FOR UPDATE [OF ім'я_стовпця[,..n]]]
При використанні ключового слова LOCAL буде створений локальний курсор, який видно тільки в межах пакету, що створив його, тригера, збереженої процедури, або призначеної для користувача функції. Після закінчення роботи пакету, тригера, процедури або функції курсор неявно знищується. Щоб передати вміст курсору за межі конструкції, що створила його, необхідно присвоїти його параметру аргумент OUTPUT.
Якщо вказано ключове слово GLOBAL, створюється глобальний курсор ; він існує до закриття поточного з'єднання.
При вказівці FORWARD_ONLY створюється послідовний курсор ; вибірку даних можна здійснювати тільки в напрямі від першого рядка до останнього.
При вказівці SCROLL створюється прокручуваний курсор ; звертатися до даних можна у будь-якому порядку і у будь-якому напрямі.
При вказівці STATIC створюється статичний курсор.
При вказівці KEYSET створюється ключовий курсор.
При вказівці DYNAMIC створюється динамічний курсор.
Якщо для курсору READ_ONLY вказати аргумент FAST_FORWARD, то створений курсор буде оптимізований для швидкого доступу до даних. Цей аргумент не може бути використаний спільно з аргументами FORWARD_ONLY і OPTIMISTIC.
У курсорі, створеному з вказівкою аргументу OPTIMISTIC, забороняється зміна і видалення рядків, які були змінені після відкриття курсору.
При вказівці аргументу TYPE_WARNING сервер інформуватиме користувача про неявну зміну типу курсору, якщо він несумісний із запитом SELECT.
Відкриття курсору
Для відкриття курсору і наповнення його даними з вказаного при створенні курсору запиту SELECT використовується наступна команда:
OPEN {{[GLOBAL]ім'я_курсору }
|@ім'я_змінної_курсору}
Після відкриття курсору відбувається виконання пов'язаного з ним оператора SELECT, вихідні дані якого зберігаються у багаторівневій пам'яті.
Вибірка даних з курсору
Відразу після відкриття курсору можна вибрати його вміст (результат виконання відповідного запиту) за допомогою наступної команди:
FETCH [[NEXT | PRIOR | FIRST | LAST
| ABSOLUTE {номер_рядка
| @змінна_номера_рядка}
| RELATIVE {номер_рядка |
@змінна_номера_рядка}]
FROM ]{{[GLOBAL ]ім'я_курсору }|
@ім'я_змінної_курсору }
[INTO @ім'я_змінної [,..n]]
При вказівці FIRST буде повернена найперший рядок повного результуючого набору курсору, яка стає поточним рядком.
При вказівці LAST повертається самий останній рядок курсору. Вона ж стає поточним рядком.
При вказівці NEXT повертається рядок, що знаходиться в повному результуючому наборі відразу ж після поточної. Тепер вона стає поточною. За умовчанням команда FETCH використовує саме цей спосіб вибірки рядків.
Ключове слово PRIOR повертає рядок, що знаходиться перед поточною. Вона і стає поточною.
Аргумент ABSOLUTE {номер_рядка | @змінна_номера_рядка} повертає рядок по її абсолютному порядковому номеру в повному результуючому наборі курсору. Номер рядка можна задати за допомогою константи або як ім'я змінної, в якій зберігається номер рядка. Змінна повинна мати цілочисельний тип даних. Вказуються як позитивні, так і негативні значення. При вказівці позитивного значення рядок відлічується від початку набору, негативного, - від кінця. Вибраний рядок стає поточним. Якщо вказано нульове значення, рядок не повертається.
Аргумент RELATIVE {кілок_рядка | @змінна_кілок_рядка} повертає рядок, що знаходиться через вказану кількість рядків після поточної. Якщо вказати негативне значення числа рядків, то буде повернений рядок, що знаходиться за вказану кількість рядків перед поточною. При вказівці нульового значення повернеться поточний рядок. Повернений рядок стає поточним.
Щоб відкрити глобальний курсор, перед його ім'ям вимагається вказати ключове слово GLOBAL. Ім'я курсору також може бути вказане за допомогою змінної.
У конструкції INTO @ім'я_змінної [,..n] задається список змінних, в яких будуть збережені відповідні значення стовпців поверненого рядка. Порядок вказівки змінних повинен відповідати порядку стовпців в курсорі, а тип даних змінної - типу даних в стовпці курсору. Якщо конструкція INTO не вказана, то поведінка команди FETCH нагадуватиме поведінку команди SELECT - дані виводяться на екран.
Зміна і видалення даних
Для виконання змін за допомогою курсору необхідно виконати команду UPDATE в наступному форматі:
UPDATE ім'я_таблиці SET {ім'я_стовпця={
DEFAULT | NULL | вираження}}[,..n]
WHERE CURRENT OF {{[GLOBAL] ім'я_курсору}
|@ім'я_змінної_курсору}
За одну операцію можуть бути змінені декілька стовпців поточного рядка курсору, але усі вони повинні належати одній таблиці.
Для видалення даних за допомогою курсору використовується команда DELETE в наступному форматі:
DELETE ім'я_таблиці
WHERE CURRENT OF {{[GLOBAL] ім'я_курсору}
|@ім'я_змінної_курсору}
В результаті буде видалений рядок, встановлений поточною в курсорі.
Закриття курсору
CLOSE {ім'я_курсору | @ім'я_змінної_курсору}
Після закриття курсор стає недоступним для користувачів програми. При закритті знімаються усі блокування, встановлені в процесі його роботи. Закриття може застосовуватися тільки до відкритих курсорів. Закритий, але не звільнений курсор може бути повторно відкритий. Не допускається закривати невідкритий курсор.
Звільнення курсору
Закриття курсору необов'язково звільняє асоційовану з ним пам'ять. У деяких реалізаціях треба явним чином звільнити її за допомогою оператора DEALLOCATE. Після звільнення курсору звільняється і пам'ять, при цьому стає можливим повторне використання імені курсору.
DEALLOCATE { ім'я_курсору |
@ім'я_змінної_курсору }
Для контролю досягнення кінця курсору рекомендується застосовувати функцію:
@@FETCH_STATUS
Функція @@FETCH_STATUS повертає:
0, 0, якщо вибірка завершилася успішно;
-- 1, якщо вибірка завершилася невдало внаслідок спроби вибірки рядка, що знаходиться за межами курсору ;
-- 2, якщо вибірка завершилася невдало внаслідок спроби звернення до видаленого або зміненого рядка.
DECLARE abc CURSOR SCROLL FOR
SELECT * FROM Клієнт
Приклад 13.1. Оголошення курсору.
DECLARE @MyCursor CURSOR
SET @MyCursor=CURSOR LOCAL SCROLL FOR
SELECT * FROM Клієнт
Приклад 13.2. Використання змінної для оголошення курсору.
DECLARE abc CURSOR GLOBAL SCROLL FOR
SELECT * FROM Клієнт
OPEN abc
Приклад 13.3. Оголошення і відкриття курсору.
DECLARE @MyCursor CURSOR
SET @MyCursor=abc
Приклад 13.4. Використання змінної для переприсвоювання курсору.
Приклад 13.5. Розробити курсор для виведення списку фірм і клієнтів з Києва.
DECLARE @firm VARCHAR(50)
@fam VARCHAR(50)
@message VARCHAR(80)
PRINT ' Список клієнтів'
DECLARE klient_cursor CURSOR LOCAL FOR
SELECT Фірма, Прізвище
FROM Клієнт
WHERE Місто='Київ'
ORDER BY Фірма, Прізвище
OPEN klient_cursor
FETCH NEXT FROM klient_cursor INTO @firm, @fam
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @message='Клієнт '+@fam+
' ' Фірма '+ @firm
PRINT @message
-- -- перехід до наступного клієнта--
FETCH NEXT FROM klient_cursor
INTO @firm, @fam
END
CLOSE klient_cursor
DEALLOCATE klient_cursor
Приклад 13.5. Курсор для виведення списку фірм і клієнтів з Києва.
Приклад 13.6. Розробити курсор для виведення списку придбаних клієнтами з Києва товарів і їх загальної вартості. У один курсор заносяться усі московські клієнти, потім для кожного рядка курсору, тобто для кожного клієнта, визначається і роздруковується інший курсор - його покупки. Підраховується загальна вартість покупок клієнта.
DECLARE @id_kl INT
@firm VARCHAR(50)
@fam VARCHAR(50),
@message VARCHAR(80)
@nam VARCHAR(50)
@d DATETIME
@p INT
@s INT
SET @s=0
PRINT ' Список покупок'
DECLARE klient_cursor CURSOR LOCAL FOR
SELECT КодКлієнта, Фірма, Прізвище
FROM Клієнт
WHERE Місто='Київ'
ORDER BY Фірма, Прізвище
OPEN klient_cursor
FETCH NEXT FROM klient_cursor
INTO @id_kl, @firm, @fam
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @message='Клієнт '+@fam+
' ' Фірма '+ @firm
PRINT @message
SELECT @message='Найменування товару Дата
покупки Вартість'
PRINT @message
DECLARE tovar_cursor CURSOR FOR
SELECT Товар.Назва, Угода.Дата
Товар.Ціна*Угода.Кількість AS
Вартість
FROM Товар INNER JOIN Угода ON Товар.
КодТовару=Угода.КодТовару
WHERE Угода.КодКлієнта=@id_kl
OPEN tovar_cursor
FETCH NEXT FROM tovar_cursor
INTO @nam, @d, @p
IF @@FETCH_STATUS<>0
PRINT ' Немає покупок'
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @message=' '+@nam+' '+
CAST(@d AS CHAR(12))+' '+
CAST(@p AS CHAR(6))
PRINT @message
SET @s=@s+@p
FETCH NEXT FROM tovar_cursor
INTO @nam, @d, @p
END
CLOSE tovar_cursor
DEALLOCATE tovar_cursor
SELECT @message='Загальна вартість '+
CAST(@s AS CHAR(6))
PRINT @message
-- -- перехід до наступного клієнта--
FETCH NEXT FROM klient_cursor
INTO @id_kl, @firm, @fam
END
CLOSE klient_cursor
DEALLOCATE klient_cursor
Приклад 13.6. Курсор для виведення списку придбаних клієнтами з Києва товарів і їх загальної вартості.
Приклад 13.7. Розробити прокручуваний курсор для клієнтів з Києва. Якщо номер телефону починається на 1, видалити клієнта з таким номером і в першому записі курсору замінити першу цифру в номері телефону на 4.
DECLARE @firm VARCHAR(50)
@fam VARCHAR(50)
@tel VARCHAR(8),
@message VARCHAR(80)
PRINT ' Список клієнтів'
DECLARE klient_cursor CURSOR GLOBAL SCROLL
KEYSET FOR
SELECT Фірма, Прізвище, Телефон
FROM Клієнт
WHERE Місто='Київ'
ORDER BY Фірма, Прізвище
FOR UPDATE
OPEN klient_cursor
FETCH NEXT FROM klient_cursor
INTO @firm, @fam, @tel
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @message='Клієнт '+@fam+
' ' Фірма '+@firm ' Телефон '+ @tel
PRINT @message
-- -- якщо номер телефону починається на 1,
-- -- видалити клієнта з таким номером
IF @tel LIKE '1%'
DELETE Клієнт
WHERE CURRENT OF klient_cursor
ELSE
-- -- перехід до наступного клієнта
FETCH NEXT FROM klient_cursor
INTO @firm, @fam, @tel
END
FETCH ABSOLUTE 1 FROM klient_cursor
INTO @firm, @fam, @tel
-- -- у першому записі замінити першу цифру
-- -- номері телефону на 4
UPDATE Клієнт SET Телефон='4' +
RIGHT(@tel, LEN(@tel) - 1))
WHERE CURRENT OF klient_cursor
SELECT @message='Клієнт '+@fam+' Фірма '+
@firm ' Телефон '+ @tel
PRINT @message
CLOSE klient_cursor
DEALLOCATE klient_cursor
Приклад 13.7. Прокручуваний курсор для клієнтів з Києва.
Приклад 13.8. Використання курсору як вихідного параметра процедури. Процедура повертає набір даних - список товарів.
CREATE PROC my_proc
@cur CURSOR VARYING OUTPUT
AS
SET @cur=CURSOR FORWARD_ONLY STATIC FOR
SELECT Назва FROM Товар
OPEN @cur
Приклад 13.8. Використання курсору як вихідного параметра процедури.
Виклик процедури і вивід на друк даних з вихідного курсору здійснюється таким чином:
DECLARE @my_cur CURSOR
DECLARE @n VARCHAR(20)
EXEC my_proc @cur=@my_cur OUTPUT
FETCH NEXT FROM @my_cur INTO @n
SELECT @n
WHILE (@@FETCH_STATUS=0)
BEGIN
FETCH NEXT FROM @my_cur INTO @n
SELECT @n
END
CLOSE @my_cur
DEALLOCATE @my_cur
Тригери є одним з різновидів процедур, що зберігаються. Їх виконання відбувається при виконанні для таблиці якого-небудь оператора мови маніпулювання даними (DML). Тригери використовуються для перевірки цілісності даних, а також для відкату транзакцій.
Тригер - це SQL, що відкомпілювалася, -процедура, виконання якої обумовлене настанням певних подій усередині реляційної бази даних. Застосування тригерів переважно дуже зручне для користувачів бази даних. Та все ж їх використання часто пов'язане з додатковими витратами ресурсів на операції введення/виводу. У тому випадку, коли тих же результатів (з набагато меншими непродуктивними витратами ресурсів) можна добитися за допомогою процедур, що зберігаються, або прикладних програм, застосування тригерів недоцільне.
Тригери - особливий інструмент SQL -сервера, використовуваний для підтримки цілісності даних у базі даних. За допомогою обмежень цілісності, правил і значень за умовчанням не завжди можна добитися потрібного рівня функціональності. Часто вимагається реалізувати складні алгоритми перевірки даних, що гарантують їх достовірність і реальність. Крім того, іноді необхідно відстежувати зміни значень таблиці, щоб потрібним чином змінити пов'язані дані. Тригери можна розглядати як свого роду фільтри, вступаючі в дія після виконання усіх операцій відповідно до правил, стандартних значень і так далі
Тригер є спеціальним типом процедур, що зберігаються, запускаються сервером автоматично при спробі зміни даних в таблицях, з якими тригери звязані. Кожен тригер прив'язується до конкретної таблиці. Усі вироблювані ним модифікації даних розглядаються як одна транзакція. У разі виявлення помилки або порушення цілісності даних відбувається відкат цієї транзакції. Тим самим внесення змін забороняється. Відміняються також усі зміни, вже зроблені тригером.
Створює тригер тільки власник бази даних. Це обмеження дозволяє уникнути випадкової зміни структури таблиць, способів зв'язку з ними інших об'єктів і тому подібне
Тригер є дуже корисним і в той же час небезпечним засобом. Так, при неправильній логіці його роботи можна легко знищити цілу базу даних, тому тригери необхідно дуже ретельно відлагоджувати.
На відміну від звичайної підпрограми, тригер виконується неявно в кожному випадку виникнення тригерної події, до того ж він не має аргументів. Приведення його в дію іноді називають запуском тригера. За допомогою тригерів досягаються наступні цілі:
• перевірка коректності введених даних і виконання складних обмежень цілісності даних, які важко, якщо взагалі можливо, підтримувати за допомогою обмежень цілісності, встановлених для таблиці;
• видача попереджень, що нагадують про необхідність виконання деяких дій при оновленні таблиці, реалізованому певним чином;
• накопичення аудиторської інформації за допомогою фіксації відомостей про внесені зміни і тих осіб, які їх виконали;
• підтримка реплікації.
Основний формат команди CREATE TRIGGER показаний нижче:
<Визначення_тригера>::=
CREATE TRIGGER ім'я_тригера
BEFORE | AFTER <тригерна_подія>
ON <ім'я_таблиці>
[REFERENCING
<список_старих_або_нових_псевдонімів>]
[FOR EACH { ROW | STATEMENT}]
[WHEN(умова_тригера)]
<тіло_тригера>
тригерні події складаються зі вставки, видалення і оновлення рядків в таблиці. У останньому випадку для тригерної події можна вказати конкретні імена стовпців таблиці. Час запуску тригера визначається за допомогою ключових слів BEFORE ( тригер запускається до виконання пов'язаних з ним подій) або AFTER (після їх виконання).
Виконувані тригером дії задаються для кожного рядка ( FOR EACH ROW ), охопленого цією подією, або тільки один раз для кожної події ( FOR EACH STATEMENT).
Позначення <список_старих_або_нових_псевдонімів> відноситься до таких компонент, як старий або новий рядок ( OLD / NEW ) або стара або нова таблиця ( OLD TABLE / NEW TABLE ). Ясно, що старі значення не застосовні для подій вставки, а нові - для подій видалення.
За умови правильного використання тригери можуть стати дуже потужним механізмом. Основна їх перевага полягає в тому, що стандартні функції зберігаються усередині бази даних і погоджено активізуються при кожному її оновленні. Це може істотно спростити додатки. Проте слід згадати і про присутні тригеру недоліки:
• складність: при переміщенні деяких функцій у базу даних ускладнюються завдання її проектування, реалізації і адміністрування;
• прихована функціональність: перенесення частини функцій у базу даних і збереження їх у вигляді одного або декількох тригерів іноді призводить до приховання від користувача деяких функціональних можливостей. Хоча це певною мірою спрощує його роботу, але, на жаль, може стати причиною незапланованих, потенційно небажаних і шкідливих побічних ефектів, оскільки в цьому випадку користувач не в змозі контролювати усі процеси, що відбуваються у базі даних;
• вплив на продуктивність: перед виконанням кожної команди по зміні стану бази цих СУБД повинна перевірити тригерну умову з метою з'ясування необхідності запуску тригера для цієї команди. Виконання подібних обчислень позначається на загальній продуктивності СУБД, а в моменти пікового навантаження її зниження може стати особливо помітним. Очевидно, що при зростанні кількості тригерів збільшуються і накладні витрати, пов'язані з такими операціями.
Неправильно написані тригери можуть привести до серйозних проблем, таким, наприклад, як поява "мертвих" блокувань. Тригери здатні тривалий час блокувати безліч ресурсів, тому слід звернути особливу увагу на зведення до мінімуму конфліктів доступу.
У реалізації СУБД MS SQL Server використовується наступний оператор створення або зміни тригера :
<Визначення_тригера>::=
{CREATE | ALTER} TRIGGER ім'я_тригера
ON {ім'я_таблиці | ім'я_перегляду }
[WITH ENCRYPTION ]
{
{ { FOR | AFTER | INSTEAD OF }
{ [ DELETE] [,] [ INSERT] [,] [ UPDATE] }
[ WITH APPEND ]
[ NOT FOR REPLICATION ]
AS
sql_оператор[..n]
} |
{ {FOR | AFTER | INSTEAD OF } { [INSERT] [,]
[UPDATE] }
[ WITH APPEND]
[ NOT FOR REPLICATION]
AS
{ IF UPDATE(ім'я_стовпця)
[ {AND | OR} UPDATE(ім'я_стовпця)] [..n]
|
IF (COLUMNS_UPDATES(){оператор_біт_обробки}
біт_маска_зміни)
{оператор_біт_порівняння }біт_маска [..n]}
sql_оператор [..n]}}
Тригер може бути створений тільки в поточній базі даних, але допускається звернення усередині тригера до інших баз даних, у тому числі і розташованим на видаленому сервері.
Розглянемо призначення аргументів з команди CREATE | ALTER TRIGGER.
Ім'я тригера має бути унікальним в межах бази даних. Додатково можна вказати ім'я власника.
При вказівці аргументу WITH ENCRYPTION сервер виконує шифрування коду тригера, щоб ніхто, включаючи адміністратора, не міг отримати до нього доступ і прочитати його. Шифрування часто використовується для приховання авторських алгоритмів обробки даних, що є інтелектуальною власністю програміста або комерційною таємницею.
Типи тригерів
У SQL Server існує два параметри, визначальних поведінку тригерів:
• AFTER. Тригер виконується після успішного виконання команд, що викликали його. Якщо ж команди з якої-небудь причини не можуть бути успішно завершені, тригер не виконується. Слід зазначити, що зміни даних в результаті виконання запиту користувача і виконання тригера здійснюється в тілі однієї транзакції : якщо станеться відкат тригера, то будуть відхилені і призначені для користувача зміни. Можна визначити декілька AFTER -тригерів для кожної операції ( INSERT, UPDATE, DELETE ). Якщо для таблиці передбачено виконання декількох AFTER -тригерів, то за допомогою системної процедури sp_settriggerorder, що зберігається, можна вказати, який з них виконуватиметься першим, а який останнім. За умовчанням в SQL Server усі тригери являються AFTER -тригерами.
• INSTEAD OF. Тригер викликається замість виконання команд. На відміну від AFTER -тригера INSTEAD OF -тригер може бути визначений як для таблиці, так і для перегляду. Для кожної операції INSERT, UPDATE, DELETE можна визначити тільки один INSTEAD OF -тригер.
Тригери розрізняють за типом команд, на які вони реагують.
Існує три типи тригерів :
• INSERT TRIGGER - запускаються при спробі вставки даних за допомогою команди INSERT.
• UPDATE TRIGGER - запускаються при спробі зміни даних за допомогою команди UPDATE.
• DELETE TRIGGER - запускаються при спробі видалення даних за допомогою команди DELETE.
Конструкції [ DELETE] [,] [ INSERT] [,] [ UPDATE] і FOR | AFTER | INSTEAD OF } { [INSERT] [,] [UPDATE] визначають, на яку команду реагуватиме тригер. При його створенні має бути вказана хоч би одна команда. Допускається створення тригера, що реагує на дві або на усі три команди.
Аргумент WITH APPEND дозволяє створювати декілька тригерів кожного типу.
При створенні тригера з аргументом NOT FOR REPLICATION забороняється його запуск під час виконання модифікації таблиць механізмами реплікації.
Конструкція AS sql_оператор[..n] визначає набір SQL - операторів і команд, які будуть виконані при запуску тригера.
Відмітимо, що усередині тригера не допускається виконання ряду операцій, таких, наприклад, як:
• створення, зміна і видалення бази даних;
• відновлення резервної копії бази даних або журналу транзакцій.
Виконання цих команд не дозволене, оскільки вони не можуть бути скасовані у разі відкату транзакції, в якій виконується тригер. Ця заборона навряд чи може якимсь чином позначитися на функціональності створюваних тригерів. Важко знайти таку ситуацію, коли, наприклад, після зміни рядка таблиці потрібно буде виконати відновлення резервної копії журналу транзакцій.
Програмування тригера
При виконанні команд додавання, зміни і видалення записів сервер створює дві спеціальні таблиці: inserted і deleted . В них містяться списки рядків, які будуть вставлені або видалені після закінчення транзакції. Структура таблиць inserted і deleted ідентична структурі таблиць, для якої визначається тригер. Для кожного тригера створюється свій комплект таблиць inserted і deleted, тому ніякий інший тригер не зможе отримати до них доступ. Залежно від типу операції, виконання тригера, що викликала, вміст таблиць inserted і deleted може бути різним:
• команда INSERT - в таблиці inserted містяться усі рядки, які користувач намагається вставити в таблицю; у таблиці deleted не буде жодного рядка; після завершення тригера усі рядки з таблиці inserted перемістяться в початкову таблицю;
• команда DELETE - в таблиці deleted міститимуться усі рядки, які користувач спробує видалити; тригер може перевірити кожен рядок і визначити, чи дозволено її видалення; у таблиці inserted не опиниться жодного рядка;
• команда UPDATE - при її виконанні в таблиці deleted знаходяться старі значення рядків, які будуть видалені при успішному завершенні тригера. Нові значення рядків містяться в таблиці inserted. Ці рядки додадуться в початкову таблицю після успішного виконання тригера.
Для отримання інформації про кількість рядків, яка буде змінено при успішному завершенні тригера, можна використовувати функцію @@ROWCOUNT; вона повертає кількість рядків, оброблених останньою командою. Слід підкреслити, що тригер запускається не при спробі змінити конкретний рядок, а у момент виконання команди зміни. Одна така команда впливає на безліч рядків, тому тригер повинен обробляти усі ці рядки.
Якщо тригер виявив, що з 100 рядків, що вставляються, змінюваних або таких, що видаляються, тільки одна не задовольняє тим або іншим умовам, то ніякий рядок не буде вставлений, змінений або видалений. Така поведінка обумовлена вимогами транзакції - мають бути виконані або усі модифікації, або жодній.
Тригер виконується як неявно певна транзакція, тому усередині тригера допускається застосування команд управління транзакціями. Зокрема, при виявленні порушення обмежень цілісності для переривання виконання тригера і відміни усіх змін, які намагався виконати користувач, необхідно використовувати команду ROLLBACK TRANSACTION.
Для отримання списку стовпців, змінених при виконанні команд INSERT або UPDATE, що викликали виконання тригера, можна використовувати функцію COLUMNS_UPDATED(). Вона повертає двійкове число, кожен біт якого, починаючи з молодшого, відповідає одному стовпцю таблиці (в порядку дотримання стовпців при створенні таблиці). Якщо біт встановлений в значення "1", то відповідний стовпець був змінений. Крім того, факт зміни стовпця визначає і функція UPDATE(ім'я_стовпця).
Для видалення тригера використовується команда
DROP TRIGGER {ім'я_тригера} [,..n]
Наведемо приклади використання тригерів.
Приклад 14.1. Використання тригера для реалізації обмежень на значення. У тій, що додається в таблицю Угода запису кількість проданого товару має бути не більше, ніж його залишок з таблиці Склад.
Команда вставки запису в таблицю Угода може бути, наприклад, такий:
INSERT INTO Угода
VALUES (3,1,-299', 01/08/2002')
Створюваний тригер повинен відреагувати на її виконання таким чином: необхідно відмінити команду, якщо в таблиці Склад величина залишку товару виявилася менше кількості товару, що продавалася, з введеним кодом (у прикладі код товару=3 ). У записі, що вставляється, кількість товару вказується зі знаком "+", якщо товар поставляється, і зі знаком "-", якщо він продається. Представлений тригер налаштований на обробку тільки одного запису, що додається.
CREATE TRIGGER Тригер_ins
ON Угода FOR INSERT
AS
IF @@ROWCOUNT=1
BEGIN
IF NOT EXISTS(SELECT *
FROM inserted
WHERE - inserted.кількість<=ALL(SELECT
Склад.Залишок
FROM Склад, Угода
WHERE Склад.КодТовару=
Угода.КодТовару))
BEGIN
ROLLBACK TRAN
' ' Відміна постачання : товару на складі немає
END
END
Приклад 14.1. Використання тригера для реалізації обмежень на значення.
Приклад 14.2. Використання тригера для збору статистичних даних.
Створити тригер для обробки операції вставки запису в таблицю Угода, наприклад, такої команди:
INSERT INTO Угода
VALUES (3,1,200', 01/08/2002')
поставляється товар з кодом 3 від клієнта з кодом 1 у кількості 200 одиниць.
При продажі або отриманні товару необхідно відповідним чином змінити кількість його складського запасу. Якщо товару на складі ще немає, необхідно додати відповідний запис в таблицю Склад. Тригер обробляє тільки один рядок, що додається.
ALTER TRIGGER Тригер_ins
ON Угода FOR INSERT
AS
DECLARE @x INT, @y INT
IF @@ROWCOUNT=1
----у таблицю Угода додається запис
----про постачання товару
BEGIN
----кількість проданого товару має бути не
----менше, ніж його залишок з таблиці Склад
IF NOT EXISTS(SELECT *
FROM inserted
WHERE - inserted.кількість<
=ALL(SELECT Склад.Залишок
FROM Склад, Угода
WHERE Склад.КодТовару=
Угода.КодТовару))
BEGIN
ROLLBACK TRAN
PRINT 'відкату товару немає '
END
----якщо запису про поставлений товар ще немає
----додається відповідний запис
----у таблицю Склад
IF NOT EXISTS ( SELECT *
FROM Склад З, inserted i
WHERE С. КодТовару=i.КодТовару )
INSERT INTO Склад (КодТовару, Залишок)
ELSE
----якщо запис про товар вже був в таблиці
----Склад, то визначається код і кількість
----товару з доданої в таблицю Угода запису
BEGIN
SELECT @y=i.КодТовару, @x=i.Кількість
FROM Угода З, inserted i
WHERE С. КодТовару=i.КодТовару
----і робиться зміни кількості товару в
----таблиці Склад
UPDATE Склад
SET Залишок=залишок+@x
WHERE КодТовару=@y
END
END
Приклад 14.2. Використання тригера для збору статистичних даних.
Приклад 14.3. Створити тригер для обробки операції видалення запису з таблиці Угода, наприклад, такої команди:
DELETE FROM Угода WHERE КодУгоди=4
Для товару, код якого вказаний при видаленні запису, необхідно відкоригувати його залишок на складі. Тригер обробляє тільки один запис, що видаляється.
CREATE TRIGGER Тригер_del
ON Угода FOR DELETE
AS
IF @@ROWCOUNT=1 -- видалена один запис
BEGIN
DECLARE @y INT,@x INT
----визначається код і кількість товару з
----видаленою з таблиці Склад запису
SELECT @y=КодТовару, @x=Кількість
FROM deleted
----у таблиці Склад коригується кількість
----товару
UPDATE Склад
SET Залишок=Залишок-@x
WHERE КодТовару=@y
END
Приклад 14.3. Тригер для обробки операції видалення запису з таблиці
Приклад 14.4. Створити тригер для обробки операції зміни запису в таблиці Угода, наприклад, такою командою:
UPDATE Угода SET кількість=кількість-10
WHERE КодТовару=3
у усіх угодах з товаром, що має код, рівний 3, зменшити кількість товару на 10 одиниць.
Вказана команда може привести до зміни відразу декількох записів в таблиці Угода. Тому покажемо, як створити тригер, оброблювальний не один запис. Для кожного зміненого запису необхідно для старого (до зміни) коду товару зменшити залишок товару на складі на величину старої (до зміни) кількості товару і для нового (після зміни) коду товару збільшити його залишок на складі на величину нового (після зміни) значення. Щоб обробити усі змінені записи, введемо курсори, в яких збережемо усі старі (з таблиці deleted ) і усі нові значення (з таблиці inserted ).
CREATE TRIGGER Тригер_upd
ON Угода FOR UPDATE
AS
DECLARE @x INT, @x_old INT, @y INT, @y_old INT
-- -- курсор з новими значеннями
DECLARE CUR1 CURSOR FOR
SELECT КодТовару, Кількість
FROM inserted
-- -- курсор із старими значеннями
DECLARE CUR2 CURSOR FOR
SELECT КодТовару, Кількість
FROM deleted
OPEN CUR1
OPEN CUR2
-- -- переміщаємося паралельно по обох курсорах
FETCH NEXT FROM CUR1 INTO @x, @y
FETCH NEXT FROM CUR2 INTO @x_old, @y_old
WHILE @@FETCH_STATUS=0
BEGIN
----для старого коду товару зменшується його
----кількість на складі
UPDATE Склад
SET Залишок=Залишок-@y_old
WHERE КодТовару=@x_old
----для нового коду товару, якщо такого товару
----ще немає на складі, вводиться новий запис
IF NOT EXISTS (SELECT * FROM Склад
WHERE КодТовару=@x)
INSERT INTO Склад(КодТовару, Залишок)
VALUES (@x,@y)
ELSE
----інакше для нового коду товару збільшується
----його кількість на складі
UPDATE Склад
SET Залишок=Залишок+@y
WHERE КодТовару=@x
FETCH NEXT FROM CUR1 INTO @x, @y
FETCH NEXT FROM CUR2 INTO @x_old, @y_old
END
CLOSE CUR1
CLOSE CUR2
DEALLOCATE CUR1
DEALLOCATE CUR2
Приклад 14.4. тригер для обробки операції зміни запису в таблиці
У розглянутому тригері відсутнє порівняння кількості товару при зміні запису про угоду з його залишком на складі.
Приклад 14.5. Поправний цей недолік. Для генерування повідомлення про помилку використовуємо в тілі тригера команду MS SQL Server RAISERROR, аргументами якої є текст повідомлення, рівень серйозності і статус помилки.
ALTER TRIGGER Тригер_upd
ON Угода FOR UPDATE
AS
DECLARE @x INT, @x_old INT, @y INT,
@y_old INT,@o INT
DECLARE CUR1 CURSOR FOR
SELECT КодТовару, Кількість
FROM inserted
DECLARE CUR2 CURSOR FOR
SELECT КодТовару, Кількість
FROM deleted
OPEN CUR1
OPEN CUR2
FETCH NEXT FROM CUR1 INTO @x, @y
FETCH NEXT FROM CUR2 INTO @x_old, @y_old
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @o=залишок
FROM Склад
WHERE КодТовару=@x
IF @o<-@y
BEGIN
RAISERROR('відкат', 16,10)
CLOSE CUR1
CLOSE CUR2
DEALLOCATE CUR1
DEALLOCATE CUR2
ROLLBACK TRAN
RETURN
END
UPDATE Склад
SET Залишок=Залишок-@y_old
WHERE КодТовару=@x_old
IF NOT EXISTS (SELECT * FROM Склад
WHERE КодТовару=@x)
INSERT INTO Склад(КодТовару, Залишок)
VALUES (@x,@y)
ELSE
UPDATE Склад
SET Залишок=Залишок+@y
WHERE КодТовару=@x
FETCH NEXT FROM CUR1 INTO @x, @y
FETCH NEXT FROM CUR2 INTO @x_old, @y_old
END
CLOSE CUR1
CLOSE CUR2
DEALLOCATE CUR1
DEALLOCATE CUR2
Приклад 14.5. Виправлений варіант тригера для обробки операції зміни запису в таблиці
Приклад 14.6. У прикладі 14.5 відбувається відміна усіх змін при неможливості реалізувати хоч би одно з них. Створимо тригер, що дозволяє відміняти зміну тільки деяких записів і виконувати зміну інших.
В цьому випадку тригер виконується не після зміни записів, а замість команди зміни.
ALTER TRIGGER Тригер_upd
ON Угода INSTEAD OF UPDATE
AS
DECLARE @k INT, @k_old INT
DECLARE @x INT, @x_old INT, @y INT
DECLARE @y_old INT,@o INT
DECLARE CUR1 CURSOR FOR
SELECT КодУгоди, КодТовару, Кількість
FROM inserted
DECLARE CUR2 CURSOR FOR
SELECT КодУгоди, КодТовару, Кількість
FROM deleted
OPEN CUR1
OPEN CUR2
FETCH NEXT FROM CUR1 INTO @k,@x, @y
FETCH NEXT FROM CUR2 INTO @k_old,@x_old
@y_old
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @o=залишок
FROM Склад
WHERE КодТовару=@x
IF @o>=-@y
BEGIN
RAISERROR('зміна', 16,10)
UPDATE Угода SET кількість=@y,
КодТовару=@x
WHERE КодУгоди=@k
UPDATE Склад
SET Залишок=Залишок-@y_old
WHERE КодТовару=@x_old
IF NOT EXISTS (SELECT * FROM Склад
WHERE КодТовару=@x)
INSERT INTO Склад(КодТовару, Залишок)
VALUES (@x,@y)
ELSE
UPDATE Склад
SET Залишок=Залишок+@y
WHERE КодТовару=@x
END
ELSE
RAISERROR('запис не змінений', 16,10)
FETCH NEXT FROM CUR1 INTO @k,@x, @y
FETCH NEXT FROM CUR2 INTO @k_old,@x_old
@y_old
END
CLOSE CUR1
CLOSE CUR2
DEALLOCATE CUR1
DEALLOCATE CUR2
Приклад 14.6. Тригер, що дозволяє відміняти зміну тільки деяких записів і виконувати зміну інших.
Розглянемо створення таблиці, що реалізовує рекурсивну ієрархію, на прикладі даних, що описують стосунки підлеглості між співробітниками. У таблиці emp_mgr необхідно задати як ім'я співробітника ( emp ), так і ім'я його начальника ( mgr ). Для рекурсивного зв'язку одна і та ж суть є і батьківською, і дочірньою. При заданому рекурсивному зв'язку атрибут первинного ключа мігрує в якості зовнішнього ключа до складу неключових атрибутів тієї ж суті (атрибути emp - співробітник і mgr - начальник таблиці emp_mgr ). Інформація про керівника міститься в тій же суті, оскільки керівник - співробітник тієї ж організації. Зв'язок керує/підкоряється ( fk_emp ) дозволяє зберігати деревовидну ієрархію підлеглості. Такий вид рекурсивного зв'язку називається ієрархічною рекурсією і задає зв'язок, коли керівник (екземпляр батьківської суті) може мати безліч підлеглих (екземплярів дочірньої суті), але підлеглий - тільки одного керівника. У середовищі MS SQL Server створимо таблицю emp_mgr :
CREATE TABLE emp_mgr
( (emp CHAR(2) PRIMARY KEY
mgr CHAR(2) NULL
NoOfReports INT DEFAULT 0
CONSTRAINT fk_emp FOREIGN KEY (mgr)
REFERENCES emp_mgr (emp))
У таблицю введено поле NoOfReports, в якому для кожного співробітника визначена кількість його підлеглих.
Для зручності ілюстрації в якості імені співробітника і його начальника використовуватимуться латинські букви. Наприклад, введення даних в таблицю здійснюється операторами:
INSERT INTO emp_mgr(emp, mgr) VALUES('a ', NULL)
INSERT INTO emp_mgr(emp, mgr) VALUES('b ',' a')
INSERT INTO emp_mgr(emp, mgr) VALUES('c ',' a')
INSERT INTO emp_mgr(emp, mgr) VALUES('d ',' a')
INSERT INTO emp_mgr(emp, mgr) VALUES('e ',' b')
INSERT INTO emp_mgr(emp, mgr) VALUES('f ',' b')
INSERT INTO emp_mgr(emp, mgr) VALUES('g ',' b')
INSERT INTO emp_mgr(emp, mgr) VALUES('i ',' c')
INSERT INTO emp_mgr(emp, mgr) VALUES('k ',' d')
Після введення даних в таблицю emp_mgr оператор SELECT * FROM emp_mgr повертає наступний результат:
emp mgr NoOfReports
-------------------------
a NULL 3
b a 3
c a 1
d a 1
e b 0
f b 0
g b 0
i c 0
k d 0
Цілісність, несуперечність і достовірність інформації в таблицях з рекурсивними зв'язками забезпечуються виконанням ряду правил :
1. Кожен співробітник має тільки одного керівника.
2. Кожен співробітник не є сам собі керівником.
3. Кожен керівник в першу чергу співробітник.
4. Є тільки один співробітник (директор організації), який нікому не підкоряється.
5. Правило 2 необхідно посилити. Кожен співробітник не повинен знаходитися в ролі власного керівника не лише безпосередньо, але і опосередкований, через інших співробітників.
Виконання правила 1 забезпечується обмеженням первинного ключа і не вимагає додаткових SQL -операторів.
Розглянемо правило 2. Імена співробітника і його начальника в одному записі не повинні співпадати. При додаванні і зміні запису в таблиці emp_mgr ця вимога пред'являється до нового запису, який до підтвердження транзакції розташовується в тимчасовій таблиці з ім'ям inserted. Цьому правилу відповідають наступні SQL -оператори:
IF EXISTS (SELECT * FROM inserted
WHERE mgr=emp)
BEGIN
ROLLBACK TRAN
RAISERROR('САМ СЕБЕ НАЧАЛЬНИК', 16,10)
RETURN
END
Правило 3 говорить про те, що ім'ям начальника може бути тільки вже внесене в таблицю ім'я співробітника. Ця вимога є декларативною посилальною цілісністю і забезпечується обмеженням зовнішнього ключа. Проте, щоб запустити механізм тригерів, доведеться видалити обмеження зовнішнього ключа і його функцію покласти на тригер.
У новому або зміненому записі ім'я начальника має бути вказане і вже бути присутнім в таблиці в якості імені співробітника, що може бути записано наступними SQL -операторами:
IF EXISTS(SELECT * FROM inserted
WHERE mgr IS NOT NULL) AND
NOT EXISTS(SELECT * FROM inserted, emp_mgr
WHERE emp_mgr.emp=inserted.mgr)
BEGIN
RAISERROR('НЕМАЄ НАЧАЛЬНИКА', 16,10)
ROLLBACK TRAN
RETURN
END
чи (що еквівалентно)
IF NOT EXISTS(SELECT * FROM emp_mgr, inserted
WHERE emp_mgr.emp=inserted.mgr
OR inserted.mgr IS NULL)
BEGIN
RAISERROR('НЕМАЄ НАЧАЛЬНИКА', 16,10)
ROLLBACK TRAN
RETURN
END
Відповідно до правила 4 необхідно перевірити, чи введений запис про директора (співробітнику, у якого немає начальника). Якщо такий запис вже є, введення нового директора забороняється за допомогою наступних SQL -операторів:
IF EXISTS (SELECT * FROM inserted
WHERE mgr IS NULL)
AND EXISTS
( (SELECT * FROM emp_mgr, inserted
WHERE emp_mgr.mgr IS NULL
AND emp_mgr.emp<>inserted.emp)
BEGIN
ROLLBACK TRAN
RAISERROR('ОДИН ДИРЕКТОР ВЖЕ Є', 16,10)
RETURN
END
Оператор UPDATE може змінити ієрархічну структуру таким чином, що виникає ситуація, коли співробітник стає начальником самому собі через інших співробітників, тобто в ієрархії підлеглості виникає петля. Для виключення подібних перетворень використовуваний SQL -оператори:
IF UPDATE(mgr)--змінився начальник
BEGIN
DECLARE @x CHAR(2), @y CHAR(2), @xx CHAR(2)
----упізнали ім'я співробітника
----у якого змінився начальник
SELECT @xx=inserted.emp FROM inserted
SELECT @x=@xx
SELECT @y='*'
WHILE @y IS NOT NULL
----поки не дійшли до директора
BEGIN
----запам'ятали ім'я начальника
SELECT @y=mgr FROM emp_mgr
WHERE emp=@x
IF @xx=@y
----ім'я співробітника і його начальника співпали
BEGIN
RAISERROR('транзитивне замикання', 16,10)
ROLLBACK TRAN
RETURN
END
ELSE
----далі начальник стає співробітником
----і в циклі шукатимемо його начальника
SELECT @x=@y
END
END
Щоб спрацювали тригери, необхідно видалити обмеження зовнішнього ключа :
ALTER TABLE emp_mgr DROP CONSTRAINT fk_emp
Нижче приведений текст тригерів, що підтримують цілісність даних в ієрархічних структурах. Передбачається, що тригери обробляють введення, зміну або видалення одного запису.
ALTER TRIGGER emp_ins
ON emp_mgr FOR INSERT
AS
----Правило 2
IF EXISTS (SELECT * FROM inserted WHERE mgr=emp)
BEGIN
ROLLBACK TRAN
RAISERROR('САМ СЕБЕ НАЧАЛЬНИК', 16,10)
RETURN
END
----Правило 4
IF EXISTS (SELECT * FROM inserted WHERE mgr IS NULL) AND
EXISTS (SELECT * FROM emp_mgr, inserted
WHERE emp_mgr.mgr IS NULL
AND emp_mgr.emp<>inserted.emp)
BEGIN
ROLLBACK TRAN
RAISERROR('ОДИН ДИРЕКТОР ВЖЕ Є', 16,10)
RETURN
END
----Правило 3
IF EXISTS(SELECT * FROM inserted
WHERE mgr IS NOT NULL) AND
NOT EXISTS(SELECT * FROM inserted, emp_mgr
WHERE emp_mgr.emp=inserted.mgr)
BEGIN
RAISERROR('НЕМАЄ ТАКОГО НАЧАЛЬНИКА', 16,10)
ROLLBACK TRAN
RETURN
END
----Перерахунок числа підлеглих у начальника
----доданого підлеглого
DECLARE @e CHAR(2), @m CHAR(2)
SELECT @e=emp_mgr.emp FROM emp_mgr, inserted
WHERE emp_mgr.emp=inserted.mgr
UPDATE emp_mgr
SET emp_mgr.NoOfReports=emp_mgr.NoOfReports+1
WHERE emp_mgr.emp=@e
Приклад 15.1. Тригер для додавання запису в таблицю.
CREATE TRIGGER emp_upd ON emp_mgr
FOR UPDATE
AS
IF UPDATE(mgr)
BEGIN
----Правило 5
DECLARE @x CHAR(2), @y CHAR(2), @xx CHAR(2)
SELECT @xx=inserted.emp FROM inserted
SELECT @x=@xx
SELECT @y='*'
WHILE @y IS NOT NULL
BEGIN
SELECT @y=mgr FROM emp_mgr WHERE emp=@x
IF @xx=@y
BEGIN
RAISERROR('транзитивне замикання', 16,10)
ROLLBACK TRAN
RETURN
END
ELSE
SELECT @x=@y
END
END
----Правило 2
IF EXISTS (SELECT * FROM inserted WHERE mgr=emp)
BEGIN
ROLLBACK TRAN
RAISERROR('САМ СЕБЕ НАЧАЛЬНИК', 16,10)
RETURN
END
----Правило 4
IF EXISTS (SELECT * FROM inserted WHERE mgr
IS NULL) AND EXISTS (SELECT *
FROM emp_mgr, inserted WHERE emp_mgr.mgr IS NULL
AND emp_mgr.emp<>inserted.emp)
BEGIN
ROLLBACK TRAN
RAISERROR('ОДИН ДИРЕКТОР ВЖЕ Є', 16,10)
RETURN
END
----Правило 3
IF UPDATE(mgr)
IF NOT EXISTS(SELECT * FROM emp_mgr, inserted
WHERE emp_mgr.emp=inserted.mgr
OR inserted.mgr IS NULL)
BEGIN
RAISERROR('НЕМАЄ ТАКОГО НАЧАЛЬНИКА', 16,10)
ROLLBACK TRAN
RETURN
END
IF UPDATE(mgr)
----перерахунок числа підлеглих у старого і нового
----начальників
BEGIN
UPDATE emp_mgr
SET emp_mgr.NoOfReports=emp_mgr.NoOfReports+1
FROM inserted WHERE emp_mgr.emp=inserted.mgr
UPDATE emp_mgr
SET emp_mgr.NoOfReports=emp_mgr.NoOfReports - 1
FROM deleted WHERE emp_mgr.emp=deleted.mgr
END
IF UPDATE(emp)
----якщо змінилося ім'я співробітника, слід змінити
----ім'я начальника у усіх його підлеглих
UPDATE emp_mgr SET emp_mgr.mgr=inserted.emp
FROM emp_mgr, inserted, deleted WHERE
emp_mgr.mgr=deleted.emp
Приклад 15.2. Тригер для зміни запису в таблиці.
Спроба підпорядкувати співробітника з ім'ям 'b' начальникові з ім'ям 'e' буде сервером знехтувана, інакше в організації склалася б така ситуація: співробітник 'e' підкорятимуться співробітникові 'b ', а співробітник 'b' підкоряється співробітникові 'e'.
UPDATE emp_mgr SET mgr='e' WHERE emp='b'
Server: Msg 50000, Level 16, State 10
Procedure emp_upd,
Line 15 транзитивне замикання
Виконання команди
UPDATE emp_mgr SET mgr='f' WHERE emp='e'
і команди
UPDATE emp_mgr SET mgr='a' WHERE emp='g'
приведе до наступної зміни первинної ієрархічної структури :
emp mgr NoOfReports
-------------------------
a NULL 4
b a 1
c a 1
d a 1
e f 0
f b 1
g a 0
i c 0
k d 0
ALTER TRIGGER emp_del
ON emp_mgr
FOR DELETE
AS
DECLARE @e CHAR(2), @m CHAR(2), @r INT
SELECT @e=emp,@m=mgr,@r=NoOfReports FROM deleted
IF @m IS NOT NULL
-- -- віддаляється співробітник, що не є директором
BEGIN
IF @r=0
-- -- віддаляється співробітник, у якого немає підлеглих
-- -- зменшується число підлеглих у начальника
-- -- співробітника, що видаляється
UPDATE emp_mgr SET NoOfReports=
NoOfReports - 1
WHERE emp=@m
ELSE
BEGIN
-- -- віддаляється співробітник, у якого є підлеглі
-- -- перепідпорядкуємо його підлеглих його начальникові
-- -- тобто начальником підлеглих співробітника, що видаляється
-- -- стає його начальник
UPDATE emp_mgr SET NoOfReports=
NoOfReports+@r - 1
WHERE emp=@m
UPDATE emp_mgr SET mgr=@m
WHERE mgr=@e
END
END
ELSE
-- -- Правило 4
IF EXISTS(SELECT * FROM emp_mgr)
BEGIN
ROLLBACK TRAN
RAISERROR(НЕ 'МОЖНА ВИДАЛЯТИ
ДИРЕКТОРИ', 16,10)
RETURN
END
Приклад 15.3. Тригер для видалення запису з таблиці.
Спроба видалення запису про директора буде знехтувана сервером:
DELETE FROM emp_mgr WHERE emp='a'
Server: Msg 50000, Level 16, State 10
Procedure emp_del, Line 24
НЕ МОЖНА ВИДАЛЯТИ ДИРЕКТОРА
В результаті видалення рядового співробітника з ім'ям b його підлеглі e, f і g стануть підпорядкованими співробітника з ім'ям a.
DELETE FROM emp_mgr WHERE emp='b'
Первинний вміст таблиці emp_mgr зміниться таким чином:
emp mgr NoOfReports
-------------------------
a NULL 5
c a 1
d a 1
e a 0
f a 0
g a 0
i c 0
k d 0
Концепція транзакцій - невід'ємна частина будь-якої клієнт-серверної бази даних.
Під транзакцією розуміється неділима з точки зору дії на БД послідовність операторів маніпулювання даними (читання, видалення, вставки, модифікації), що призводить до одного з двох можливих результатів : або послідовність виконується, якщо усі оператори правильні, або уся транзакція відкочується, якщо хоч би один оператор не може бути успішно виконаний. Обробка транзакцій гарантує цілісність інформації у базі даних. Таким чином, транзакція переводить базу даних з одного цілісного стану в інше.
Підтримка механізму транзакцій - показник рівня розвиненості СУБД. Коректна підтримка транзакцій одночасно є основою забезпечення цілісності БД. Транзакції також складають основу ізольованості в розрахованих на багато користувачів системах, де з однією БД паралельно можуть працювати декілька користувачів або прикладних програм. Одне з основних завдань СУБД - забезпечення ізольованості, тобто створення такого режиму функціонування, при якому кожному користувачеві здавалося б, що БД доступна тільки йому. Таке завдання СУБД прийнято називати паралелізмом транзакцій.
Більшість виконуваних дій робляться в тілі транзакцій. За умовчанням кожна команда виконується як самостійна транзакція. При необхідності користувач може явно вказати її початок і кінець, щоб мати можливість включити в неї декілька команд.
При виконанні транзакції система управління базами даних повинна дотримуватися певних правил обробки набору команд, що входять в транзакцію. Зокрема, розроблено чотири правила, відомі як вимоги ACID, вони гарантують правильність і надійність роботи системи.
Характеристики транзакцій описуються в термінах ACID (Atomicity, Consistency, Isolation, Durability - неподільність, узгодженість, ізольованість, стійкість ).
• Транзакція неділима в тому сенсі, що є єдиним цілим. Усі її компоненти або мають місце, або немає. Не буває часткової транзакції. Якщо може бути виконана лише частина транзакції, вона відхиляється.
• Транзакція є погодженою, тому що не порушує бізнес-логіку і стосунки між елементами даних. Ця властивість дуже важлива при розробці клієнт-серверних систем, оскільки в сховище даних поступає велика кількість транзакцій від різних систем і об'єктів. Якщо хоч би одна з них порушить цілісність даних, то усі інші можуть видати невірні результати.
• Транзакція завжди ізольована, оскільки її результати самодостатні. Вони не залежать від попередніх або наступних транзакцій - ця властивість називається серіалізуємістю і означає, що транзакції в послідовності незалежні.
• Транзакція стійка. Після свого завершення вона зберігається в системі, яку ніщо не може повернути в початковий (до початку транзакції ) стан, тобто відбувається фіксація транзакції, що означає, що її дія постійно навіть при збої системи. При цьому мається на увазі деяка форма зберігання інформації в постійній пам'яті як частина транзакції .
Вказані вище за правило виконує сервер. Програміст лише вибирає потрібний рівень ізоляції, піклується про дотримання логічної цілісності даних і бізнес-правил. На нього покладаються обов'язки по створенню ефективних і логічно вірних алгоритмів обробки даних. Він вирішує, які команди повинні виконуватися як одна транзакція, а які можуть бути розбиті на декілька послідовно виконуваних транзакцій. Слід по можливості використовувати невеликі транзакції, тобто що включають якомога менше команд і змінюють мінімум даних. Дотримання цієї вимоги дозволить найбільш ефективним чином забезпечити одночасну роботу з даними безлічі користувачів.
Підвищення ефективності роботи при використанні невеликих транзакцій пов'язане з тим, що при виконанні транзакції сервер накладає на ці блокування.
Блокуванням називається тимчасове обмеження на виконання деяких операцій обробки даних. Блокування може бути накладене як на окремий рядок таблиці, так і на усю базу даних. Управлінням блокуваннями на сервері займається менеджер блокувань, контролюючий їх застосування і вирішення конфліктів. Транзакції і блокування тісно пов'язані один з одним. Транзакції накладають блокування на дані, щоб забезпечити виконання вимог ACID. Без використання блокувань декілька транзакцій могли б змінювати одні і ті ж дані.
Блокування є методом управління паралельними процесами, при якому об'єкт БД не може бути модифікований без відома транзакції, тобто відбувається блокування доступу до об'єкту з боку інших транзакцій, чим виключається непередбачувана зміна об'єкту. Розрізняють два види блокування :
• блокування запису - транзакція блокує рядки в таблицях таким чином, що запит іншої транзакції до цих рядків буде скасований ;
• блокування читання - транзакція блокує рядки так, що запит з боку іншої транзакції на блокування запису цих рядків буде знехтуваний, а на блокування читання - прийнятий.
У СУБД використовують протокол доступу до даних, що дозволяє уникнути проблеми паралелізму. Його суть полягає в наступному:
• транзакція, результатом дії якої на рядок даних в таблиці являється її витягання, зобов'язана накласти блокування читання на цей рядок;
• транзакція, призначена для модифікації рядка даних, накладає на неї блокування запису;
• якщо прошене блокування на рядок відкидається із-за вже наявного блокування, то транзакція переводиться в режим очікування до тих пір, поки блокування не буде знято;
• блокування запису зберігається аж до кінця виконання транзакції.
Вирішення проблеми паралельної обробки БД полягає в тому, що рядки таблиць блокуються, а наступні транзакції, модифікуючі ці рядки, відкидаються і переводяться в режим очікування. У зв'язку з властивістю збереження цілісності БД транзакції є відповідними одиницями ізольованості користувачів. Дійсно, якщо кожен сеанс взаємодії з базою даних реалізується транзакцією, то користувач починає з того, що звертається до погодженого стану бази даних - стану, в якому вона могла б знаходитися, навіть якщо б користувач працював з нею самостійно.
Якщо в системі управління базами даних не реалізовані механізми блокування, то при одночасному читанні і зміні одних і тих же даних декількома користувачами можуть виникнути наступні проблеми одночасного доступу :
• проблема останньої зміни виникає, коли декілька користувачів змінюють один і той же рядок, ґрунтуючись на її початковому значенні; тоді частина даних буде втрачена, оскільки кожна наступна транзакція перезапише зміни, зроблені попередньою. Вихід з цієї ситуації полягає в послідовному внесенні змін;
• проблема "брудного" читання можлива у тому випадку, якщо користувач виконує складні операції обробки даних, що вимагають множинної зміни даних перед тим, як вони набудуть логічно вірного стану. Якщо під час зміни даних інший користувач прочитуватиме їх, то може виявитися, що він отримає логічно невірну інформацію. Для виключення подібних проблем необхідно робити зчитування даних після закінчення усіх змін;
• проблема неповторюваного читання є наслідком неодноразового зчитування транзакцією одних і тих же даних. Під час виконання першої транзакції інша може внести в ці зміни, тому при повторному читанні перша транзакція отримає вже інший набір даних, що призводить до порушення їх цілісності або логічної неузгодженості;
• проблема читання фантомів з'являється після того, як одна транзакція вибирає дані з таблиці, а інша вставляє або видаляє рядки до завершення першої. Вибрані з таблиці значення будуть некоректні.
Для вирішення перерахованих проблем в спеціально розробленому стандарті визначено чотири рівні блокування. Рівень ізоляції транзакції визначає, чи можуть інші (що конкурують) транзакції вносити зміни в дані, змінені поточною транзакцією, а також чи може поточна транзакція бачити зміни, зроблені конкуруючими транзакціями, і навпаки. Кожен наступний рівень підтримує вимоги попереднього і накладає додаткові обмеження:
• рівень 0 - заборона "забруднення" даних. Цей рівень вимагає, щоб змінювати дані могла тільки одна транзакція ; якщо іншій транзакції необхідно змінити ті ж дані, вона повинна чекати завершення першої транзакції ;
• рівень 1 - заборона "брудного" читання. Якщо транзакція почала зміну даних, то ніяка інша транзакція не зможе прочитати їх до завершення першої;
• рівень 2 - заборона неповторюваного читання. Якщо транзакція прочитує дані, то ніяка інша транзакція не зможе їх змінити. Таким чином, при повторному читанні вони знаходитимуться в первинному стані;
• рівень 3 - заборона фантомів. Якщо транзакція звертається до даних, то ніяка інша транзакція не зможе додати нові або видалити рядки, що мають, які можуть бути лічені при виконанні транзакції. Реалізація цього рівня блокування виконується шляхом використання блокувань діапазону ключів. Схоже блокування накладається не на конкретні рядки таблиці, а на рядки, що задовольняють певній логічній умові.
Під управлінням транзакціями розуміється здатність управляти різними операціями над даними, які виконуються усередині реляційної СУБД. Передусім, мається на увазі виконання операторів INSERT, UPDATE і DELETE. Наприклад, після створення таблиці (виконання оператора CREATE TABLE ) не треба фіксувати результат: створення таблиці фіксується у базі даних автоматично. Так само за допомогою відміни транзакції не вдасться відновити тільки що видалену оператором DROP TABLE таблицю.
Після успішного виконання команд, поміщених в тіло однієї транзакції, негайної зміни даних не відбувається. Для остаточного завершення транзакції існують так звані команди управління транзакціями, за допомогою яких можна або зберегти у базі даних усі зміни, що сталися в ході її виконання, або повністю їх відмінити.
Існують три команди, які використовуються для управління транзакціями:
• COMMIT - для збереження змін ;
• ROLLBACK - для відміни змін ;
• SAVEPOINT - для установки особливих точок повернення.
Після завершення транзакції уся інформація про зроблені зміни зберігається або в спеціально виділеній оперативній пам'яті, або в тимчасовій області відкату в самій базі даних до тих пір, поки не буде виконана одна з команд управління транзакціями. Потім усі зміни або фіксуються у базі даних, або відкидаються, а тимчасова область відкату звільняється.
Команда COMMIT призначена для збереження у базі даних усіх змін, що сталися в ході виконання транзакції. Вона зберігає результати усіх операцій, які мали місце після виконання останньої команди COMMIT або ROLLBACK .
Команда ROLLBACK призначена для відміни транзакцій, ще не збережених у базі даних. Вона відміняє тільки ті транзакції, які були виконані з моменту видачі останньої команди COMMIT або ROLLBACK .
Команда SAVEPOINT (точка збереження) призначена для установки в транзакції особливих точок, куди надалі може бути зроблений відкат (при цьому відкату всієї транзакції не відбувається). Команда має наступний вигляд:
SAVEPOINT ім'я_точки_збереження
Вона служить виключно для створення точок збереження серед операторів, призначених для зміни даних. Ім'я точки збереження в пов'язаній з нею групі транзакцій має бути унікальним.
Для відміни дії групи транзакцій, обмежених точками збереження, використовується команда ROLLBACK з наступним синтаксисом:
ROLLBACK TO ім'я_точки_збереження
Оскільки за допомогою команди SAVEPOINT велике число транзакцій може бути розбите на менші і тому більше керовані групи, її застосування є одним із способів управління транзакціями.
Визначення транзакцій
SQL Server пропонує безліч засобів управління поведінкою транзакцій. Користувачі в основному повинні вказувати тільки почало і кінець транзакції, використовуючи команди SQL або API (прикладного інтерфейсу програмування). Транзакція визначається на рівні з'єднання з базою даних і при закритті з'єднання автоматично закривається. Якщо користувач спробує встановити з'єднання знову і продовжити виконання транзакції, то це йому не вдасться. Коли транзакція починається, усі команди, виконані в з'єднанні, вважаються тілом однієї транзакції, поки не буде досягнутий її кінець.
SQL Server підтримує три види визначення транзакцій :
• явне ;
• автоматичне;
• що мається на увазі.
За умовчанням SQL Server працює в режимі автоматичного початку транзакцій, коли кожна команда розглядається як окрема транзакція. Якщо команда виконана успішно, то її зміни фіксуються. Якщо при виконанні команди сталася помилка, то зроблені зміни відміняються і система повертається в первинний стан.
Коли користувачеві знадобиться створити транзакцію, що включає декілька команд, він повинен явно вказати транзакцію.
Сервер працює тільки в одному з двох режимів визначення транзакцій : автоматичному або такому, що мається на увазі. Він не може знаходитися в режимі виключно явного визначення транзакцій. Цей режим працює поверх двох інших.
Для установки режиму автоматичного визначення транзакцій використовується команда:
SET IMPLICIT_TRANSACTIONS OFF
При роботі в режимі неявного (що мається на увазі) початку транзакцій SQL Server автоматично починає нову транзакцію, як тільки завершена попередня. Установка режиму визначення транзакцій, що мається на увазі, виконується за допомогою іншої команди:
SET IMPLICIT_TRANSACTIONS ON
Явні транзакції
Явні транзакції вимагають, щоб користувач вказав початок і кінець транзакції, використовуючи наступні команди:
• початок транзакції : в журналі транзакцій фіксуються первинні значення змінюваних даних і момент початку транзакції ;
• BEGIN TRAN[SACTION]
• [ім'я_транзакції |
• @ім'я_змінної_транзакції
[WITH MARK ['опис_транзакції']]]
• кінець транзакції : якщо в тілі транзакції не було помилок, то ця команда наказує серверу зафіксувати усі зміни, зроблені в транзакції, після чого в журналі транзакцій позначається, що зміни зафіксовані і транзакція завершена;
• COMMIT [TRAN[SACTION]
• [ім'я_транзакції |
@ім'я_змінної_транзакції]]
• створення усередині транзакції точки збереження : СУБД зберігає стан БД в поточній точці і привласнює збереженому стану ім'я точки збереження;
• SAVE TRAN[SACTION]
• {ім'я_точки_сохранеия |
@ім'я_змінної_точки_збереження}
• переривання транзакції ; коли сервер зустрічає цю команду, відбувається відкат транзакції, відновлюється первинний стан системи і в журналі транзакцій відмічається, що транзакція була скасована. Приведена нижче команда відміняє усі зміни, зроблені у БД після оператора BEGIN TRANSACTION або відміняє зміни, зроблені у БД після точки збереження, повертаючи транзакцію до місця, де був виконаний оператор SAVE TRANSACTION.
• ROLLBACK [TRAN[SACTION]
• [ім'я_транзакції |
• @ім'я_змінної_транзакції
• | ім'я_точки_збереження
|@ім'я_змінної_точки_збереження]]
Функція @@TRANCOUNT повертає кількість активних транзакцій.
Функція @@NESTLEVEL повертає рівень вкладеності транзакцій.
BEGIN TRAN
SAVE TRANSACTION point1
Приклад 16.1. Використання точок збереження
У точці point1 зберігається первинний стан таблиці Товар
DELETE FROM Товар WHERE КодТовару=2
SAVE TRANSACTION point2
У точці point2 зберігається стан таблиці Товар без товарів з кодом 2.
DELETE FROM Товар WHERE КодТовару=3
SAVE TRANSACTION point3
У точці point3 зберігається стан таблиці Товар без товарів з кодом 2 і з кодом 3.
DELETE FROM Товар WHERE КодТовару<>1
ROLLBACK TRANSACTION point3
Відбувається повернення в стан таблиці без товарів з кодами 2 і 3, відміняється останнє видалення.
SELECT * FROM Товар
Оператор SELECT покаже таблицю Товар без товарів з кодами 2 і 3.
ROLLBACK TRANSACTION point1
Відбувається повернення в первинний стан таблиці.
SELECT * FROM Товар
COMMIT
Первинний стан зберігається.
Вкладені транзакції
Вкладеними називаються транзакції, виконання яких ініціюється з тіла вже активній транзакції .
Для створення вкладеної транзакції користувачеві не потрібні які-небудь додаткові команди. Він просто починає нову транзакцію, не закривши попередню. Завершення транзакції верхнього рівня відкладається до завершення вкладених транзакцій. Якщо транзакція самого нижнього ( вкладеного ) рівня завершена невдало і скасована, то всі транзакції верхнього рівня, включаючи транзакцію першого рівня, будуть скасовані. Крім того, якщо декілька транзакцій нижнього рівня було завершено успішно (але не зафіксовані), проте на середньому рівні (не сама верхня транзакція ) невдало завершилася інша транзакція, то відповідно до вимог ACID станеться відкат всіх транзакцій усіх рівнів, включаючи успішно завершені. Тільки коли усі транзакції на усіх рівнях завершені успішно, відбувається фіксація усіх зроблених змін в результаті успішного завершення транзакції верхнього рівня.
Кожна команда COMMIT TRANSACTION працює тільки з останньою початою транзакцією. При завершенні вкладеної транзакції команда COMMIT застосовується до найбільш "глибокої" вкладеної транзакції. Навіть якщо в команді COMMIT TRANSACTION вказано ім'я транзакції більше високого рівня, буде завершена транзакція, почата останньою.
Якщо команда ROLLBACK TRANSACTION використовується на будь-якому рівні вкладеності без вказівки імені транзакції, то відкочуються усі вкладені транзакції, включаючи транзакцію самого високого рівня. У команді ROLLBACK TRANSACTION дозволяється вказувати тільки ім'я самої верхньої транзакції. Імена будь-яких вкладених транзакцій ігноруються, і спроба їх вказівки приведе до помилки. Таким чином, при відкаті транзакції будь-якого рівня вкладеності завжди відбувається відкат усіх транзакцій. Якщо ж вимагається відкотити лише частину транзакцій, можна використовувати команду SAVE TRANSACTION, за допомогою якої створюється точка збереження.
BEGIN TRAN
INSERT Товар (Назва, залишок)
VALUES ('v ', 40)
BEGIN TRAN
INSERT Товар (Назва, залишок)
VALUES ('n ', 50)
BEGIN TRAN
INSERT Товар (Назва, залишок)
VALUES ('m ', 60)
ROLLBACK TRAN
Приклад 16.2. Вкладені транзакції.
Тут відбувається повернення на початковий стан таблиці, оскільки виконання команди ROLLBACK TRAN без вказівки імені транзакції відкочує усі транзакції.
Управління блокуваннями
Користувачеві найчастіше не треба робити ніяких дій з управління блокуваннями. Усю роботу по установці, зняттю і вирішенню конфліктів виконує спеціальний компонент сервера, званий менеджером блокувань. MS SQL Server підтримує різні рівні блокування об'єктів (чи деталізацію блокувань), починаючи з окремого рядка таблиці і закінчуючи базою даних в цілому. Менеджер блокувань автоматично оцінює, яку кількість даних необхідно блокувати, і встановлює відповідний тип блокування. Це дозволяє підтримувати рівновагу між продуктивністю роботи системи блокування і можливістю користувачів діставати доступ до даних. Блокування на рівні рядка дозволяє найточніше управляти таким доступом, оскільки блокуються тільки дійсно змінювані рядки. Безліч користувачів можуть одночасно працювати з даними з мінімальними затримками. Платою за це є збільшення числа операцій установки і зняття блокувань, а також велика кількість службової інформації, яку доводиться зберігати для відстежування встановлених блокувань. При блокуванні на рівні таблиці продуктивність системи блокування різко збільшується, оскільки необхідно встановити лише одне блокування і зняти її тільки потім завершення транзакції. Користувач при цьому має максимальну швидкість доступу до даних. В той же час вони не доступні нікому іншому, тому що уся таблиця заблокована. Доводиться чекати, доки поточний користувач завершить роботу.
Дії, що виконуються користувачами при роботі з даними, зводяться до операцій двох типів : їх читанню і зміні. У операції по зміні включаються дії з додавання, видалення і власне зміни даних. Залежно від виконуваних дій сервер накладає певний тип блокування з наступного переліку:
• Колективні блокування. Вони накладаються при виконанні операцій читання даних (наприклад, SELECT ). Якщо сервер встановив на ресурс колективне блокування, то користувач може бути упевнений, що вже ніхто не зможе змінити ці дані.
• Блокування оновлення. Якщо на ресурс встановлено колективне блокування і для цього ресурсу встановлюється блокування оновлення, то ніяка транзакція не зможе накласти колективне блокування або блокування оновлення .
• Монопольне блокування. Цей тип блокувань використовується, якщо транзакція змінює дані. Коли сервер встановлює монопольне блокування на ресурс, то ніяка інша транзакція не може прочитати або змінити заблоковані дані. Монопольне блокування не сумісне ні з якими іншими блокуваннями, і ні одне блокування, включаючи монопольне, не може бути накладене на ресурс.
• Блокування масивного оновлення. Накладається сервером при виконанні операцій масивного копіювання в таблицю і забороняє звернення до таблиці будь-яким іншим процесам. В той же час декілька процесів, що виконують масивне копіювання, можуть одночасно вставляти рядки в таблицю.
Окрім перерахованих основних типів блокувань SQL Server підтримує ряд спеціальних блокувань, призначених для підвищення продуктивності і функціональності обробки даних. Вони називаються блокуваннями намірів і використовуються сервером у тому випадку, якщо транзакція має намір отримати доступ до даних вниз за ієрархією і для інших транзакцій необхідно встановити заборону на накладення блокувань, які конфліктуватимуть з блокуванням, першої транзакції, що накладається .
Раніше розглянуті блокування відносяться до даних. Окрім перерахованих в середовищі SQL Server існує два інші типи блокувань : блокування діапазону ключів і блокування схеми (метаданих, що описують структуру об'єкту).
Блокування діапазону ключів вирішує проблему виникнення фантомів і забезпечує вимоги серіалізуємості транзакції. Блокування цього типу встановлюються на діапазон рядків, що відповідають певній логічній умові, за допомогою якої здійснюється вибірка даних з таблиці.
Блокування схеми використовується при виконанні команд модифікації структури таблиць для забезпечення цілісності даних.
"Мертві" блокування
"Мертві", або тупикові, блокування характерні для розрахованих на багато користувачів систем. "Мертве" блокування виникає, коли дві транзакції блокують два блоки даних і для завершення будь-якої з них потрібний доступ до даних, заблокованих раніше іншою транзакцією. Для завершення кожної транзакції необхідно дочекатися, поки блокована іншою транзакцією частина даних буде розблокована. Але це неможливо, оскільки друга транзакція чекає розблокування ресурсів, використовуваних першою.
Без застосування спеціальних механізмів виявлення і зняття "мертвих" блокувань нормальна робота транзакцій буде порушена. Якщо в системі встановлений нескінченний період очікування завершення транзакції (а це задано за умовчанням), то при виникненні "мертвого" блокування для двох транзакцій цілком можливо, що, чекаючи звільнення заблокованих ресурсів, у безвиході виявляться і нові транзакції. Щоб уникнути подібних проблем, в середовищі MS SQL Server реалізований спеціальний механізм вирішення конфліктів тупикового блокування.
Для цих цілей сервер знімає одне з блокувань, що викликали конфлікт, і відкочує транзакцію, що ініціалізувала її. При виборі блокування, якому необхідно пожертвувати, сервер виходить з міркувань мінімальної вартості.
Повністю уникнути виникнення "мертвих" блокувань не можна. Хоча сервер і має ефективні механізми зняття таких блокувань, все ж при написанні додатків слід враховувати вірогідність їх виникнення і робити усі можливі дії для попередження цього. "Мертві" блокування можуть істотно понизити продуктивність, оскільки системі потрібно досить багато часу для їх виявлення, відкату транзакції і повторного її виконання.
Для мінімізації можливості утворення "мертвих" блокувань при розробці коду транзакції слід дотримуватися наступних правил:
• виконувати дії з обробки даних в постійному порядку, щоб не створювати умови для захоплення одних і тих же даних;
• уникати взаємодії з користувачем в тілі транзакції ;
• мінімізувати тривалість транзакції і виконувати її по можливості в одному пакеті;
• застосовувати як можна нижчий рівень ізоляції.
Рівень ізоляції визначає міру незалежності транзакцій один від одного. Найвищим рівнем ізоляції є серіалізуємість, що забезпечує повну незалежність транзакцій один від одного. Кожен наступний рівень відповідає вимогам усіх попередніх і забезпечує додатковий захист транзакцій .
SQL Server підтримує усі чотири рівні ізоляції, визначені стандартом ANSI. Рівень ізоляції встановлюється командою:
SET TRANSACTION ISOLATION LEVEL
{ READ UNCOMMITTED
| READ COMMITTED
| REPEATABLE READ
| SERIALIZABLE }
• READ UNCOMMITED - незавершене читання, або допустиме чорнове читання. Нижчий рівень ізоляції, що відповідає рівню 0. Він гарантує тільки фізичну цілісність даних : якщо декілька користувачів одночасно змінюють один і той же рядок, то в остаточному варіанті рядок матиме значення, визначене користувачем, що останнім змінив запис. По суті, для транзакції не встановлюється ніякого блокування, яке гарантувало б цілісність даних. Для установки цього рівня використовується команда:
• SET TRANSACTION ISOLATION
LEVEL READ UNCOMMITTED
• READ COMMITTED - завершене читання, при якому відсутнє чорнове, "брудне" читання. Проте в процесі роботи однієї транзакції інша може бути успішно завершена і зроблені нею зміни зафіксовані. У результаті перша транзакція працюватиме з іншим набором даних. Це проблема неповторюваного читання . Цей рівень ізоляції встановлений в SQL Server за умовчанням і встановлюється за допомогою команди:
• SET TRANSACTION ISOLATION
LEVEL READ COMMITTED
• REPEATABLE READ - читання, що повторюється. Повторне читання рядка поверне спочатку лічені дані, незважаючи на будь-які оновлення, зроблені іншими користувачами до завершення транзакції. Проте на цьому рівні ізоляції можливе виникнення фантомів . Його установка реалізується командою:
• SET TRANSACTION ISOLATION
LEVEL REPEATABLE READ
• SERIALIZABLE - серіалізуємість. Читання заборонене до завершення транзакції. Це максимальний рівень ізоляції, який забезпечує повну ізоляцію транзакцій один від одного. Він встановлюється командою:
• SET TRANSACTION ISOLATION
LEVEL SERIALIZABLE
У кожен момент часу можливий тільки один рівень ізоляції.
Таблиця 16.1. Рівень ізоляції конкуруючої транзакції прийнятий за умовчанням (READ COMMITTED). У прикладі кроки 4, 6 і 8 демонструють чорнове читання. Кроки 9 і 10 блокуються, тому що дані захоплені конкуруючою транзакцією. |
|
Користувач user1 Конкуруюча транзакція |
Користувач user2 Поточна транзакція |
USE basa_user2 BEGIN TRANSACTION TRA |
USE basa_user2 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED BEGIN TRANSACTION TRB |
1. SELECT * FROM Товар |
2. SELECT * FROM Товар |
3. UPDATE Товар SET залишок=залишок+10 WHERE КодТовару=4 |
4. SELECT * FROM Товар (читає змінені непідтверджені дані) |
5. DELETE FROM Товар WHERE КодТовару=4 |
6. SELECT * FROM Товар (читає змінені непідтверджені дані) |
7. INSERT Товар (Назва, залишок) VALUES ('SS ', 999) |
8. SELECT * FROM Товар (читає змінені непідтверджені дані) |
12. ROLLBACK TRANSACTION TRA |
9. UPDATE Товар SET залишок=залишок+10 WHERE КодТовару=4 (блокується до закінчення конкуруючої транзакції ) |
10. DELETE FROM Товар WHERE КодТовару=4 (блокується до закінчення конкуруючої транзакції ) |
11. INSERT Товар(Назва, залишок) VALUES(виконується) |
13. ROLLBACK TRANSACTION TRB SELECT @@TRANCOUNT |
|
Таблиця 16.2. Рівень ізоляції конкуруючої транзакції прийнятий за умовчанням (READ COMMITTED). У прикладі кроки 4, 6 і 8 демонструють блокування даних, захоплених іншою транзакцією, тоді як робота з іншими даними дозволяється (крок 10). |
|
Користувач user1 Конкуруюча транзакція |
Користувач user2 Поточна транзакція |
USE basa_user2 BEGIN TRANSACTION TRA |
USE basa_user2 SET TRANSACTION ISOLATION LEVEL READ COMMITTED BEGIN TRANSACTION TRB |
1. SELECT * FROM Товар |
2. SELECT * FROM Товар |
3. UPDATE Товар SET залишок=залишок+10 (захоплює дані) |
4. SELECT * FROM Товар WHERE КодТовару=4 (блокується до закінчення конкуруючої транзакції ) |
5. DELETE FROM Товар WHERE КодТовару=4 |
6. UPDATE Товар SET залишок=залишок+10 WHERE КодТовару=4(блокується до закінчення конкуруючої транзакції ) |
7. UPDATE Товар SET залишок=залишок+10 WHERE КодТовару=4 (виконується тією транзакцією, яка першою захопила дані на зміну або видалення) |
8. DELETE FROM Товар WHERE КодТовару=4 (блокується до закінчення конкуруючої транзакції ) |
9. INSERT Товар (Назва, залишок) VALUES ('SS ', 999) |
10. INSERT Товар(Назва, залишок) VALUES(виконується) |
11. ROLLBACK TRANSACTION TRA SELECT @@TRANCOUNT |
12. ROLLBACK TRANSACTION TRB SELECT @@TRANCOUNT |
Таблиця 16.3. Рівень ізоляції конкуруючої транзакції прийнятий по замовчуванню (READ COMMITTED). На кроці 2 транзакція захватила дані читанням і блокує роботу з ними зі сторони конкуруючої транзакції (кроки 3, 5), яка може лише додавати записи (крок 7). |
|
Користувач user1 Конкуруюча транзакція |
Користувач user2 Поточна транзакція |
USE basa_user2 BEGIN TRANSACTION TRA |
USE basa_user2 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ BEGIN TRANSACTION TRB |
1. SELECT * FROM Товар |
2. SELECT * FROM Товар (захоплює дані) |
3. UPDATE Товар SET залишок=залишок+10 WHERE КодТовару=4(блокується) |
4. SELECT * FROM Товар (блокується до закінчення конкуруючої транзакції ) |
5. DELETE FROM Товар WHERE КодТовару=4 (блокується) |
6. UPDATE Товар SET залишок=залишок+10 WHERE КодТовару=4 (виконується, оскільки дані захоплені поточною транзакцією ) |
7. INSERT Товар (Назва, залишок) VALUES(виконується) |
8. DELETE FROM Товар WHERE КодТовару=4 (виконується, оскільки дані захоплені поточною транзакцією ) |
10. ROLLBACK TRANSACTION TRA SELECT @@TRANCOUNT |
9. INSERT Товар(Назва, залишок) VALUES(виконується) |
11. ROLLBACK TRANSACTION TRB SELECT @@TRANCOUNT |
|
Таблиця 16.4. Рівень ізоляції конкуруючої транзакції прийнятий за умовчанням (READ COMMITTED). Приклад демонструє, що поточна транзакція захопила дані читанням (крок 2) і блокує будь-які дії з ними з боку конкуруючої транзакції аж до вставки даних (крок 7). |
|
Користувач user1 Конкуруюча транзакція |
Користувач user2 Поточна транзакція |
USE basa_user2 BEGIN TRANSACTION TRA |
USE basa_user2 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION TRB |
1. SELECT * FROM Товар |
2. SELECT * FROM Товар (захоплює дані) |
3. UPDATE Товар SET залишок=залишок+10 WHERE КодТовару=4(блокується) |
4. SELECT * FROM Товар (виконується) |
5. DELETE FROM Товар WHERE КодТовару=4 (блокується) |
6. UPDATE Товар SET залишок=залишок+10 WHERE КодТовару=4 (виконується, оскільки дані захоплені поточною транзакцією ) |
7. INSERT Товар (найменування, залишок) VALUES(блокується) |
8. DELETE FROM Товар WHERE КодТовару=4 (виконується, оскільки дані захоплені поточною транзакцією ) |
10. ROLLBACK TRANSACTION TRA SELECT @@TRANCOUNT |
9. INSERT Товар(Назва, залишок) VALUES(виконується) |
11. ROLLBACK TRANSACTION TRB SELECT @@TRANCOUNT |
Стабільна система управління користувачами - обов'язкова умова безпеки даних, що зберігаються у будь-якій реляційній СУБД. У мові SQL не існує єдиної стандартної команди, призначеної для створення користувачів бази даних, - кожна реалізація робить це по-своєму. У одних реалізаціях ці спеціальні команди мають певну схожість, тоді як в інших їх синтаксис має істотні відмінності. Проте незалежно від конкретної реалізації усі основні принципи однакові.
Розглянемо питання створення користувачів в середовищі MS SQL Server.
Після проектування логічної структури бази даних, зв'язків між таблицями, обмежень цілісності і інших структур необхідно визначити круг користувачів, які матимуть доступ до бази даних.
У системі SQL -сервер організована дворівневе налаштування обмеження доступу до даних. На першому рівні необхідно створити так званий обліковий запис користувача(login), що дозволяє йому підключитися до самого сервера, але не дає автоматичного доступу до баз даних. На другому рівні для кожної бази даних SQL -сервера на підставі облікового запису необхідно створити запис користувача. На основі прав, виданих користувачеві як користувачеві бази даних (user), його реєстраційне ім'я (login) дістає доступ до відповідної бази даних. У різних базах даних login одного і того ж користувача може мати однакові або різні імена user з різними правами доступу. Інакше кажучи, за допомогою облікового запису користувача здійснюється підключення до SQL -серверу, після чого визначаються його рівні доступу для кожної бази даних окремо.
У системі SQL -сервер існують додаткові об'єкти - ролі, які визначають рівень доступу до об'єктів SQL -сервера. Вони розділені на дві групи: що призначаються для облікових записів користувача сервера і використовувані для обмеження доступу до об'єктів бази даних.
Отже, на рівні сервера система безпеки оперує наступними поняттями:
• аутентифікація ;
• обліковий запис ;
• вбудовані ролі сервера.
На рівні бази даних застосовуються наступні поняття;
• користувач бази даних;
• фіксована роль бази даних;
• призначена для користувача роль бази даних.
Режими аутентифікації
SQL Server пропонує два режими аутентифікації користувачів :
• режим аутентифікації засобами Windows NT/2000;
• змішаний режим аутентифікації (Windows NT Authentication and SQL Server Authentication).
Адміністрування системи безпеки
Для створення користувача в середовищі MS SQL Server слід зробити наступні кроки:
1. Створити у базі даних обліковий запис користувача, вказавши для нього пароль і прийняте за умовчанням ім'я бази даних (процедура sp_addlogin ).
2. Додати цього користувача в усі необхідні бази даних (процедура sp_adduser).
3. Надати йому в кожній базі даних відповідні привілеї (команда GRANT ).
Створення нового облікового запису може бути зроблене за допомогою системної збереженої процедури :
sp_addlogin
[@login=] 'обліковий_запис'
[, [@password=] 'пароль']
[, [@defdb=] 'база_даних_за умовчанням']
Після завершення аутентифікації і отримання ідентифікатора облікового запису (login ID) користувач вважається зареєстрованим, і йому надається доступ до сервера. Для кожної бази даних, до об'єктів якої він має намір отримати доступ, обліковий запис користувача (login) асоціюється з користувачем (user) конкретної бази даних, що здійснюється за допомогою процедури:
sp_adduser
[@loginame=] 'обліковий_запис'
[, [@name_in_db=] 'ім'я_користувача']
[, [@grpname=] 'ім'я_ролі']
Відобразити обліковий запис Windows NT в ім'я користувача дозволяє процедура, що зберігається :
sp_grantdbaccess
[@login=] 'обліковий_запис'
[, [@name_in_db=]'ім'я_користувача']
Користувач, який створює об'єкт у базі даних (таблицю, процедуру, що зберігається, перегляд), стає його власником. Власник об'єкту (database object owner dbo) має всі права доступу до створеного їм об'єкту. Щоб користувач міг створити об'єкт, власник бази даних (dbo) повинен надати йому відповідні права. Повне ім'я створюваного об'єкту включає ім'я користувача, що створив його .
Власник об'єкту не має спеціального пароля або особливих прав доступу. Він неявно має повний доступ, але повинен явно надати доступ іншим користувачам.
SQL Server дозволяє передавати права володіння від одного користувача іншому за допомогою процедури:
sp_changeobjectowner
[@objname=] 'ім'я_об'єкту'
[@newowner=] 'ім'я_власника'
Роль дозволяє об'єднати в одну групу користувачів, що виконують однакові функції.
У SQL Server реалізовано два види стандартних ролей : на рівні сервера і на рівні баз даних. При установці SQL Server створюються фіксовані ролі сервера (наприклад, sysadmin з правом виконання будь-яких функцій SQL -сервера) і фіксовані ролі бази даних (наприклад, db_owner з правом повного доступу до бази даних або db_accessadminс правом додавання і видалення користувачів ). Серед фіксованих ролей бази даних існує роль public, яка має спеціальне призначення, оскільки її членами є усі користувачі, що мають доступ до бази даних.
Можна включити будь-який обліковий запис SQL Server (login) або обліковий запис Windows NT у будь-яку роль сервера.
Ролі бази даних дозволяють об'єднувати користувачів в одну адміністративну одиницю і працювати з нею як із звичайним користувачем. Можна призначити права доступу до об'єктів бази даних для конкретної ролі, при цьому автоматично усі члени цієї ролі наділяються однаковими правами.
У роль бази даних можна включити користувачів SQL Server, ролі SQL Server, користувачів Windows NT.
Різні дії по відношенню до ролі здійснюються за допомогою спеціальних процедур:
• створення нової ролі :
• sp_addrole
• [@rolename=] 'ім'я_ролі'
[, [@ownername=] 'ім'я_власника']
• додавання користувача до ролі:
• sp_addrolemember
• [@rolename=] 'ім'я_ролі',
[@membername=] 'ім'я_користувача'
• видалення користувача з ролі:
• sp_droprolemember
• [@rolename=] 'ім'я_ролі',
[@membername=] 'ім'я_користувача'
• видалення ролі :
• sp_droprole
[@rolename=] 'ім'я_ролі'
Визначення привілеїв в стандарті мови
Кожна СУБД повинна підтримувати механізм, що гарантує, що доступ до бази даних зможуть отримати тільки ті користувачі, які мають відповідний дозвіл. Мова SQL включає оператори GRANT і REVOKE, призначені для організації захисту таблиць у базі даних. Механізм захисту побудований на використанні ідентифікаторів користувачів, що надаються їм прав володіння і привілеїв.
Ідентифікатором користувача називається звичайний ідентифікатор мови SQL, вживаний для позначення деякого користувача бази даних. Кожному користувачу повинен бути призначений власний ідентифікатор, що привласнюється адміністратором бази даних. З очевидних міркувань безпеки ідентифікатор користувача, як правило, зв'язується з деяким паролем. Кожен виконуваний СУБД SQL -оператор виконується від імені якого-небудь користувача. Ідентифікатор користувача визначає, на які об'єкти бази даних користувач може посилатися і які операції з цими об'єктами він має право виконувати.
Кожен створений в середовищі SQL об'єкт має свого власника, який спочатку є єдиною персоною, що знає про існування цього об'єкту і має право виконувати з ним будь-які операції.
Привілеями, або правами, називаються дії, які користувач має право виконувати відносно цієї таблиці бази даних або представлення. У стандарті SQL визначається наступний набір привілеїв :
• SELECT - право вибирати дані з таблиці;
• INSERT - право вставляти в таблицю нові рядки;
• UPDATE - право змінювати дані в таблиці;
• DELETE - право видаляти рядки з таблиці;
• REFERENCES - право посилатися на стовпці вказаної таблиці в описах вимог підтримки цілісності даних;
• USAGE - право використовувати домени, перевірки і набори символів.
Привілеї INSERT і UPDATE можуть обмежуватися лише окремими стовпцями таблиці, в цьому випадку користувачеві дозволяється модифікувати значення тільки вказаних стовпців. Аналогічним чином привілей REFERENCES може поширюватися виключно на окремі стовпці таблиці, що дозволить використовувати їх імена у формулюваннях вимог захисту цілісності даних - наприклад, в пропозиціях CHECK і FOREIGN KEY, що входять у визначення інших таблиць, тоді як застосування для подібних цілей інших стовпців буде заборонено.
Коли користувач за допомогою оператора CREATE TABLE створює нову таблицю, він автоматично стає її власником і отримує по відношенню до неї повний набір привілеїв, яких інші користувачі початково не мають. Щоб забезпечити їм доступ, власник повинен явним чином надати необхідні права, для чого використовується оператор GRANT.
Створюючи представлення за допомогою оператора CREATE VIEW, користувач автоматично стає власником цього представлення і також отримує повний набір прав. Для створення представлення користувачеві досить мати привілей SELECT для усіх таблиць, що входять в нього, і привілей REFERENCES для усіх стовпців, що згадуються у визначенні цього представлення. Привілеї INSERT, UPDATE і DELETE відносно створеного представлення користувач отримає тільки у тому випадку, якщо має відповідні привілеї відносно усіх використовуваних в представленні таблиць.
Надання привілеїв користувачам
Оператор GRANT застосовується для надання привілеїв відносно пойменованих об'єктів бази даних вказаним користувачам. Зазвичай його використовує власник таблиці з метою надання доступу до неї іншим користувачам . Оператор GRANT має наступний формат:
<надання_привілеїв>::=
GRANT {<привілей>[,..n] |
ALL PRIVILEGES}
ON ім'я_об'єкту
TO {<ідентифікатор_користувача>
[,..n]| PUBLIC}
[ WITH GRANT OPTION]
Параметр <привілей> є:
<привілей>::=
{SELECT | DELETE | INSERT
[(ім'я_стовпця[,..n])]
| UPDATE [(ім'я_стовпця[,..n])]}
| REFERENCES [(ім'я_стовпця[,..n])] |
USAGE }
З міркувань спрощення в операторові GRANT можна вказати ключове слово ALL PRIVILEGES, що дозволить надати вказаному користувачеві усі існуючі привілеї без необхідності їх перерахування. Крім того, в цьому операторові може вказуватися ключове слово PUBLIC, надання доступу вказаного типу, що означає, не лише усім існуючим користувачам, але також і усім тим, хто буде визначений у базі даних згодом.
Параметр ім'я_об'єкту може використовуватися як ім'я таблиці бази даних, представлення, домену, набору символів, перевірки.
Завдяки параметру WITH GRANT OPTION, вказані в операторові GRANT користувачі мають право передавати усі надані їм відносно вказаного обєкта привілеї іншим користувачам, які, у свою чергу, будуть наділені таким самим правом передачі своїх повноважень. Якщо цей параметр не буде вказаний, одержувач привілею не зможе передати свої права іншим користувачам. Таким чином, власник об'єкту може чітко контролювати, хто отримав право доступу до об'єкту і які повноваження йому надані.
Відміна наданих користувачам привілеїв
У мові SQL для відміни привілеїв, наданих користувачам за допомогою оператора GRANT, використовується оператор REVOKE. За допомогою цього оператора можуть бути відмінені усі або деякі з привілеїв, отриманих вказаним користувачем раніше. Оператор REVOKE має наступний формат:
<відміна_привілеїв>::=
REVOKE[GRANT OPTION FOR]
{<привілей>[,..n]
| ALL PRIVILEGES}
ON ім'я_об'єкту
FROM {<ідентифікатор_користувача>
[,..n]| PUBLIC}
[RESTRICT | CASCADE]
Ключове слово ALL PRIVILEGES означає, що для вказаного користувача відміняються усі привілеї, надані йому раніше тим користувачем, який ввів цей оператор. Необов'язкова фраза GRANT OPTION FOR дозволяє для усіх привілеїв, переданих в початковому операторові GRANT фразою WITH GRANT OPTION, відміняти можливість їх передачі незалежно від самих привілеїв.
Якщо в операторові вказано ключове слово RESTRICT, успішне виконання команди REVOKE можливе лише у тому випадку, коли перераховані в операторові привілеї не можуть послужити причиною появи у яких-небудь інших користувачів так званих "залишених" привілеїв. За допомогою параметра CASCADE віддаляються всі привілеї, які інакше могли б залишитися у інших користувачів.
"Залишеними" є привілеї, що збереглися у користувача, якому вони свого часу були надані за допомогою параметра GRANT OPTION.
Оскільки наявність привілею потрібна для створення певних об'єктів, разом з її видаленням можна позбутися права, за рахунок використання якого був утворений той або інший об'єкт (подібні об'єкти називаються "кинутими"). Якщо в результаті виконання оператора REVOKE можуть з'явитися кинуті об'єкти (наприклад, представлення), право буде скасовано за умови, що в нім не вказується ключове слово CASCADE. Якщо ключове слово CASCADE в операторові є присутнім, то для будь-яких кинутих об'єктів, що виникають при виконанні початкового оператора REVOKE, будуть автоматично видані оператори DROP.
Привілеї, які були надані вказаному користувачеві іншими користувачами, не можуть торкнутися оператором REVOKE. Отже, якщо інший користувач також надав цьому користувачеві привілей, що видалявся, то право доступу до відповідної таблиці у вказаного користувача збережеться. Наприклад, нехай користувач A і користувач Е мали право INSERT на таблицю Товар. Користувач А надав користувачеві B привілей INSERT для таблиці Товар, причому з вказівкою WITH GRANT OPTION (етап 1). Користувач B передав цей привілей користувачеві C (етап 2). Потім користувач C отримав її ж від користувача E (етап 3). Дальше користувач C надав згаданий привілей користувачеві D (етап 4). Коли користувач A відміняє привілей INSERT для користувача B, вона не може бути відмінена і для користувача C, оскільки раніше він вже отримав її від користувача E. Якби користувач E не надав цього привілею користувачеві C, то видалення привілеїв користувача B мало б слідством каскадне видалення привілеїв для користувачів C і D (див. таблицю 17.1).
Категорії прав в середовищі MS SQL Server
При підключенні до SQL Server усі можливі дії користувачів визначаються правами ( привілеями, дозволами), виданими їх обліковому запису, групі або ролі, в яких вони полягають.
Права можна розділити на три категорії:
• права на доступ до об'єктів ;
• права на виконання команд ;
• неявні права.
Таблиця 17.1. |
||||
Користувач A |
Користувач B |
Користувач C |
Користувач D |
Користувач E |
GRANT INSERT ON Товар TO B WITH GRANT OPTION |
Отримання права |
|||
GRANT INSERT ON Товар TO C WITH GRANT OPTION |
Отримання права від B. Отримання права від E |
GRANT INSERT ON Товар TO C WITH GRANT OPTION |
||
GRANT INSERT ON Товар TO D |
Отримання права |
|||
REVOKE INSERT ON Товар TO B CASCADE |
Відміна права |
Збереження права |
Збереження права |
Збереження права |
Робота з даними і виконання процедур, що зберігаються, вимагають наявності класу доступу, званого правами на доступ до об'єктів баз даних. Під об'єктами маються на увазі таблиці, стовпці таблиць, представлення, збережені процедури.
Для різних об'єктів застосовуються різні набори прав доступу до них:
• SELECT, INSERT, UPDATE, DELETE, REFERENCES - для таблиці або представлення;
• SELECT, UPDATE - для конкретного стовпця таблиці або представлення;
• EXECUTE - для процедур, що зберігаються, і функцій.
Право INSERT дозволяє вставляти нові рядки в таблицю або представлення і видається тільки на рівні таблиці або представлення; воно не може бути видане на рівні стовпця.
Право UPDATE видається або на рівні таблиці, що дозволяє змінювати в ній усі дані, або на рівні окремого стовпця, що дозволяє змінювати дані тільки в його межах.
Право DELETE дозволяє видаляти рядки з таблиці або представлення, видається тільки на рівні таблиці або представлення, але не може бути видане на рівні стовпця.
Право SELECT дозволяє вибірку даних і може видаватися як на рівні таблиці, так і на рівні окремого стовпця.
Право REFERENCES надає можливість посилатися на вказаний об'єкт. Стосовно таблиць дозволяє створювати зовнішні ключі, що посилаються на первинний ключ або унікальний стовпець цієї таблиці.
Надання прав
Для управління дозволом користувача на доступ до об'єктів бази даних використовується команда:
<надання_привілеїв>::=
GRANT { ALL [ PRIVILEGES] | <привілей>
[,..n]}
{ [( ім'я_стовпця [,..n])]
ON { ім'я_таблиці |
ім'я_перегляду} |
ON {ім'я_таблиці |
ім'я_перегляду }
( ([ім'я_стовпця
[,..n])]
| ON {ім'я_збереженої процедури_ |
ім'я_зовнішньої_процедури}}
TO { ім'я_користувача | ім'я_групи |
ім'я_ролі} [,..n]
[WITH GRANT OPTION ]
[AS {ім'я_групи | ім'я_ролі }]
Параметр <привілей> є наступною конструкцією:
<привілей>::=
{SELECT | DELETE | INSERT |
UPDATE | EXECUTE | REFERENCES }
Параметр WITH GRANT OPTION допоможе користувачеві, якому ви надаєте права, призначити права на доступ до об'єкту іншим користувачам. Його використання вимагає особливої обережності, оскільки при цьому власник втрачає контроль над наданням прав на доступ іншим користувачам. Краще всього обмежити коло користувачів, що мають можливість управляти призначенням прав.
Необов'язковий параметр AS {ім'я_групи | ім'я_ролі } дозволяє вказати участь користувача в ролі, що забезпечує надання прав іншим користувачам.
Єдине право доступу, яке може бути надане для збереженої процедури, - право на її виконання ( EXECUTE ). Природно, окрім цього власник збереженої процедури, може переглядати і змінювати її код.
Для функції можна видати право на її виконання, а крім того, видати право REFERENCES, що забезпечить можливість зв'язування функції з об'єктами, на які вона посилається. Таке зв'язування дозволить заборонити внесення змін до структури об'єктів, здатних привести до порушення роботи функції.
Права на виконання команд SQL
Цей клас прав контролює можливість створення об'єктів у базі даних, самої бази даних і виконання процедури резервного копіювання. Можна використовувати наступну команду для надання права на виконання команд SQL :
<надання_права_виконання>::=
GRANT {ALL | <команда>[,..n]}
TO {ім'я_користувача | ім'я_групи |
ім'я_ролі} [,..n]
Параметр <команда> є наступною конструкцією:
<команда>::=
{CREATE DATABASE | CREATE TABLE |
CREATE VIEW | CREATE DEFAULT |
CREATE RULE | CREATE PROCEDURE
| BACKUP DATABASE |
BACKUP LOG | ALL }
Таким чином, можна надати право на створення бази даних, таблиці, перегляду, умовчання, правила, збереженої процедури, резервної копії бази даних і журналу транзакцій або надати відразу усі вище перелічені права.
Неявні права
Виконання деяких дій не вимагає явного дозволу і доступно за умовчанням. Ці дії можуть бути виконані тільки членами ролей сервера або власниками обєкта у базі даних.
Неявні права не надаються користувачеві безпосередньо, він отримує їх лише при певних обставинах. Наприклад, користувач може стати власником обєкту бази даних, тільки якщо сам створить об'єкт або якщо хтось інший передасть йому право володіння своїм об'єктом. Таким чином власник об'єкту автоматично отримає права на виконання будь-яких дій з об'єктом, у тому числі і на надання доступу до об'єкту іншим користувачам. Ці права ніде не вказуються, виконувати будь-які дії дозволяє тільки факт володіння об'єктом.
Заборона доступу
Система безпеки SQL Server має ієрархічну структуру, і тому ролі бази даних включають облікові записи і групи Windows NT, користувачів і ролі SQL Server. Користувач же, у свою чергу, може брати участь в декількох ролях і одночасно мати різні права доступу для різних ролей. Коли одна з ролей, в яких полягає користувач, має дозвіл на доступ до даних, він автоматично має аналогічні права. Проте, якщо виникає необхідність, користувачеві можна заборонити доступ до даних або команд, тоді анулюються усі дозволи на доступ, отримані їм на будь-якому рівні ієрархії. При цьому гарантується, що доступ залишиться забороненим незалежно від дозволів, наданих на більш високому рівні.
Для заборони доступу до об'єктів бази даних використовується команда:
<заборона_доступу>::=
DENY {ALL [PRIVILEGES]| | <привілей>
[,..n]}
{ [(ім'я_стовпця [,..n])]
ON { ім'я_таблиці |
ім'я_перегляду}
| ON {ім'я_таблиці | ім'я_перегляду }
[ім'я_стовпця [,..n])]
| ON {ім'я_збереженої процедури_ |
ім'я_зовнішньої_процедури}}
TO {ім'я_користувача | ім'я_групи |
ім'я_ролі}
[,..n]
[CASCADE ]
Параметр CASCADE дозволяє відкликати права не лише у конкретного користувача, але також і у усіх тих, кому він надав аналогічні права.
Для заборони виконання команд SQL застосовується оператор:
<заборона_виконання>::=
DENY {ALL | <команда>[,..n]}
TO {ім'я_користувача | ім'я_групи |
ім'я_ролі} [,..n]
Неявне відхилення доступу
Неявне відхилення подібно до заборони доступу з тією відмінністю, що воно діє тільки на тому рівні, на якому визначено. Якщо користувачеві на певному уровненеявно відхилений доступ, він все ж може отримати його на іншому рівні ієрархії через членство в ролі, що має право перегляду. За умовчанням доступ користувача до даних неявно відхилений . Для неявного відхилення доступу до об'єктів бази даних використовується команда:
<неявне_відхилення_доступу>::=
REVOKE [GRANT OPTION FOR]
{ALL [ PRIVILEGES]| | <привілей>
[,..n]}
{ [(ім'я_стовпця [,..n])] ON
{ ім'я_таблиці | ім'я_перегляду}
| ON {ім'я_таблиці |
ім'я_перегляду }
[ім'я_стовпця [,..n])]
| ON {ім'я_збереженої процедури_ |
ім'я_зовнішньої_процедури}}
TO | FROM {ім'я_користувача |
ім'я_групи |
ім'я_ролі}[,..n]
[CASCADE ]
[AS {ім'я_групи | ім'я_ролі }]
Для неявного відхилення дозволу на виконання команд SQL використовується наступна команда:
<неявне_відхилення_дозволу>::=
REVOKE {ALL | <команда>[,..n]}
FROM {ім'я_користувача | ім'я_групи |
ім'я_ролі}[,..n]
Сенс параметрів аналогічний параметрам команд GRANT і DENY. Параметр GRANT OPTION FOR використовується, коли необхідно відкликати право, надане параметром WITH GRANT OPTION команди GRANT. Користувач зберігає дозвіл на доступ до об'єкту, але втрачає можливість надавати цей дозвіл іншим користувачам.
Конфлікти доступу
Дозволи, надані ролі або групі, наслідують їх членами. Хоча користувачеві може бути наданий доступ через членство в одній ролі, роль іншого рівня може мати заборону на дію з об'єктом. У такому разі виникає конфлікт доступу .
При вирішенні конфліктів доступу SQL Server керується наступним принципом: дозвіл на надання доступу має найнижчий пріоритет, а на заборону доступу - найвищий. Це означає, що доступ до даних може бути отриманий тільки явним його наданням за відсутності заборони доступу на будь-якому іншому рівні ієрархії системи безпеки. Якщо доступ явно не наданий, користувач не зможе працювати з даними.
Приклад 17.1. Створити нову базу даних, нового користувача для цієї бази даних, надавши йому усі права.
-- -- створення адміністратором нової
-- -- бази даних
CREATE DATABASE basa_user
-- -- створення нового користувача з
-- -- ім'ям UserA і паролем '123'
-- -- базою даних за умовчанням для
-- -- користувача UserA буде база
-- -- з ім'ям basa_user.
sp_addlogin 'UserA ',' 123 ',' basa_user'
-- -- перехід у базу даних basa_user
USE basa_user
-- -- додавання в поточну базу даних
-- (-- (basa_user) користувача з ім'ям
-- -- userA
sp_adduser 'UserA'
-- -- надання користувачеві userA
-- -- у базі даних basa_user усіх прав
GRANT ALL TO UserA
Приклад 17.1. Створення нової бази даних, нового користувача для цієї бази даних, з наданням йому усіх прав.
Приклад 17.2. Використання ролей.
Створимо роль stud і включимо в цю роль двох користувачів user1 і user2 :
sp_addrole 'stud'
sp_addrolemember 'stud ',' user1'
sp_addrolemember 'stud ',' user2'
Надамо права ролі stud і безпосередньо користувачеві user2 :
GRANT SELECT, INSERT ON Товар TO stud
GRANT SELECT, INSERT ON Товар TO user2
Після виконання цих команд користувачі user1 і user2 можуть виконувати команди вибірки і додавання запису в таблицю Товар.
Припинимо право на виконання вставки в таблицю Товар для ролі stud :
REVOKE INSERT ON Товар TO stud
Після виконання попередньої команди користувач user1 втрачає право вставки запису, а user2 зберігає це право, оскільки право вставки надане йому явно.
Виконаємо команду
DENY INSERT ON Товар TO stud.
Після виконання цієї команди обидва користувачі втрачають право вставки в таблицю Товар.
Мову SQL можна використовувати як в інтерактивному режимі, так і шляхом впровадження його операторів в програми, написані на процедурних мовах високого рівня. Прикладом інтерактивного використання SQL -операторів є вікно Query Analyzer в середовищі MS SQL Server. Застосування ж мови SQL в прикладних програмах на практиці реалізоване двома різними способами:
1. Впроваджені SQL -оператори. Окремі SQL -оператори впроваджуються прямо в початковий текст програми і змішуються з операторами базової мови. Цей підхід дозволяє створювати програми, що звертаються безпосередньо до бази даних. Спеціальні програми-передкомпілятори перетворять початковий текст з метою заміни SQL -операторів відповідними викликами підпрограм СУБД, потім він компілюється і збирається звичайним способом.
2. Використання прикладного інтерфейсу програмування (API). Альтернативний варіант полягає в наданні програмістові стандартного набору функцій, до яких можна звертатися із створюваних їм програм. Конкретний варіант API може надавати той же набір функціональних можливостей, який існує при підключенні вбудованих операторів, проте при цьому усувається необхідність передкомпіляції початкового тексту. Крім того, деякі розробники вказують, що в цьому випадку використовується зрозуміліший інтерфейс і створений програмний текст зручніший з точки зору його супроводу.
Обидва способи припускають використання операторів як статичного SQL, так і динамічного SQL.
Що стосується операторів статичного SQL, то якого-небудь зміни після їх одноразового написання не передбачається. Вони можуть зберігатися як у файлах, призначених для подальшого використання, так і у вигляді процедур бази даних, що зберігаються, проте програмісти не отримують усієї тієї гнучкості, яку пропонує їм динамічний SQL. Незважаючи на наявність великого числа запитів, доступних кінцевому користувачеві, може статися так, що жоден з цих "законсервованих" запитів не зможе задовольнити його поточним потребам.
Динамічний SQL дає можливість програмістові або кінцевому користувачеві створювати оператори під час виконання додатка і передавати їх базі даних, яка після виконання цих операторів поміщає вихідні дані в змінні програми. Динамічний SQL часто використовується інструментальними засобами, призначеними для побудови заздалегідь незапланованих запитів, що дозволяють оперативно формувати той або інший оператор SQL залежно від особливих вимог, що виникли в конкретній ситуації. Після налаштування оператора SQL відповідно до потреб користувача він прямує серверу баз даних для перевірки на наявність синтаксичних помилок і необхідних для його виконання привілеїв, після чого відбувається його компіляція і виконання.
Розглянемо застосування прикладного інтерфейсу програмування (API) для виконання операторів SQL.
Прикладний API включає набір бібліотечних функцій, що надають програмістові різноманітні типи доступу до бази даних, а саме: підключення, виконання різних SQL -операторів, вибірка окремих рядків даних з результуючих наборів даних і т. д.
Щоб не розробляти окремі версії призначеного для користувача застосування для кожної з цільових СУБД, з якими це застосування планується використовувати, Microsoft розробила стандарт, що дістав назву Open Database Connectivity ODBC. Технологія ODBC передбачає застосування єдиного інтерфейсу для доступу до різних баз даних SQL, причому мова SQL розглядається як основний стандартний засіб доступу. Цей інтерфейс забезпечує високу міру універсальності, в результаті одно і те ж застосування може діставати доступ до даних, що зберігаються у базах різних цільових СУБД, без необхідності внесення змін до його програмного тексту. Таким чином, розробники отримали інструмент для створення і поширення додатків архітектури "клієнт-сервер", здатних працювати з широким спектром різних цільових СУБД, а зв'язати додатки з будь-якою вибраною цільовою СУБД можна за допомогою відповідного ODBC -драйвера.
Нині технологія ODBC фактично набула значення галузевого стандарту. Головною причиною її популярності є властива їй гнучкість, що надає розробникам наступні переваги :
• додатки більше не пов'язані з прикладним API якоїсь однієї СУБД;
• SQL -оператори можуть явно включатися в початковий текст додатка або динамічно створюватися безпосередньо під час виконання програм;
• додаток здатний ігнорувати особливості використовуваних протоколів передачі даних;
• дані посилаються і доставляються в тому форматі, який найбільш зручний для конкретного застосування;
• засоби підтримки ODBC розроблені з урахуванням вимог стандартів X/Open і CLI (Call Level Interface);
• нині існують драйвери ODBC для різних типів найпоширеніших СУБД.
У інтерфейс ODBC включені наступні елементи:
• бібліотека функцій, виклик яких дозволяє додатку підключатися до бази даних, виконувати SQL -оператори і витягати інформацію з результуючих наборів даних ;
• стандартний метод підключення і реєстрації в СУБД;
• стандартне представлення для цих різних типів;
• стандартний набір кодів помилок;
• типовий синтаксис SQL -операторів, побудований на використанні специфікації X/Open і ISO CGI.
Загальна архітектура ODBC включає чотири елементи:
1. Додаток. Цей компонент виконує обробку даних і виклик функцій бібліотеки ODBC для відправки SQL -операторів СУБД і вибірки поверненої СУБД інформації.
2. Менеджер драйверів. Він виконує завантаження драйверів на вимогу додатка.
3. Драйвери і агенти баз даних. Ці компоненти обробляють виклики функцій ODBC і направляють SQL -запити до конкретних джерел даних, а також повертають отримані результати додатку. При необхідності драйвери виконують модифікацію початкового запиту додатка з метою приведення його у відповідність синтаксичним вимогам цільової СУБД.
4. Джерела даних. Містять ті дані, доступ до яких потрібний користувачеві додатка. Дані зберігаються у БД, контрольованій цільовою СУБД, операційною системою, а також мережевою операційною системою, якщо така використовується.
Виходячи з вищесказаного, можна відмітити, що технологія ODBC пропонує єдиний інтерфейс доступу до різноманітних баз даних SQL. Мова SQL використовується в ній як основний стандарт доступу до даних. Інтерфейс ODBC (вбудований в мову Сі) забезпечує високу міру універсальності : одно застосування може звертатися до різних SQL - сумісних СУБД за допомогою загального коду. Це дозволяє розробникові створювати і поширювати додатки "клієнт/сервер" без урахування особливостей конкретної СУБД, в результаті одно і те ж застосування дістає можливість доступу до баз цих різних СУБД, що підтримують мову SQL. Подібні функціональні можливості технології ODBC дозволяють розробляти додатки СУБД різного типу. Для зв'язку додатків з різнотипними СУБД використовуються відповідні ODBC драйвери . Як вже говорилося, технологія ODBC вже фактично прийнята як галузевий стандарт.
Технологія ODBC передбачає створення додаткового рівня між додатком і використовуваною СУБД. Служби ODBC забезпечують отримання від додатка запитів на вибірку інформації і переклад їх на мову ядра бази даних, що адресується, для доступу до інформації, що зберігається в ній.
Основне призначення ODBC полягає в абстрагуванні додатка від особливостей ядра серверної бази даних, з якою воно здійснює взаємодію, тому серверна база даних стає як би прозорою для будь-якого клієнтського застосування.
Взаємодія додатка з даними робиться за допомогою менеджера (диспетчера) драйверів, він підключає необхідний драйвер відповідно до формату цих СУБД. Драйвер СУБД, використовуючи мережеві засоби, як правило, комунікаційні модулі конкретної СУБД, передає SQL -оператори серверу СУБД. Результати виконання запитів на сервері пересилаються назад в додаток.
Гідність технології ODBC полягає в простоті розробки додатків, обумовленій високим рівнем абстрактності інтерфейсу доступу до даних практично будь-яких існуючих типів СУБД. При цьому можливе створення джерела даних, пов'язаного з будь-яким типом бази даних. За допомогою цієї технології можна створювати клієнт-серверні застосування, причому засобами персональних СУБД доцільно розробляти клієнтську частину додатка, а засобами SQL Server - серверну.
Основний недолік технології ODBC пов'язаний з необхідністю трансляції запитів, що знижує швидкість доступу до даних. У системах клієнт-сервер він усувається шляхом переміщення обробки запиту з комп'ютера-клієнта на комп'ютер-сервер.
При використанні в клієнтському додатку засобів ODBC здійснюється звернення до певного джерела даних, а через нього - до СУБД, що представляється їм. Крім того, встановлюється загальна підсистема ODBC і визначаються пари "драйвер - база даних", яким задаються імена, вживані при установці з'єднання з базою даних. Відповідні пари називаються іменами джерел даних, або пойменованими джерелами даних ( Data Source Names, DSN ).
Створення джерела даних виконується за допомогою утиліти ODBC Data Source Administrator, що викликається з вікна панелі управління. До складу параметрів джерела даних входять: його ім'я і опис; сервер, з яким встановлюється з'єднання ; метод аутентифікації; ім'я бази даних.
Ім'я DSN дозволяє звернутися до джерела даних ODBC з прикладного застосування.
Витягання і обробка інформації з бази даних в загальному випадку пов'язані з рішенням наступних завдань :
• підключення / відключення бази даних;
• запуск, фіксація і відкат SQL -транзакцій;
• відображення результатів SQL -запиту;
• створення оновлюваних курсорів для перегляду, вставки, видалення і зміни даних;
• доступ до великих бінарних об'єктів з мультимедіа-вмістом.
В якості прикладу організації доступу до бази даних з прикладних програм розглянемо:
• взаємодія з базою даних в Java -програмах;
• звернення до бази даних з мов сценаріїв з використанням технології ADO.
Java -програма може бути спеціалізована для роботи із зовнішніми базами даних. З цією метою в Java включені класи для доступу до БД (java.sql.*).
Взаємодія Java -програми із зовнішнім сервером баз даних здійснюється за допомогою спеціалізованого протоколу, що відповідає за сумісність Java з базами даних ( Java Database Connectivity, JDBC ). Він побудований на принципах інтерфейсу ODBC і застосовується для стандартизації Java -коду при організації доступу до різних СУБД. Створений услід за специфікацією ODBC, пакет JDBC став одним з методів доступу до реляційних СУБД з Java -програм. Протокол JDBC, по суті, є посередником Java -коду і драйвером ODBC.
Етап підключення до бази даних включає завантаження драйвера і створення з'єднання.
Завантаження драйвера
Конкретна база даних зазвичай доступна за допомогою одного або декількох драйверів. Складова частина JDBC - драйвер для доступу з JDBC до джерел даних ODBC. Цей драйвер називається програмою сполучення JDBC - ODBC і реалізований у вигляді JdbcOdbc.class.
Оскільки JDBC конструктивно близький до ODBC, програма сполучення є надбудовою над JDBC. На внутрішньому рівні цей драйвер відображає методи Java у виклики ODBC і тим самим взаємодіє з будь-яким ODBC -драйвером. Гідність такої програми сполучення полягає в тому, що JDBC має доступ до будь-яких баз даних, оскільки ODBC -драйвери поширені дуже широко. Драйвер JDBC - ODBC являється міст-драйвером, оскільки створює міст між JDBC і іншим інтерфейсом рівня звернення (Call Level Interface, CLI). Він обробляє звернення JDBC і, у свою чергу, викликає функції ODBC, які передають запити SQL джерелу даних ODBC. Драйвер JDBC - ODBC завантажується командою:
Class.forName(
" "com.ms.jdbc.odbc.JdbcOdbcDriver");
Створення з'єднання : клас Connection
Клас DriverManager - самий верхній в ієрархії класів. Він відстежує інформацію про драйвер, про стан, реєструє драйвер в процесі його завантаження і так далі. Коли вимагається встановити зв'язок, цей клас вибирає драйвер залежно від URL JDBC.
Створити з'єднання з джерелом даних можна за допомогою методу getConnection класу DriverManager.
Для завдання джерела даних використовується угоди по привласненню імен URL. Відповідно до правил Internet, JDBC ідентифікує базу даних за допомогою URL, який має наступну форму:
jdbc:<субпротокол>:<ім'я, пов'язане з
СУБД або протоколом>
Ім'я субпротоколу odbc зарезервоване для джерела даних формату ODBC. Типовий JDBC URL для БД ODBC виглядає таким чином:
jdbc: odbc:<DSN -имя ODBC>;
user=<ім'я користувача>;pw=<пароль>
Клас Connection ( з'єднання ) - один з найважливіших в JDBC. Він надає широкий спектр можливостей : від створення операторів до обробки транзакцій. Обєкт Connection управляє усіма аспектами установки зв'язку. Фактично, Connection - це клас, що веде до драйвера СУБД. Успішно створивши об'єкт Connection для джерела даних, програміст може взаємодіяти з джерелами самими різними способами. Найбільш поширений підхід полягає в тому, щоб об'єкти управляли SQL -операторами.
У JDBC є три основні типи об'єктів для операторів:
• Statement ;
• PreparedStatement ;
• CallableStatement.
Оператор SQL може бути виконаний негайно ( Statement ), відкомпілювався ( PreparedStatement ), представлений у вигляді виклику процедур ( CallableStatement ).
Для створення цих об'єктів клас Connection пропонує, відповідно, три методи:
• createStatement() ;
• prepareStatement(String sql);
• prepareCall(String sql).
Створення оператора : клас Statement
Об'єкт Statement створюється методом createStatement() з об'єкту Connection і краще всього підходить для SQL -операторів, що виконуються один раз.
Коли запит повертає звичайні рядки даних, для виконання SQL -оператора необхідно використовувати метод executeQuery(String sql). У такому разі запит - це статичний SQL -запрос вибірки SELECT. Метод executeQuery(String sql) приймає рядок SQL, передає його джерелу даних через диспетчер драйверів, отримує набір результатів і повертає його прикладній програмі. Метод повертає тільки один набір результатів типу ResultSet. Якщо необхідно повертати декілька наборів даних, застосовується метод execute(String sql).
Для SQL -операторів, результатів (наприклад UPDATE, DELETE і INSERT ), що не повертають набори, об'єкт Statement застосовує метод executeUpdate(String sql), який бере рядок SQL і повертає ціле. Це ціле вказує кількість рядків, оброблених оператором SQL.
Отримання результатів : клас ResultSet
Об'єкт ResultSet, представляючий набір результатів, фактично є табличним набором даних, тобто полягає з лав даних, організованих в уніфіковані стовпці. Програма на мові Java, використовуюча JDBC, одноразово здатна видати тільки один ряд даних. Щоб перейти до наступного ряду, вона повинна викликати метод next(). JDBC не надає метод для зворотного руху по ResultSet або запам'ятовування рядів ("закладки" в ODBC). Отримавши ряд, програма може користуватися позиційним покажчиком (1 - для першого стовпця, 2 - для другого і так далі) або назвою стовпця і отримати значення поля, викликавши метод getXXXX ( getInt, getByte, getString і так далі) відповідно до типу повертаючих даних.
Class.forName(
" "com.ms.jdbc.odbc.JdbcOdbcDriver");
// // при створенні з'єднання вказується
// // DSN джерела даних (mystud)
// // ім'я користувача (user1), його пароль(123)
Connection myCon=DriverManager.getConnection
(" ("jdbc: odbc: mystud", "user1", "123");
Statement mySt=myCon.createStatement();
ResultSet rs=mySt.executeQuery(
" "SELECT назва, тип, ціна FROM товар");
while (rs.next()) {
String var1=rs.getString(1);
String var2=rs.getString(2);
int var3=rs.getInt(3);
// // значення змінних var1, var2, var3 можуть
// // далі бути використані в елементах
// // призначеного для користувача графічного інтерфейсу
}
Приклад 18.1. Виконання статичного SQL -запиту до учбової бази даних з Java -програми.
Створення оператора : клас PreparedStatement
У разі використання цього об'єкту програма готує SQL -оператор за допомогою методу prepareStatement (String sql) об'єкту Connection : береться SQL -рядок і передається СУБД. Рядок проходить через стадії синтаксичного аналізу, оптимізації і генерування плану виконання, але не виконує оператор SQL. Посилання на план виконання повертається JDBC, який зберігає її в об'єкті PreparedStatement.
Одно з важливих властивостей методу prepareStatement - можливість обробки вхідних параметрів. Вони позначаються в операторові SQL символом ""? на місці фактичного значення. У програмі Java проводиться відповідність між параметрами і методами setXXXX() - setInt, setFloat, setString і так далі, відповідно до типів вхідних параметрів. Усе методи setXXXX() приймають як параметри значення параметра і покажчик parameterIndex, який дорівнює 1 для першого ""?, 2 - для другого і так далі. Виконання sql -оператору забезпечується методами об'єкту PreparedStatement :
• executeQuery() - для виконання запиту вибірки SELECT ;
• execute() - для виконання запиту, що повертає множинні набори даних ;
• executeUpdate() - для виконання запиту модифікації даних INSERT, UPDATE або DELETE.
Об'єкт PreparedStatement забезпечує швидше виконання оператора SQL і є прикладом реалізації динамічного SQL.
Class.forName(
" "com.ms.jdbc.odbc.JdbcOdbcDriver");
Connection myCon=DriverManager.getConnection
(" ("jdbc: odbc: mystud", "user1", "123");
PreparedStatement mySt=myCon.prepareStatement
(" ("INSERT товар(назва, тип, ціна)
VALUES(?,?,?)");
mySt.setString(1, "Трюфелі");
mySt.setString(2, "Цукерки");
mySt.setInt(3,156);
int res=mySt.executeUpdate();
Приклад 18.2. Виконання динамічного SQL -запиту до учбової бази даних з Java -програми.
Технологія Active Data Objects (ADO) - це програмне розширення технології активних серверних сторінок ASP, реалізоване в Web -сервері Internet Information Server (IIS) компанії Microsoft з метою організації підключень до баз даних. У технології ADO підтримуються наступні основні функції:
• незалежно створювані об'єкти;
• підтримка процедур, що зберігаються, з вхідними, вихідними і поверненими параметрами ;
• курсори різних типів (включаючи можливість підтримки різних спеціальних курсорів кінцевих користувачів);
• пакетне оновлення;
• підтримка обмежень для числа повернених рядків або інших параметрів запиту;
• підтримка декількох наборів даних, повернених процедурами, що зберігаються, або пакетними операторами.
Основними перевагами технології ADO є простота використання, висока швидкість, невеликі потреби в оперативній пам'яті і незначні витрати дискової пам'яті.
Об'єктна модель ADO визначає набір ( колекцію ) програмованих об'єктів, які можуть застосовуватися з Visual Basic, Visual C++, VBScript. Об'єктна модель ADO розроблена для виконання більшості особливостей інтерфейсу OLE DB.
Якщо за допомогою інтерфейсу ODBC операційна система здійснює, як правило, доступ до реляційних БД, використовуючих структуровану мову запитів SQL, то інтерфейс OLE DB (Object Linking and Embedding for DataBases) є більше універсальною технологією для доступу до будь-яких джерел даних.
У інтерфейс OLE DB включений механізм провайдерів, під якими розуміються постачальники даних, що знаходяться в надбудові над фізичним форматом даних. Їх називають сервіс-провайдерами, вони допомагають об'єднувати в однотипну сукупність об'єкти, пов'язані з різноманітними джерелами даних.
Інтерфейс OLE DB може використовувати для доступу до джерел даних інтерфейс ODBC. В цьому випадку застосовується провайдер OLE DB для доступу до ODBC -даних. Таким чином, інтерфейс OLE DB не замінює інтерфейс ODBC, а дозволяє організувати доступ до джерел даних через різні інтерфейси, і у тому числі через ODBC.
ADO містить сім об'єктів, які інкапсулюють в собі більшість операцій з базою даних, - Connection ( з'єднання ), Command ( команда ), Parameter ( параметр ), Recordset ( набір даних ), Field (поле), Property (властивість) і Error (помилка), - а також чотири набори об'єктів ( колекції ) - Fields (поля), Properties (властивості), Parameters (параметри ) і Errors (помилки).
Об'єкт Connection встановлює комунікаційний зв'язок між додатком і джерелом даних, дозволяє виконувати команди. Клас Connection включає наступні методи:
• Open ( Close ) - встановлення (закриття) фізичного з'єднання з джерелом даних;
• Execute - виконання команди для цього з'єднання ;
• BeginTrans, CommitTrans, RollbackTrans - управління транзакціями для поточного підключення, включаючи вкладені транзакції, якщо джерело даних підтримує роботу з ними.
Об'єкт Command. Команда, що направляється у базу даних, як правило, є SQL -команду або виклик деякої збереженої процедури. Об'єкт Command може настроюватися за допомогою параметрів, що задаються за допомогою створення колекції об'єктів класу Parameter. Клас Command включає наступні методи:
• Execute - виконання команди для цього з'єднання ;
• CreateParameter - створення нового об'єкту класу Parameter.
Колекція Parameters. Містить будь-які параметри, які використовуються разом з цим об'єктом Command. Клас Parameters містить наступні методи:
• Append ( Delete ) - додавання (видалення) параметра для вказаної колекції ;
• Item - витягання певного об'єкту Parameter.
На деякий об'єкт Parameter в колекції Parameters можна посилатися, використовуючи його порядковий номер або значення, присвоєне властивості Name цього об'єкту.
Об'єкт Recordset представляє набір записів, отриманий в результаті виконання запиту у базі даних. При створенні об'єкту Recordset покажчик поточного запису встановлюється на його перший запис (якщо така є), а властивостям BOF і EOF привласнюється значення FALSE. Якщо ніяких записів немає, то властивості Recordcount присвоюється значення 0, а властивостям BOF і EOF - значення TRUE. Клас Recordset включає наступні методи:
• MoveFirst, MoveLast, MoveNext, MovePrevious і Move - роблять переміщення покажчика поточного запису в припущенні, що провайдер підтримує виконання відповідної функції. У однонапрямлених об'єктах Recordset підтримується тільки метод MoveNext. При використанні вказаних методів для переміщення по записах результуючого набору для виявлення його початку і кінця можуть застосовуватися властивості BOF і EOF об'єкту Recordset ;
• AddNew, Update, Delete - здійснюють додавання нових записів, оновлення і видалення наявних записів, пов'язаних з відкритим об'єктом;
• Open ( Close ) - виконують відкриття (закриття) курсора, що представляє результати виконання команди.
Колекція Fields. Об'єкт Recordset містить колекцію Fields, що складається з об'єктів класу Field, кожен з яких відповідає стовпцю даних об'єкту Recordset. Як і при роботі з об'єктами Parameter, на окремий об'єкт Field в колекції Fields можна посилатися, використовуючи його порядковий номер або ім'я.
Об'єкт Connection
Розглянемо можливість з'єднання з базою даних з мов сценаріїв.
ASP -сценарій, працюючий з базою даних, в першу чергу повинен підключитися до неї. Після цього можна виконувати інструкції SQL і створювати набори записів. Існує спеціальний об'єкт Connection, керівник підключенням до бази даних.
Об'єкт Connection дозволяє встановлювати сеанси зв'язку з джерелами даних; він забезпечує функціонування механізму для ініціалізації і встановлення з'єднання, виконання запитів і використання транзакцій.
Створення з'єднання з базою даних включає наступні кроки:
• спочатку викликається метод CreateObject() об'єкту Server, що створює об'єктну змінну cn типу Connection. Об'єкт Connection визначений у бібліотеці ADODB :
• Dim cn
Set cn=Server.CreateObject("ADODB.Connection")
• далі можна використовувати метод Open об'єкту Connection для установки з'єднання c провайдером ODBC. Провайдер визначається за допомогою установки властивості Provider. Якщо воно не визначене, то за умовчанням буде використаний провайдер MSDASQL - ця скорочена назва драйвера OLE DB Microsoft для SQL Server :
cn.provider "MSDASQL"
• потім викликається метод Open() об'єкту Connection, що відкриває з'єднання із заданим джерелом даних.
Послатися на базу даних SQL Server з ASP -сценарію можливо двома способами:
• шляхом створення джерела даних ( DSN );
• за допомогою рядка з'єднання (без застосування DSN ).
У першому випадку створене заздалегідь джерело даних з ім'ям mystud використовується для з'єднання з базою даних таким чином:
cn.open "mystud", "user1", "123"
Тут для методу Open вказується DSN бази даних, ім'я користувача і пароль.
У другому випадку рядка з'єднання містять усю інформацію, необхідну ADO для того, щоб створити з'єднання із зовнішнім джерелом даних. Приклад такого рядка :
""uid=user1;driver={SQL Server};server=its;
database=basa_user1"
Рядок створює з'єднання з базою даних basa_user1 на MS SQL Server з ім'ям its, використовуючи драйвер для SQL Server і ім'я користувача user1. Якщо потрібний пароль, то необхідно додати підрядок pwd=<пароль>:
""uid=user1;pwd=123;driver{SQL Server};
server=its;
database=basa_user1"
Такий рядок підійде для з'єднання з базою даних в тексті сценарію замість джерела даних :
cn.open "uid=user1;driver={SQL Server};
server=its;
database=basa_user1"
чи
cn.open "uid=user1; pwd=123;
driver={SQL Server};
server=its;database=basa_user1"
Опустивши деякі подробиці роботи з API -інтерфейсом, приведемо невеликий фрагмент сценарію на мові VBScript для серверної сторони, що виконує вибірку і зміну інформації у базі даних учбового прикладу.
Dim cn
Dim rst
Set cn=Server.CreateObject("ADODB.Connection")
Set rst=Server.CreateObject("ADODB.Recordset")
cn.open "uid=user1;pwd=123;
driver={SQL Server};
server=its;database=basa_user1"
rst.open "SELECT назва, тип, ціна
FROM товар", cn
do until rst.eof
response.write rst.fields(0)
response.write rst.fields(1)
response.write rst.fields(2) & "<br>"
rst.movenext
loop
Приклад 18.3. Виконання статичного SQL -запиту до учбової бази даних з VBScript -сценарію.
Приклад 18.4. Виконання динамічного SQL -запиту до учбової бази даних з VBScript -сценарію.
Для створення динамічного запиту зміни даних на сервері скористаємося об'єктом Command з параметрами.
Dim cn
Dim rst
Dim cmd
Set cn=Server.CreateObject("ADODB.Connection")
Set rst=Server.CreateObject("ADODB.Recordset")
Set cmd=Server.CreateObject("ADODB.Command")
cn.open "uid=user1;pwd=123;
driver={SQL Server};
server=its;database=basa_user1"
Set cmd.ActiveConnection=cn
Dim prm1, prm2
' ' створення параметрів
prm1=Server.CreateObject("ADODB.Parameter")
prm2=Server.CreateObject("ADODB.Parameter")
' ' визначення динамічного запиту
cmd.CommandText="update товар set ціна=?
where назва="?
cmd.CommandType=adCmdText
cmd.Prepared=True
' ' визначення параметра, що відповідає
' ' першому знаку ? в SQL -запиті
Set prm1=сmd.CreateParameter("par1",
adInteger, adParamInput,, 160)
' ' визначення параметра, що відповідає
' ' другому знаку ? в SQL -запиті
Set prm2=сmd.CreateParameter("par2", adChar
adParamInput, 20, "Трюфелі" )
' ' додавання параметрів в колекцію параметрів
cmd.Parameters.Append prm1
cmd.Parameters.Append prm2
' ' виконання SQL -запиту
cmd.Execute
Приклад 18.4. Виконання динамічного SQL -запиту до учбової бази даних з VBScript -сценарію.
На сьогоднішній день (і в осяжному майбутньому) мова SQL є єдиним визнаним стандартом мови баз даних, підтримуваним всіма основними постачальниками СУБД. З роками (а історія SQL налічує вже близько 30 років) мова розвивається і ускладнюється. Добре володіння мовою SQL є обов'язковим для професійних розробників додатків баз даних та їх адміністраторів. У курсову роботу включені теми, що є, по-перше, найбільш важливими для користувачів і розробників додатків і, по-друге, найбільш проробленими в поточній версії стандарту. У вступній частині курсової роботи обговорюються історія мови, її основні концепції, типи даних, допустимі в SQL. Наводиться огляд підходів SQL до визначення даних і маніпулювання ними. В основній частині послідовно обговорюються наступні теми: значення, базові функції і вирази SQL; арифметичні вирази з перемикачами і перетворенням типу, вирази зі рядковими значеннями; види предикатів, допустимих в логічних виразах; з'єднання та теоретико-множинні операції; види виразів запитів; обмеження цілісності і посилальна цілісність; тригери; вбудована SQL і мова модулів; принципи роботи з курсорами; привілеї, користувачі і безпека; управління транзакціями; управління з'єднаннями і віддалений доступ до баз даних; збережені процедури і функції; динамічний SQL; інтерфейс рівня викликів; діагностика та управління помилковими ситуаціями; питання інтернаціоналізації та локалізації; інформаційна схема.
http://www.intuit.ru/department/database/sql/