Вище було показано, що в багатотабличному запиті можна об'єднувати дані таблиць, проте цікаве і те. що та ж сама методика може використовуватися для об'єднання разом двох копій одиночної таблиці. Для об'єднання таблиці з собою можна зробити кожний рядок таблиці одночасне і комбінацією її з собою і комбінацією з кожним іншим рядком таблиці, а потім оцінити кожну комбінацію в термінах предиката. Це дозволяє легко створювати певні види зв'язків між різними елементами усередині одиночної таблиці. Наприклад, припускає зобразити об'єднання таблиці з собою, як об'єднання двох копій однієї і тієї ж таблиці, причому вона насправді не копіюється, але SQL виконує команду так, як якби це було зроблено.
Використовування команди для об'єднання таблиці з собою аналогічно тому прийому, який використовується для об'єднання декількох таблиць. Коли об'єднується таблиця з собою, всі повторювані імена стовпця заповнюються префіксами імені таблиці. Щоб посилатися до цих стовпців усередині запиту, необхідно мати два різні імена для цієї таблиці. Це можна зробити за допомогою визначення тимчасових імен, званих псевдонімами, які визначаються в пропозиції FROM запиту. Синтаксис в цьому випадку наступний: після імені таблиці залишають пропуск, а потім повинен слідувати псевдонім для неї.
Наприклад, для пошуку студентів, що мають однаковий розмір стипендії, можна скористатися наступним запитом:
SELECT FIRST.SFAM, SECOND.SFAM, FIRST.STIP
FROM STUDENTS FIRST, STUDENTS SECOND
WHERE FIRST.STIP = SECOND.STIP;
Результат такого запиту буде наступним:
Поляків Поляків 25.50
Поляків Нагірний 25.50
Сфарова Старова 17.00
Гріценко Гріценко 0.00
Гріценко Котенко 0.00
Кофенко Гріценко 0.00
Котенко Кофенко 0.00
Нагірний Поляків 25.50
Нагірний Нагірний 25.50
В даному прикладі SQL поводиться так. неначебто він з’єднував дві різні таблиці, звані FIRST і SECOND, тобто псевдоніми дозволяє одній і тій же таблиці бути обробленою незалежно. Звернете увагу на те. що псевдоніми можуть використовуватися в речення SELECT до їх оголошення в
речення FROM, проте SQL буде спочатку припускати будь-які псевдоніми і може відхилювати команду, якщо вони не будуть визначені далі в запиті. Крім того, необхідно пам'ятати, що псевдонім існує тільки тоді, коли команда виконується, а після завершення запиту псевдоніми, використовувані в ньому, більше не мають ніякого значення.
Висновок останнього прикладу має два значення для кожної комбінації прізвищ, причому другий раз в зворотному порядку це пов'язано з тим, що кожне значення показане уперше в кожному псевдонімі і другий раз в предикаті, тобто поточне значення в першому псевдонімі спочатку вибирається в комбінації із значенням в другому псевдонімі, а потім навпаки. Наприклад, в нашому випадку Поляків вибрався разом з Нагірним, а потім Нагірний вибрався разом з Поляковим і т. ін. Крім того, кожний рядок був порівняний сама з собою, наприклад Поляків з Поляковим.
Кращий спосіб уникнути це полягає в накладенні порядку на два значення так, щоб один міг бути меншим, ніж інший або передував йому в алфавітному порядку. Це робить предикат асиметричним щодо зв'язку, тому ті ж самі значення в зворотному порядку не будуть вибрані знов. Отже, приклад можна модифікувати таким чином:
SELECT FIRST.SFAM, SECOND.SFAM, FIRST.STIP
FROM STUDENTS FIRST, STUDENTS SECOND WHERE FIRST.STIP = SECOND.STIP AND FIRST.SFAM < SECOND.SFAM;
Результат цього запиту буде таким:
Гріценко Котенко 0.00
Нагірний Поляків 25.50
Зокрема, Гріценко передує Котенко в алфавітному порядку, тому комбінація задовольняє обом умовам предиката і з'являється у висновку. Якщо та ж сама комбінація з'являється в зворотному порядку, тобто Котенко в псевдонімі першої таблиці порівнюється з Гріценко в другій таблиці, то друга умова не виконується. Із аналогічної причини у висновок не потрапляє порівняння з самим собою. Якщо ж виникла необхідність порівняння рядків з ними ж, то в запитах варто використати < = замість <.
Таким чином, можна використати цю особливість SQL для перевірки певних видів помилок. Наприклад, якщо вважати, що учбовий предмет може вести тільки один викладач, то всякий раз в таблиці PREDMET необхідна перевірка на цю умову. При цьому кожного разу, коли код предмета з'являється в таблиці PREDMET, він повинен співпадати з відповідним номером викладача. Наступна команда буде визначати будь-які неузгодженості в цій області:
Виведення для даного прикладу не буде, т.к. даних, що задовольняють предикату в даній таблиці немає. Логіка цього запиту достатньо проста: з таблиці буде вибиратися черговий рядок і запам'ятовуватися під першим псевдонімом. Після цього SQL почне перевіряти її в комбінації з кожним рядком таблиці під другим псевдонімом. Якщо комбінація рядків задовольняє предикату, то вона вибирається для висновку, тобто якщо буде знайдений учбовий предмет, в якого з'ясується неспівпадання номера викладача в таблиці під першим і другим псевдонімом.
Об'єднання таблиці з собою - це ситуація, що найбільш часто зустрічається, коли використовуються псевдоніми, проте їх можна використати у будь-який час для створення альтернативних імен для таблиць в запиті, наприклад, у випадку, якщо таблиці мають дуже довгі і складні імена.
Більше того, припускає використати будь-яке число псевдонімів для однієї таблиці в запиті, хоча використовування більше двох в одній пропозиції SELECT часте буде надмірністю. Наприклад, для призначення стипендії на наступний семестр необхідно переглянути всі варіанти комбінацій студентів з різними розмірами стипендії: 25.50, 17.00 і 0.00 у. о. Тоді такий запит буде виглядати таким чином:
SELECT FIRST.SFAM, SECOND.SFAM, THIRD.SFAM
FROM STUDENTS FIRST, STUDENTS SECOND, STUDENTS THIRD
WHERE FIRST.STIP = 25.50
AND SECOND.STIP = 17.00 AND THIRD.STIP = 0.00;
Висновок для цього запиту слідує нижче:
SFAM SFAM SFAM
Поляків Старова Гріценко
Поляків Старова Котеняті
Нагірний Старова Гріценко
Нагірний Старова Котеняті
Як видно з результату, цей запит знаходить всі комбінації студентів з трьома різними розмірами стипендії, тому перший стовпець висновку складається із студентів із стипендією 25.50, другий з 17.00 і останній - з 0.00. які повторюються у всіх можливих комбінаціях. Цікаво, що такий запит не може бути виконаний з GROUP BY або ORDER BY, оскільки вони порівнюють значення тільки в одному стовпці висновку.
В реченні SELECT допускає не використати кожний псевдонім або таблицю, які згадувалися в пропозиції FRОМ запиту, тобто псевдонім або таблиця використовуються тільки для створення предиката. Розглянемо чисто ілюстративний приклад наступного запиту:
SELECT FIRST.SFAM, FIRST.SIMA, FIRST.SOTCH
FROM STUDENTS FIRST, STUDENTS SECOND
WHERE FIRST.STIP = 25.50 AND SECOND.STIP = 0.00;
Виведення даного запиту наступний:
SFAM SIMA SOTCH
_______ і_____________________
Поляків Анатолій Олексійович
Поляків Анатолій Олексійович
Нагірний Євгеній Васильович
Нагірний Євгеній Васильович
Фактично тут дані про студентів, що мають стипендію 25.50. повторюється стільки разів. скільки існує їхніх поєднань із студентами, не одержуючих стипендію (тобто для яких STIP = 0.00).
В SQL передбачається створення об'єднання, яке включає і різні таблиці, і псевдоніми одиночної таблиці. Наступний запит об'єднує таблицю з даними про успішність для того, щоб знайти учбові предмети, які вже здані більш ніж одним студентом, і таблицю учбових предметів:
SELECT PREDMET.PNAME, FIRST.SNUM, SECOND.SNUM
FROM USP FIRST, USP SECOND, PREDMET
WHERE FIRST.PNUM = SECOND.PNUM
AND PREDMET.PNUM = FIRST.PNUM AND FIRST.SNUM < SECOND.SNUM;
Результати цього запиту наступні:
PNAME SNUM SNUM
Математика 3413 3412
У виведенні маємо пари номерів студентів, що здали той або інший предмет, визначуваний по назві з таблиці учбових предметів.
Як вже було сказано, операція об'єднання в SQL поєднує інформацію з двох таблиць, формуючи пари зв'язаних рядків з них. З'єднану таблицю утворюють пари тих рядків з різних таблиць, в яких в зв'язаних стовпцях містяться однакові значення. Якщо рядок одній з таблиць не має пари, то об'єднання може привести до несподіваних результатів.
Припустимо, що в таблиці TEACHERS з'явився запис {NULL, Федченко. Світлана, Геннадіївна. 01/09/1999}, в якій табельний номер ще не відомий. Несподівані результати можуть вийти при використовуванні наступних запитів:
SELECT TFAM, TIMA, ТОТСН
FROM TEACHERS;
Висновок цього запиту наступний:
TFAM TIMA ТОТСН
Никуліна Валентина Іванівна
Костиркин Олег Володимирович
Казанко Віталій Володимирович
Позднякова Любов Олексіївна
Загарійчук Ігор Дмитрович
Федченко Світлана Геннадіївна
і запиту
SELECT TEACHERS.TFAM, PREDMET.PNAME
FROM TEACHERS, PREDMET
WHERE TEACHERS.TNUM = PREDMET.TNUM;
Висновок цього запиту такий:
TFAM PNAME
Никуліна Фізика
Костиркин Хімія
Казанко Математика
Позднякова Економіка
Загарійчук Філософія
- Здавалося б, що ці два запити повинні давати однакову кількість рядків, але результати першого запиту налічують шість рядків, а другого - тільки п'ять. Це пов'язано з тим. що викладач Федченко зараз ще не отримала номера і відповідний запис має значення NULL в полі TNUM, отже, це значення не співпадає ні з одним ідентифікатором учбового предмета в таблиці PREDMET. Значить, висновку для цього рядка в другому запиті не буде - вона просто зникає з об'єднання. Таким чином, стандартне SQL-об'єднання може привести до втрати інформації, якщо об'єднувані таблиці містять незв'язані рядки.
Другий запит можна модифікувати таким чином:
SELECT TEACHERS.TFAM, PREDMET.PNAME
FROM TEACHERS, PREDMET
WHERE TEACHERS.TNUM *= PREDMET. TNUM;
і його висновок буде більш повним:
TFAM PNAME
Никуліна Фізика
Костиркин Хімія
Казанко Математика
Позднякова Економіка
Загарійчук Філософія
Федченко NULL
Такі результати запиту виходять за допомогою іншої операції об'єднання, званої зовнішнім об'єднанням таблиць, яке в речення WHERE позначається символом *=. Зовнішнє об'єднання є розширенням стандартного об'єднання, описаного вище і іноді званого внутрішнім об'єднанням таблиць. Майте на увазі, що в стандарті SQL1 дано визначення тільки внутрішнього об'єднання, а поняття зовнішнього об'єднання в ньому відсутнє.
Розглянемо повне зовнішнє об'єднання таблиць на прикладі наступного запиту: