Завантажити розв'язання
В завданні розглядалась база даних предметної області «Енергетика», схему якої можна представити у наступному вигляді:
База даних містить лише тривіальні зв’язки з множинністю «один до багатьох» за відповідними полями пов’язаних таблиць. Ці зв’язки і відображені на рисунку вище.
Розглянемо почергово запити, які необхідно було реалізувати.
Відобразіть електростанції, фактична електрична потужність яких становить принаймні 1 ГВт (гігават).
Цей запит є тривіальним запитом на просту умову:
SELECT Електростанції.Назва
FROM Електростанції
WHERE Електростанції.[Фактична електрична потужність] >= 1000;
Відобразіть обсяги виготовленої Хмельницькою АЕС електроенергії за кожен рік окремо.
Цей запит дещо складніший за попередній, оскільки передбачає використання простої умови та операції об’єднання таблиць.
Код запиту, що пропонується в якості ефективного розв’язання задачі, є наступним:
SELECT [Обсяги виготовлення].Рік, [Обсяги виготовлення].Обсяг
FROM Електростанції INNER JOIN [Обсяги виготовлення] ON Електростанції.Ідентифікатор=[Обсяги виготовлення].Електростанція
WHERE Електростанції.Назва=”Хмельницька АЕС”;
Якщо вважати код Хмельницької АЕС відомим (50 у поданій заготовці), запит можна спростити:
SELECT [Обсяги виготовлення].Рік, [Обсяги виготовлення].Обсяг
FROM [Обсяги виготовлення]
WHERE [Обсяги виготовлення].Електростанція=50;
Цей запит не зовсім чітко виконує поставлене завдання, але теж має право на існування та оцінюється в повну кількість балів.
Для введеної користувачем атомної електростанції (користувач вводить назву) відобразіть діючі в ній енергоблоки.
В цьому випадку позбутися операції об’єднання вже не вийде. Нам потрібно накласти умову на назву електростанції, що міститься в таблиці Електростанції, та відобразити дані про енергоблоки, що містяться в таблиці Енергоблоки АЕС.
Код запиту, який розв’язує поставлене завдання, є наступним:
SELECT [Енергоблоки АЕС].*
FROM [Енергоблоки АЕС] INNER JOIN Електростанції ON [Енергоблоки АЕС].Електростанція=Електростанції.Ідентифікатор
WHERE (Електростанції.Назва = [Введіть назву електростанції]) AND ([Енергоблоки АЕС].[Введення в експлуатацію] IS NOT NULL) AND ([Енергоблоки АЕС].[Виведення з експлуатації] IS NULL);
Тут поле [Введіть назву електростанції] є параметром нашого запиту та призведе до відображення діалогового вікна в ході виконання з наступним змістом:
Відобразіть дані про гідроелектростанції (ГЕС), що розташовані на перетині двох річок.
Цей запит є значно складнішим за попередні. Спочатку слід сформувати пари річок, на яких розташовані ГЕС за допомогою операції об’єднання двох екземплярів однієї і тієї ж таблиці. Потім слід накласти умову рівності поля ГЕС, що позначає ідентифікатор електростанції, для річок в кожній з пар. На виході отримаємо окрім потрібних нам пар річок ще й пари, що містять двічі одну й ту ж річку. Аби прибрати повтори та цей недолік накладемо на назви річок додаткову умову: залишимо лише ті пари, в яких спочатку знаходиться менша за алфавітним порядком річка.
Загалом код запиту матиме наступний вигляд:
SELECT [Річки ГЕС].ГЕС
FROM [Річки ГЕС] INNER JOIN [Річки ГЕС] AS [Річки ГЕС_1] ON [Річки ГЕС].ГЕС=[Річки ГЕС_1].ГЕС
WHERE [Річки ГЕС].Річка<[Річки ГЕС].Річка;
Відобразіть дані про електростанції, для яких відсутні дані про виготовлення ними електроенергії.
Цей запит є яскравим прикладом знаходження доповнення до множини об’єктів (або різниці множин). Ми володіємо даними про електростанції та легко можемо отримати дані про електростанції, про які в нас є дані щодо виготовленої ними електроенергії. Останнє легко записується наступним запитом:
SELECT DISTINCT Електростанції.*
FROM Електростанції INNER JOIN [Обсяги виготовлення] ON Електростанції.Ідентифікатор=[Обсяги виготовлення].Електростанція;
Відповідь на поставлене перед нами запитання є по суті різницею множини всіх електростанцій та тих електростанцій, дані про яких наявні.
Частина популярних СКБД для таких випадків пропонує спеціальний оператор MINUS, який залишає тільки ті рядки першого запиту, які відсутні в другому. Проте Access до таких СКБД не відноситься і такий оператор в цьому середовищі відсутній.
Існує кілька способів вирішення задачі за допомогою наявних в Access інструментів.
Спосіб 1. Використання оператора NOT IN.
SELECT Електростанції.*
FROM Електростанції
WHERE Електростанції.Ідентифікатор NOT IN (
SELECT DISTINCT Електростанції.Ідентифікатор
FROM Електростанції INNER JOIN [Обсяги виготовлення] ON Електростанції.Ідентифікатор=[Обсяги виготовлення].Електростанція;
);
В вищенаведеному запиті ми обираємо дані лише про ті електростанції, ідентифікаторів яких немає серед ідентифікаторів електростанцій з другого запиту (тобто електростанції, які відсутні в списку електростанцій з даними про виготовлення електроенергії).
Насправді, цей запит можна значно спростити. Ідентифікатори електростанцій (а в другому запиті зараз нам потрібні тільки вони) ми цілком можемо отримати й з таблиці Обсяги виготовлення, адже там знаходяться ідентифікатори лише тих електростанцій, для яких дані наявні. Отож здійснювати об’єднання в другій таблиці зовсім не обов’язково.
Більш оптимальний запит матиме наступний вигляд:
SELECT Електростанції.*
FROM Електростанції
WHERE Електростанції.Ідентифікатор NOT IN (
SELECT [Обсяги виготовлення].Електростанція
FROM [Обсяги виготовлення];
);
Спосіб 2. Використання зовнішнього об’єднання
Окрім внутрішнього об’єднання (INNER JOIN), яке передбачає об’єднання лише тих рядків обох таблиць, що мають відповідні їх записи іншої таблиці, зовнішнє (OUTER JOIN) об’єднання дозволяє включати до результату ще й ті об’єкти, які не мають відповідників.
Наприклад, у зв’язку між класами та учнями бази даних «Школа», внутнішнє об’єднання дозволяє отримати у вигляді однієї таблиці дані про учня та клас, в якому цей учень навчається. Але до цієї таблиці не потраплять дані про класи, що не містять учнів.
Зовнішні об’єднання в теорії реляційних баз даних поділяють на:
- ліве об’єднання, LEFT JOIN (обираються усі записи таблиці з лівого боку від LEFT JOIN та лише ті записи таблиці з правого боку, що мають відповідний їм запис в лівій таблиці);
- праве об’єднання, RIGHT JOIN (обираються усі записи таблиці з правого боку від RIGHT JOIN та лише ті записи таблиці з лівого боку, що мають відповідний їм запис в правій таблиці);
- повне об’єднання, FULL JOIN (обираються усі записи таблиць з правого та лівого боку від FULL JOIN та їм співставляються поєднані записи з іншої таблиці, якщо такі записи існують).
Слід зазначити, що для записів, що містять об’єкти без відповідника, на місці полів іншої таблиці знаходяться порожні значення (NULL).
Загалом, множини, які породжуються цими об’єднаннями, задовольняють наступним властивостям:
FULL JOIN = LEFT JOIN RIGHT JOIN
INNER JOIN LEFT JOIN
INNER JOIN RIGHT JOIN
З використанням зовнішнього об’єднання (а саме LEFT JOIN) запит, який дає відповідь на поставлене запитання, можна написати наступним чином:
SELECT DISTINCT Електростанції.*
FROM Електростанції LEFT JOIN [Обсяги виготовлення] ON Електростанції.Ідентифікатор=[Обсяги виготовлення].Електростанція
WHERE [Обсяги виготовлення].Електростанція IS NULL;
Слід зауважити, що в СКБД Access цей запит виконуватиметься значно швидше, аніж поданий у способі 1, якщо кількість даних буде достатньо великою.
Як можна задати тип об’єднання в режимі конструктора пропонуємо дослідити самостійно за допомогою мережі Інтернет.
Окрім запитів, у завданні також пропонувалося створити дві прості форми.
- Форму Електростанції для відображення даних про усі електростанції та обсяги виготовлення ними електроенергії відповідно до зразка:
Для створення цієї форми слід було використати майстра форм та обрати відповідні поля з таблиць Електростанції та Обсяги виготовлення. Якщо залишити інші налаштування за промовчанням – буде відображено форму з поєднаною підформою, що відповідатиме поданому зразку.
- Форму Річки з ГЕС для відображення переліку річок, на яких розташовані гідроелектростанції, відповідно до наступного зразка:
Оскільки форма відображає нетривіальний набір даних, потрібно спочатку побудувати запит, який формує результат для відображення.
Запит легко будується за допомогою інструкції DISTINCT:
SELECT DISTINCT [Річки ГЕС].Річка
FROM [Річки ГЕС];
Після цього слід було на основі цього запиту створити звичайну форму на кілька елементів.