Справочник от Автор24
Поделись лекцией за скидку на Автор24

Многотабличные и вложенные запросы

  • 👀 235 просмотров
  • 📌 203 загрузки
Выбери формат для чтения
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Конспект лекции по дисциплине «Многотабличные и вложенные запросы» pdf
ЛЕКЦИЯ № 8 3.3. Многотабличные и вложенные запросы..................1 3.3.1. Соединения таблиц............................................2 3.3.1.1. Неявное соединение таблиц...................2 3.3.1.2. Явное соединение таблиц.......................6 3.3.1.3. Реализация стандартных операций реляционной алгебры.. 13 3.3.1.4. Соединение таблицы со своей копией. 17 3.3. МНОГОТАБЛИЧНЫЕ И ВЛОЖЕННЫЕ ЗАПРОСЫ СУБД поддерживают 3 варианта запросов к множеству таблиц с помощью одного SQL-запроса на выборку: соединения, подзапросы и объединения [29, 52]. Эти 3 метода поиска данных во множестве таблиц существенно отличаются друг от друга и, как правило, решают разные виды поисковых задач. Соединение является одной из наиболее востребованных операций в запросе SELECT. Поскольку большинство БД являются нормализованными, часто возникает необходимость получения данных из нескольких таблиц. Соединения дают возможность формировать результирующий набор из столбцов одной или более таблиц, которые хранят связанные данные. Множество столбцов, выбранных из каждой таблицы, называются потоками. Процесс соединения объединяет выбранные столбцы в единый выходной набор данных. Стандарты SQL поддерживают 2 варианта синтаксиса соединения: неявное и явное. Неявное соединение соответствует более старому SQL-стандарту. Таблицы, участвующие в соединении, задаются списком с разделяющими запятыми в секции FROM запроса SELECT. Условия для связи таблиц задаются среди условий поиска секции WHERE. Не существует специального синтаксиса для указания, какие условия используются для поиска, а какие – для соединения. В стандарте SQL:92 введен более универсальный синтаксис явного соединения, которое осуществляется с помощью конструкции JOIN…ON. Структура конструкции JOIN…ON дает возможность отличать условие соединения от условий поиска. Следует отметить, что неявное соединение может быть всегда заменено эквивалентным явным, обратное же возможно не всегда. Подзапросом является запрос, заключенный в круглые скобки и вложенный в секцию SELECT, FROM, WHERE или HAVING основного (внешнего) запроса SELECT или других запросов, использующих эти секции. Правила построения подзапросов изменяются в соответствии с целью запроса. Оба метода – и соединения, и подзапросы – используют слияние потоков данных из строк различных таблиц. В связи с этим при некоторых условиях их роли могут совпадать. Тем не менее, рациональнее использовать разные 1 методы для решения разных задач, а именно: для сравнения значений агрегатных функций с другими значениями – подзапросы, для выборки информации из нескольких таблиц – соединения [53]. В этом заключается основное различие рассматриваемых видов запросов ко множеству таблиц. Кроме того, соединения позволяют формировать набор данных из столбцов таблицы или таблиц, хранящих связанные данные, в то время, как в подзапросах результаты внешнего и внутреннего запросов могут быть и не связаны. Запросы объединения, реализуемые с помощью оператора UNION, дают возможность выбрать строки из различных наборов данных в объединенный набор данных, причем подмножества не обязательно должны быть связаны друг с другом – просто они должны соответствовать друг другу структурно. Соединения, подзапросы и объединения не являются взаимоисключающими. Соединения и объединения могут включать подзапросы, и некоторые подзапросы могут содержать соединения. 3.3.1. Соединения таблиц 3.3.1.1. Неявное соединение таблиц Как уже отмечалось, различные виды соединений используются для получения составных наборов данных, содержащих столбцы из нескольких таблиц, которые хранят связанные данные. Формат секций FROM и WHERE при неявном соединении таблиц имеет вид: FROM <таблица1> [[AS] псевдоним1], <таблица2> [[AS] псевдоним2]… [WHERE <условие_соединения> [AND <условие_поиска>]… ], где <условие_соединения>::= <таблица1>.столбец <операция_сравнения> <таблица2>.столбец, <операция_сравнения> ::= { = | < | > | {<= | !> } | { >= | !< } | { <> | != }}; В Oracle операции сравнения !> и !< не используются. Особенности синтаксиса неявных соединений.  Использование более одной таблицы в секции FROM (список таблиц с разделяющими запятыми).  Среди остальных условий поиска секции WHERE применяется операция сравнения для создания выражения, которое определяет связанные столбцы, используемые для соединения указанных таблиц (<условие_соединения>). При этом соединение на основе точного равенства между двумя столбцами называется соединением по равенству (эквивалентности). Алгоритм выполнения запросов на неявное соединение таблиц состоит из нескольких этапов [53]. 1. Вычисляется декартово произведение таблиц, входящих в соединение, т. е. для каждой строки одной из таблиц берутся все возможные сочетания строк из других таблиц. 2 2. Производится отбор строк из полученной таблицы согласно условиям в секции WHERE. 3. Осуществляется проекция (вывод) по столбцам, указанным в списке возвращаемых элементов. Среди запросов на соединение таблиц наиболее распространены запросы к таблицам, которые связаны с помощью отношения родитель-потомок. Чтобы использовать в запросе отношение родитель-потомок, необходимо задать <условие_соединения>, в котором первичный ключ родительской таблицы сравнивается с внешним ключом таблицы-потомка (обычно имена этих столбцов совпадают в связанных таблицах). Несмотря на то, что в языке определения данных присутствует возможность декларативного задания первичных и внешних ключей таблиц, связь, о которой идет речь, должна всегда явно указываться в секции WHERE запроса SELECT. Например, необходимо вывести для всех абонентов названия улиц, на которых они проживают (рис. 3.82). Для этого надо каждую строку из таблицы Abonent связать по полю внешнего ключа (столбец StreetCD в таблице Abonent) с таблицей улиц (столбец StreetCD в таблице Street). Следующий запрос позволяет получить требуемый результат: SELECT Abonent.Fio, Street.StreetCD, Street.StreetNM FROM Abonent, Street WHERE Abonent.StreetCD = Street.StreetCD; Данный запрос, как и большинство приведенных в учебнике запросов с неявным и явным соединением, корректен как в Firebird, так и в Oracle и MS SQL Server. При этом в MS SQL Server результаты многих многотабличных запросов будут отличаться порядком следования строк от результатов, приведенных для Firebird. FIO Аксенов С.А. Мищенко Е.В. Конюхов В.С. Тулупова М.И. Свирина З.А. Тимошкина Н.Г. Лукашина Р.М. Шубина Т. П. Стародубцев Е.В. Шмаков С.В. Маркова В.П. Денисова Е.К. STREETCD 3 3 3 7 7 6 8 8 4 4 4 4 STREETNM ВОЙКОВ ПЕРЕУЛОК ВОЙКОВ ПЕРЕУЛОК ВОЙКОВ ПЕРЕУЛОК КУТУЗОВА УЛИЦА КУТУЗОВА УЛИЦА МОСКОВСКАЯ УЛИЦА МОСКОВСКОЕ ШОССЕ МОСКОВСКОЕ ШОССЕ ТАТАРСКАЯ УЛИЦА ТАТАРСКАЯ УЛИЦА ТАТАРСКАЯ УЛИЦА ТАТАРСКАЯ УЛИЦА Рис. 3.82. Результат выполнения многотабличного запроса 3 Следует обратить внимание на то, что к столбцам таблиц обращение производится на основе полного имени столбца (указание таблицы, к которой он относится), чтобы исключить неоднозначности, возникающие в случае присутствия в разных таблицах столбцов с одинаковыми именами (например, столбцов StreetCD в таблицах Abonent и Street). Чтобы ускорить ввод запросов и сделать их более понятными, в списке таблиц можно определить псевдонимы таблиц (сокращенные имена). Например, предыдущий запрос можно записать более кратко: SELECT A.Fio, S.StreetCD, S.StreetNM FROM Abonent A, Street S WHERE A.StreetCD = S.StreetCD; В многотабличном запросе можно комбинировать условие соединения, в котором задаются связанные столбцы, с условиями поиска. Например, для вывода ФИО абонентов, которым за 2013 г. начислены суммы более 350 (рис. 3.83), можно использовать запрос: SELECT A.Fio, N.NachislSum FROM Abonent A, NachislSumma N WHERE A.AccountCD = N.AccountCD AND NachislYear = 2013 AND NachislSum > 350; FIO NACHISLSUM Термин «соединение» Конюхов В.С. 611,30 применяется к любому запросу, который Стародубцев Е.В. 444,45 объединяет данные Денисова Е.К. 528,44 нескольких таблиц БД Тимошкина Н.Г. 454,60 путем сравнения значений Рис. 3.83. Результат выполнения в парах столбцов этих запроса таблиц. Самыми многотабличного с комбинированным условием распространенными являются соединения по поиска равенству. Кроме этого, имеется возможность соединять таблицы с помощью других операций сравнения. Например, чтобы вывести все комбинации ФИО абонентов и исполнителей ремонтных заявок так, чтобы ФИО абонентов были больше при сравнении, можно использовать следующий запрос с соединением таблиц по неравенству: SELECT A.Fio, E.Fio FROM Abonent A, Executor E WHERE A.Fio > E.Fio; Как следует из данного примера, соединения таблиц по условиям, отличающимся от равенства, во многом искусственны. Поэтому в подавляющем большинстве случаев таблицы соединяются по равенству, а другие операции сравнения используются для дополнительного отбора строк в условии поиска. SQL позволяет соединять 3 и более таблицы, используя ту же самую методику, что и при соединении данных из двух таблиц. Например, чтобы в 4 предыдущем запросе вместе со значениями начислений вывести и значения оплат за тот же период и за ту же услугу (рис. 3.84), можно использовать соединение трех таблиц: SELECT A.Fio, N.NachislSum, P.PaySum FROM Abonent A, NachislSumma N, PaySumma P WHERE A.AccountCD = N. AccountCD AND A.AccountCD = P.AccountCD AND N.ServiceCD = P.ServiceCD AND N.NachislMonth =P.PayMonth AND N.NachislYear = P.PayYear AND NachislYear = 2013 AND NachislSum > 350; FIO Конюхов В.С. Стародубцев Е.В. Денисова Е.К. Тимошкина Н.Г. NACHISLSUM 611,30 444,45 528,44 454,60 PAYSUM 611,30 444,45 528,44 460,00 Рис. 3.84. Результат выполнения запроса на соединение трех таблиц Следует отметить, что результат выполнения запроса на неявное соединение более двух таблиц не зависит от порядка перечисления этих таблиц в секции FROM и от порядка указания условий соединения в секции WHERE. В таблицах соединяются только те строки, для которых выполняется <условие_соединения>, и независимо от порядка соединения результат будет одинаковый. Можно соединять данные из трех и более таблиц, связанных более чем одним отношением родитель-потомок. Например, для того чтобы определить исполнителей, которым назначены ремонтные заявки абонентов, необходимо соединить таблицы Abonent, Request и Executor. Для этого надо каждую строку из таблицы Request связать по полю внешнего ключа AccountCD со справочником абонентов (столбец AccountCD в таблице Abonent), а по полю внешнего ключа ExecutorCD – со справочником исполнителей (столбец ExecutorCD в таблице Executor). Для этого можно использовать такой запрос: SELECT DISTINCT A.Fio AS Fio_Abonent, E.Fio AS Fio_Executor FROM Abonent A, Executor E, Request R WHERE R.AccountCD = A.AccountCD AND R.ExecutorCD = E.ExecutorCD; Результат выполнения запроса представлен на рис. 3.85. FIO_ABONENT Аксенов С.А. Аксенов С.А. Аксенов С.А. FIO_EXECUTOR Стародубцев Е.М. Школьников С.М. Шлюков М.К. 5 Денисова Е.К. Денисова Е.К. Конюхов В.С. Лукашина Р.М. Мищенко Е.В. Мищенко Е.В. Мищенко Е.В. Мищенко Е.В. Свирина З.А. Стародубцев Е.В. Стародубцев Е.В. Тимошкина Н.Г. Шмаков С.В. Шубина Т. П. Булгаков Т.И. Школьников С.М. Стародубцев Е.М. Стародубцев Е.М. Булгаков Т.И. Стародубцев Е.М. Шлюков М.К. Шубин В.Г. Шубин В.Г. Стародубцев Е.М. Рис. 3.85. Результат на соединение трех таблиц выполнения Школьников С.М. Шлюков М.К. Стародубцев Е.М. Шубин В.Г. запроса Таким образом, при выполнении операции неявного соединения данные из двух таблиц комбинируются с образованием пар связанных строк, в которых значения сопоставляемых столбцов являются одинаковыми. Если одно из значений в сопоставляемом столбце одной таблицы не совпадает ни с одним из значений в сопоставляемом столбце другой таблицы, то соответствующая строка удаляется из результирующей таблицы. 3.3.1.2. Явное соединение таблиц Другим способом связывания таблиц является явное соединение, осуществляемое с помощью JOIN. Формат секции FROM при таком соединении таблиц имеет вид: FROM {<таблица1> [псевдоним1] <тип_соединения1> <таблица2> [псевдоним2] [ { ON <условие_соединения1> | USING (<список_столбцов>) }] } [<тип_соединения2> <таблица3> [псевдоним3] [ { ON <условие_соединения2> | USING (<список_столбцов>) }]]…, где <тип_соединения>::= {CROSS JOIN | [NATURAL] [{INNER | {LEFT | RIGHT | FULL} [OUTER]}] JOIN }. Итак, существуют различные типы явного соединения таблиц. 1. Перекрестное соединение CROSS JOIN используется без конструкции ON <условие_соединения>. CROSS JOIN эквивалентно декартовому произведению таблиц. То есть конструкция … FROM A CROSS JOIN B полностью эквивалентна конструкции … FROM A, B. Перекрестное (полное) соединение группирует строки таблиц по правилу «каждая с каждой». Первая строка первой таблицы соединяется с первой 6 строкой второй таблицы, потом первая строка первой таблицы соединяется со второй строкой второй таблицы и так до тех пор, пока в первой таблице не закончатся строки. 2. Уточненные соединения, которые предполагают явное задание условия соединения после ON или имен столбцов, по которым производится соединение, после USING. Для визуального представления различных типов соединения часто используются диаграммы Эйлера-Венна [54]. Диаграмма Венна представляет собой схематичное изображение всех возможных пересечений нескольких множеств и полезна для понимания, как происходит выборка данных в таблицах с использованием соединений и условий. Среди уточненных соединений выделяют:  INNER JOIN – «внутреннее» соединение (рис. 3.86). В таблицах соединяются только те строки, для которых выполняется <условие_соединения>: все значения связанных столбцов одной таблицы попарно находятся в заданном оператором сравнения отношении с соответствующими значениями связанных столбцов другой таблицы. Остальные строки из соединения исключаются. Этот вид соединения используется чаще всего. Рис. 3.86. Диаграмма Венна для «внутреннего» соединения  OUTER JOIN – «внешнее» соединение. Данное ключевое слово является необязательным и имеет смысл только в комбинации с ключевым словом определения типа внешнего соединения. Внешние соединения бывают трех типов: LEFT [OUTER] JOIN – «левое (внешнее)» соединение (рис. 3.87); выполняется сравнение значений связанных столбцов и в результат запроса включаются все строки левой таблицы и только те строки правой таблицы, для которых выполняется <условие_соединения> (для строк из левой таблицы, для которых не найдено соответствия в правой таблице, в столбцы, извлекаемые из правой таблицы, заносится NULL); Рис. 3.87. Диаграмма Венна для «левого (внешнего)» соединения 7 RIGHT [OUTER] JOIN – «правое (внешнее)» соединение (рис. 3.88); является зеркальным отображением левого внешнего соединения, в нем тоже сначала выполняется сравнение значений связанных столбцов, но в результат запроса включаются все строки правой таблицы и только те строки левой таблицы, для которых выполняется <условие_соединения> (для строк из правой таблицы, для которых не найдено соответствия в левой таблице, в столбцы, извлекаемые из левой таблицы, заносится NULL); Рис. 3.88. Диаграмма Венна для «правого (внешнего)» соединения FULL [OUTER] JOIN – «полное (внешнее)» соединение – это комбинация «левого» и «правого» соединения таблиц (рис. 3.89); позволяет возвращать все строки как из правой, так и из левой таблицы, включая те, которые не удовлетворяют условиям соединения (строки, у которых нет пары по связанным столбцам, возвращаются со значениями NULL в выходных столбцах «противоположной» таблицы). Рис. 3.89. Диаграмма Венна для «полного (внешнего)» соединения Если не указан тип соединения в JOIN, то он по умолчанию принимается за INNER. 3. Естественное соединение (NATURAL JOIN). Стандарт SQL определяет это соединение как результат соединения таблиц по всем одноименным столбцам. Соединяются те строки, в которых все значения одноименных столбцов одной таблицы попарно совпадают с соответствующими значениями одноименных столбцов другой таблицы. Остальные строки из соединения исключаются. Если одноименных столбцов нет, выполняется перекрестное соединение CROSS JOIN. Естественное соединение не требует задания каких-либо условий (используется без ON <условие_соединения>). Может применяться при внутреннем и внешнем соединении таблиц. В Oracle формат секции FROM существенных отличий от вышеприведенного не имеет. 8 В MS SQL Server формат секции FROM при явном соединении таблиц несколько отличается: FROM {<таблица1> [псевдоним1] <тип_соединения1> <таблица2> [псевдоним2] [ ON <условие_соединения1> ] } [<тип_соединения2> <таблица3> [псевдоним3] [ ON <условие_соединения2> ]]…, где <тип_соединения>::= { CROSS JOIN | { CROSS | OUTER } APPLY | { [ { INNER | {LEFT | RIGHT | FULL} [OUTER] } ] [<подсказка соединения>] JOIN } }. Из приведенного синтаксиса видны особенности реализации явных соединений в MS SQL Server [37]: - для задания условия соединения используется только ключевое слово ON, USING не поддерживается; - не поддерживается естественное соединение NATURAL JOIN; - может использоваться оператор APPLY с ключевыми словами CROSS и OUTER, который позволяет соединять таблицу с возвращающей табличное значение функцией (table valued function - TVF) по принципу перекрестного либо внешнего соединения; - может быть задана подсказка соединения, которая указывает оптимизатору запросов на выбор определенной стратегии соединения таблиц. В уточненных явных соединениях <условие_соединения>, указываемое после ON, аналогично рассмотренному выше условию соединения в секции WHERE. При соединении данных из нескольких таблиц конструкции JOIN и WHERE в большинстве случаев взаимозаменяемы. Однако зачастую конструкция JOIN является более удобной для понимания. Например, конструкция JOIN…ON дает возможность отличать условие соединения, указываемое после ON, от условия поиска, указываемого в секции WHERE. Например, необходимо вывести для всех абонентов названия и коды улиц, на которых они проживают. Решение этого примера на основе конструкции WHERE было приведено на рис. 3.82. Реализация запроса посредством явного внутреннего соединения таблиц, позволяющего выбрать только строки, которые есть и в таблице Street и в таблице Abonent, имеет вид: SELECT A.Fio, S.StreetCD, S.StreetNM FROM Abonent A INNER JOIN Street S ON A.StreetCD = S.StreetCD; Если в этом же примере использовать правое внешнее соединение, то получится список всех улиц и проживающих на них абонентов, если таковые имеются. Запрос выглядит так: SELECT A.Fio, S.StreetCD, S.StreetNM FROM Abonent A RIGHT JOIN Street S ON A.StreetCD = S.StreetCD; Результат выполнения запроса представлен на рис. 3.90. FIO Аксенов С.А. Мищенко Е.В. STREETCD STREETNM 3 ВОЙКОВ ПЕРЕУЛОК 3 ВОЙКОВ ПЕРЕУЛОК 9 Конюхов В.С. Тулупова М.И. Свирина З.А. Тимошкина Н.Г. Лукашина Р.М. Шубина Т. П. Стародубцев Е.В. Шмаков С.В. Маркова В.П. Денисова Е.К. NULL NULL NULL 3 7 7 6 8 8 4 4 4 4 5 1 2 ВОЙКОВ ПЕРЕУЛОК КУТУЗОВА УЛИЦА КУТУЗОВА УЛИЦА МОСКОВСКАЯ УЛИЦА МОСКОВСКОЕ ШОССЕ МОСКОВСКОЕ ШОССЕ ТАТАРСКАЯ УЛИЦА ТАТАРСКАЯ УЛИЦА ТАТАРСКАЯ УЛИЦА ТАТАРСКАЯ УЛИЦА ГАГАРИНА УЛИЦА ЦИОЛКОВСКОГО УЛИЦА НОВАЯ УЛИЦА Рис. 3.90. Результат правого внешнего соединения Для каждого абонента выводится название улицы, на которой он проживает, а если на какой-либо улице не проживают абоненты, то в столбце Fio строки для данной улицы выводится NULL. Если в данном примере использовать левое внешнее соединение, то результат будет совпадать с результатом внутреннего соединения (см. рис. 3.82), так как в учебной БД нет абонентов, для которых не указана улица проживания. Если же использовать полное внешнее соединение, то для данного примера результат будет совпадать с результатом правого внешнего соединения (см. рис. 3.90). Нужно отметить, что необязательно в качестве имен соединяемых таблиц использовать только явные имена таблиц или только псевдонимы таблиц. Допускается использовать их сочетание. Следующий запрос (использующий по умолчанию «внутреннее» соединение таблиц) вернет правильный результат: SELECT Abonent.Fio, S.StreetCD, S.StreetNM FROM Abonent JOIN Street S ON Abonent.StreetCD = S.StreetCD; Рассмотрим примеры запросов, в которых используются явное соединение таблиц и условие поиска в секции WHERE. Например, если предыдущий запрос с явным «правым» соединением дополнить условием и выполнить запрос SELECT A.Fio, S.StreetCD, S.StreetNM FROM Abonent A RIGHT JOIN Street S ON A.StreetCD = S.StreetCD WHERE A.StreetCD IS NULL;, то будет выведена информация только об улицах с кодами 1, 2 и 5, на которых не проживают абоненты. 10 Для выбора ФИО абонентов, которые производили оплату за услугу с кодом 2 позднее 1 октября 2011 г. (рис. 3.91), запрос с явным «внутренним» соединением может быть построен так: SELECT A.Fio, P.PaySum FROM Abonent A JOIN PaySumma P ON A.AccountCD = P.AccountCD WHERE ServiceCD=2 AND PayDate > '01.10.2011'; FIO Аксенов С.А. Аксенов С.А. Мищенко Е.В. Стародубцев Е.В. Шмаков С.В. Денисова Е.К. Шубина Т. П. Шубина Т. П. Тимошкина Н.Г. PAYSUM 58,70 56,00 250,00 80,00 56,00 58,70 80,00 80,00 30,00 Рис. 3.91. Результат наложения дополнительных условий поиска для соединяемых таблиц В Firebird существует возможность более простого, по сравнению с конструкцией ON, задания условия соединения – соединение по именам столбцов. Если таблицы соединяются по одноименным столбцам, то можно использовать конструкцию USING (<список_столбцов>). В <списке_столбцов> указываются имена всех столбцов, по значениям в которых требуется соединить таблицы. При создании соединения по именам столбцов нужно помнить:  что все столбцы, указанные в списке столбцов, должны существовать в соединяемых таблицах;  по всем указанным столбцам автоматически создается такое соединение, как если бы было указано <таблица1>.столбец = <таблица2>.столбец в секции WHERE при неявном соединении или после ON при явном соединении. Например, рассмотренный ранее запрос, выводящий для всех абонентов названия и коды улиц, можно реализовать с использованием конструкции USING: SELECT A.Fio, S.StreetCD, S.StreetNM FROM Abonent A INNER JOIN Street S USING (StreetCD); Этот же запрос можно реализовать с помощью естественного соединения: SELECT A.Fio, S.StreetCD, S.StreetNM FROM Abonent A NATURAL JOIN Street S; С помощью оператора JOIN можно соединять 3 и более таблицы. Порядок соединений может уточняться круглыми скобками, так как результат нескольких внешних соединений зависит от порядка их выполнения. 11 Например, вывести 10 первых строк c адресом и ФИО абонентов, проживающих на улицах, наименования которых начинаются с букв Г или М, указав для каждого абонента значения начислений, в Firebird можно с помощью запроса: SELECT FIRST 10 S.StreetNM,('д.'||A.HouseNo) AS House, ('кв.'||A.FlatNo) AS Flat, A.Fio, N.NachislSum, (N.NachislMonth || ' месяц ' || N.NachislYear || ' г.') AS Period FROM (Abonent A RIGHT JOIN Street S ON A.StreetCD = S.StreetCD) FULL JOIN NachislSumma N ON A.AccountCD = N.AccountCD WHERE (S.StreetNM LIKE 'М%') OR (S.StreetNM LIKE 'Г%') ORDER BY N.NachislYear ASC, N.NachislMonth ASC; Результат выполнения запроса представлен на рис. 3.92. STREETNM ГАГАРИНА УЛИЦА МОСКОВСКОЕ ШОССЕ МОСКОВСКОЕ ШОССЕ МОСКОВСКАЯ УЛИЦА МОСКОВСКАЯ УЛИЦА МОСКОВСКАЯ УЛИЦА МОСКОВСКОЕ ШОССЕ МОСКОВСКОЕ ШОССЕ МОСКОВСКОЕ ШОССЕ МОСКОВСКОЕ ШОССЕ HO FL FIO USE AT NUL NU NULL L LL д.35 кв.1 Лукашин 1 а Р.М. д.35 кв.1 Лукашин 1 а Р.М. д.35 кв.6 Тимошки на Н.Г. д.35 кв.6 Тимошки на Н.Г. д.35 кв.6 Тимошки на Н.Г. д.35 кв.1 Лукашин 1 а Р.М. д.35 кв.1 Лукашин 1 а Р.М. д.39 кв.3 Шубина 6 Т. П. д.39 кв.3 Шубина 6 Т. П. NACHIS PERIOD LSUM NULL NULL 22,86 12,60 58,10 444,43 60,10 56,00 254,40 32,56 80,00 4 месяц 2010 г. 8 месяц 2010 г. 12 месяц 2010 г. 3 месяц 2011 г. 5 месяц 2011 г. 6 месяц 2011 г. 7 месяц 2011 г. 9 месяц 2011 г. 10 месяц 2011 г. Рис. 3.92. Результат соединения трех таблиц В НД включена и ГАГАРИНА УЛИЦА, на которой не проживают абоненты, так как сначала выполнялось правое внешнее соединение таблиц Abonent и Street, а затем полное внешнее соединение полученной таблицы 12 с таблицей NachislSumma. Итоговый результат отсортирован по возрастанию года начислений, а внутри года – по возрастанию месяца. 3.3.1.3. Реализация стандартных операций реляционной алгебры Селекция (горизонтальное подмножество). Создается из тех строк таблицы, которые удовлетворяют заданным условиям: SELECT * FROM Abonent WHERE Phone IS NOT NULL; Проекция (вертикальное подмножество). Создается из указанных столбцов таблицы с последующим исключением избыточных дубликатов строк: SELECT DISTINCT StreetCD FROM Abonent; Декартово произведение. Для получения декартова произведения таблиц в секции FROM необходимо указать перечень перемножаемых таблиц, а в секции SELECT – все их столбцы. Перемножим таблицы Abonent (12 строк) и Street (8 строк) и получим результирующую таблицу (96 строк): SELECT Abonent.*, Street.* FROM Abonent, Street; Фрагмент результата выполнения запроса представлен на рис. 3.93. Такой же результат может быть получен, если использовать запрос на явное перекрестное соединение: SELECT Abonent.*, Street.* FROM Abonent CROSS JOIN Street; Таким образом, декартово произведение двух таблиц – это набор всевозможных комбинаций строк из двух таблиц. ACCO STR HOU FL FIO UNTC EET SEN AT D CD O NO 005488 3 4 1 Аксенов С.А. 115705 3 1 82 Мищенко Е.В. 015527 3 1 65 Конюхов В.С. … … … … … 005488 3 4 1 Аксенов С.А. 115705 3 1 82 Мищенко Е.В. 015527 3 1 65 Конюхов В.С. … … … … … 080047 8 39 36 Шубина Т. П. PH STRE STREETNM ON ETC E D1 5568 3 ВОЙКОВ 93 ПЕРЕУЛОК 7699 3 ВОЙКОВ 75 ПЕРЕУЛОК 7616 3 ВОЙКОВ 99 ПЕРЕУЛОК … … … 5568 7 КУТУЗОВА 93 УЛИЦА 7699 7 КУТУЗОВА 75 УЛИЦА 7616 7 КУТУЗОВА 99 УЛИЦА … … … 2578 2 НОВАЯ 42 УЛИЦА 13 080270 6 35 6 Тимошкин 3210 2 а Н.Г. 02 НОВАЯ УЛИЦА Рис. 3.93. Декартово произведение таблиц Abonent и Street Экви-соединение. Для получения экви-соединения таблиц необходимо для декартова произведения таблиц установить имеющее смысл соответствие на основе равенства между столбцами соединяемых таблиц. Например, запрос на неявное экви-соединение таблиц Abonent и Street будет выглядеть таким образом: SELECT Abonent.*, Street.* FROM Abonent, Street WHERE Abonent.StreetCD = Street.StreetCD; Фрагмент результата выполнения запроса представлен на рис. 3.94. ACCO STRE HOUS FLA FIO PHO STREE STREETNM UNTC ETCD ENO TNO NE TCD1 D 005488 3 4 1 Аксенов 55689 3 ВОЙКОВ С.А. 3 ПЕРЕУЛОК 115705 3 1 82 Мищенко 76997 3 ВОЙКОВ Е.В. 5 ПЕРЕУЛОК 015527 3 1 65 Конюхов 76169 3 ВОЙКОВ В.С. 9 ПЕРЕУЛОК 443690 7 5 1 Тулупова М 21483 7 КУТУЗОВА .И. 3 УЛИЦА 136159 7 39 1 Свирина NULL 7 КУТУЗОВА З.А. УЛИЦА … … … … … … … … Рис. 3.94. Экви-соединение таблиц Abonent и Street Такой же результат может быть получен, если использовать запрос на явное соединение: SELECT Abonent.*, Street.* FROM Abonent JOIN Street ON Abonent.StreetCD = Street.StreetCD; Естественное соединение. Для получения естественного соединения таблиц необходимо в экви-соединении таблиц исключить дубликаты повторяющихся столбцов (входящих в условие соединения). Для предыдущего примера естественное соединение таблиц Abonent и Street по столбцу StreetCD выглядит так: SELECT AccountCD, Street.StreetCD, StreetNM, HouseNo, FlatNo, Fio, Phone FROM Abonent, Street WHERE Abonent.StreetCD = Street.StreetCD; Фрагмент результата выполнения запроса представлен на рис. 3.95. 14 ACCO UNTC D 005488 115705 015527 443690 136159 … STR STREETN HOU FLA FIO EET M SEN TN CD O O 3 ВОЙКОВ 4 1 Аксенов ПЕРЕУЛО С.А. К 3 ВОЙКОВ 1 82 Мищенко ПЕРЕУЛО Е.В. К 3 ВОЙКОВ 1 65 Конюхов ПЕРЕУЛО В.С. К 7 КУТУЗОВ 5 1 Тулупова А УЛИЦА М.И. 7 КУТУЗОВ 39 1 Свирина А УЛИЦА З.А. … … … … … PHONE 556893 769975 761699 214833 NULL … Рис. 3.95. Естественное соединение таблиц Abonent и Street Аналогичный результат может быть получен, если использовать следующий запрос на явное естественное соединение, например в Firebird: SELECT AccountCD, StreetCD, StreetNM, HouseNo, FlatNo, Fio, Phone FROM Abonent NATURAL JOIN Street; Композиция. Для создания композиции таблиц нужно исключить из вывода все столбцы, по которым проводилось соединение таблиц: SELECT AccountCD, StreetNM, HouseNo, FlatNo, Fio, Phone FROM Abonent, Street WHERE Abonent.StreetCD = Street.StreetCD; Фрагмент результата выполнения запроса представлен на рис. 3.96. ACCO STREETNM HOUS FLA UNTCD ENO TNO 005488 ВОЙКОВ 4 1 ПЕРЕУЛОК 115705 ВОЙКОВ 1 82 ПЕРЕУЛОК 015527 ВОЙКОВ 1 65 ПЕРЕУЛОК 443690 КУТУЗОВА 5 1 УЛИЦА 136159 КУТУЗОВА 39 1 УЛИЦА 080270 МОСКОВСКА 35 6 Я УЛИЦА … … … … FIO Аксенов С.А. Мищенко Е.В. Конюхов В.С. Тулупова М.И. Свирина З.А. Тимошкин а Н.Г. … PHONE 556893 769975 761699 214833 NULL 321002 … Рис. 3.96. Композиция таблиц Abonent и Street 15 Тета-соединение. Тета-соединение предназначено для тех случаев, когда необходимо соединить две таблицы на основе некоторых условий, отличных от равенства. Получить тета-соединение таблиц Abonent и Street можно таким образом: SELECT Abonent.*, Street.* FROM Abonent, Street WHERE Abonent.StreetCD < Street.StreetCD; Фрагмент результата выполнения запроса представлен на рис. 3.97. ACC OUN TCD 00548 8 11570 5 01552 7 44306 9 13616 12611 2 13616 9 08027 … 01552 7 44306 9 13616 12611 2 13616 9 STR HOU FL FIO EET SEN AT CD O NO 3 4 1 Аксенов С.А. 3 1 82 Мищенко Е.В. 3 1 65 Конюхов В.С. 4 51 55 Стародубц ев Е.В. 4 9 15 Шмаков С.В. 4 7 11 Маркова В.П. 4 7 13 Денисова Е.К. 6 35 6 Тимошкин а Н.Г. … … … … 3 1 65 Конюхов В.С. 4 51 55 Стародубц ев Е.В. 4 9 15 Шмаков С.В. 4 7 11 Маркова В.П. 4 7 13 Денисова Е.К. PH ON E 556 893 769 975 761 699 683 014 NU LL 683 301 680 305 321 002 … 761 699 683 014 NU LL 683 301 680 305 STRE STREETNM ETC D1 7 КУТУЗОВА УЛИЦА 7 КУТУЗОВА УЛИЦА 7 КУТУЗОВА УЛИЦА 7 КУТУЗОВА УЛИЦА 7 КУТУЗОВА УЛИЦА 7 КУТУЗОВА УЛИЦА 7 КУТУЗОВА УЛИЦА 7 КУТУЗОВА УЛИЦА … … 5 ГАГАРИНА УЛИЦА 5 ГАГАРИНА УЛИЦА 5 ГАГАРИНА УЛИЦА 5 ГАГАРИНА УЛИЦА 5 ГАГАРИНА УЛИЦА Рис. 3.97. Тета-соединение таблиц Abonent и Street Разность таблиц. Это соединение позволяет в одной из двух таблиц, имеющих общие ключи, найти строки, которых нет в другой таблице. Например, для выяснения улиц, представленных в таблице Street, отсутствующих в таблице Abonent, можно использовать запрос SELECT S.* 16 FROM Street S LEFT JOIN Abonent A ON S.StreetCD= A.StreetCD WHERE A.StreetCD IS NULL ORDER BY 1; Пересечение таблиц. Позволяет из двух таблиц, имеющих общие ключи, найти значения, которые имеются в обеих таблицах. Например, для выяснения улиц, представленных в таблице Street, имеющихся в таблице Abonent, можно использовать такой запрос: SELECT DISTINCT S.* FROM Street S LEFT JOIN Abonent A ON S.StreetCD= A.StreetCD WHERE A.StreetCD IS NOT NULL ORDER BY 1; Этот запрос решает ту же задачу, что и аналогичные запросы, приведенные в пп. 3.3.1.1, 3.3.1.2 соответственно с неявным и явным внутренним соединением. Деление таблиц. Позволяет в одной из двух таблиц, имеющих общие ключи, найти значения, для которых имеются все соответствия в другой таблице. Пример рассматривается в разд. 3.3.2.6. 3.3.1.4. Соединение таблицы со своей копией В некоторых, довольно часто встречающихся на практике случаях необходимо выбрать данные из таблицы, основываясь на результатах дополнительных выборок из этой же таблицы. Такие выборки называются коррелированными. Для коррелированных выборок многотабличные запросы используют отношения, существующие внутри одной из таблиц (самосоединение) [52]. Чтобы обратиться к одной и той же таблице внутри одного запроса, используются псевдонимы таблиц, определяемые непосредственно после имени таблицы в секции FROM запроса SELECT. Например, чтобы найти все пары абонентов, проживающих на одной и той же улице, можно использовать следующее неявное рефлексивное самосоединение таблицы Abonent: SELECT F.Fio, S.Fio FROM Abonent F, Abonent S WHERE F.StreetCD = S.StreetCD AND F.Fio < S.Fio; В приведенном примере для таблицы Abonent определены 2 псевдонима: F (First) и S (Second). Эти псевдонимы будут существовать, пока выполняется запрос. Запрос ведет себя так, как будто в операции соединения участвуют две таблицы, называемые F и S. Обе они в действительности являются таблицей Abonent, но алиасы позволяют рассматривать ее как две независимые таблицы. Получив две копии таблицы Abonent для работы, SQL выполняет операцию соединения, как для двух разных таблиц: выбирает очередную строку из одного алиаса и соединяет ее с каждой строкой другого алиаса. Дополнительное условие поиска F.Fio < S.Fio предназначено для удаления из НД повторяющихся строк, появляющихся в результате того, что запрос выбирает все комбинации строк с одинаковым кодом улицы (рис. 17 3.98). Такой же результат может быть получен, если использовать следующий запрос на явное внутреннее рефлексивное самосоединение: SELECT F.Fio, S.Fio FROM Abonent F JOIN Abonent S ON F.StreetCD = S.StreetCD WHERE F.Fio < S.Fio; FIO Аксенов С.А. Аксенов С.А. Конюхов В.С. Свирина З.А. Стародубцев Е.В. Маркова В.П. Маркова В.П. Денисова Е.К. Денисова Е.К. Денисова Е.К. Лукашина Р.М. FIO1 Мищенко Е.В. Конюхов В.С. Мищенко Е.В. Тулупова М.И. Шмаков С.В. Стародубцев Е.В. Шмаков С.В. Стародубцев Е.В. Шмаков С.В. Маркова В.П. Шубина Т. П. Рис. 3.98. Результат соединения таблицы со своей копией Примером неявного соединения таблицы со своей копией и другой таблицей может быть запрос, выводящий все пары абонентов, имеющих ремонтные заявки с одной и той же неисправностью газового оборудования: SELECT FailureNM, A.AccountCD, B.AccountCD FROM Request A, Request B, Disrepair D WHERE A.FailureCD = B.FailureCD AND D.FailureCD = A.FailureCD AND A.AccountCD < B.AccountCD; Предположим, что в таблицу Abonent добавлен внешний рекурсивный ключ Head_Account (это можно сделать с помощью запроса ALTER TABLE, использование которого будет рассмотрено позднее). В этом столбце для каждого абонента указан номер лицевого счета управляющего по дому, в котором проживает абонент. Если абонент сам является управляющим, то в столбце Head_Account указывается NULL. Допустим, в таблице Abonent имеются данные, представленные на рис. 3.99. ACCOUNT HEAD_ STRE HOU FLA FIO CD ACCOU ETCD SEN TNO NT O 005488 NULL 3 4 1 Аксенов С.А. 015527 115705 3 1 65 Конюхов В.С. 080047 NULL 8 39 36 Шубина Т. П. PHONE 556893 761699 257842 18 080270 NULL 6 35 6 080613 NULL 8 35 11 115705 NULL 3 1 82 126112 136169 4 7 11 136159 NULL 7 39 1 136160 NULL 4 9 15 136169 NULL 4 7 13 443069 NULL 4 51 55 443690 NULL 7 5 1 Тимошкин а Н.Г. Лукашина Р.М. Мищенко Е.В. Маркова В.П. Свирина З.А. Шмаков С.В. Денисова Е.К. Стародубц ев Е.В. Тулупова М.И. 321002 254417 769975 683301 NULL NULL 680305 683014 214833 Рис. 3.99. Данные таблицы Abonent с рекурсивным внешним ключом Head_Account С помощью внутреннего рекурсивного самосоединения можно создать запрос, в результате выполнения которого выводится список абонентов с указанием ФИО управляющих их домов: SELECT A.Fio "Абонент", B.Fio "Управляющий" FROM Abonent A INNER JOIN Abonent B ON A.Head_Account = B.AccountCD; Этот запрос включает таблицу Abonent и ее копию: из таблицы Abonent (под псевдонимом A) извлекаются ФИО абонентов, а из ее копии (под псевдонимом B) – ФИО управляющих домов. Хотя в таблице Abonent 12 абонентов, но запрос возвращает только 2. Остальные абоненты являются управляющими домов. Чтобы включить всех абонентов в результирующий набор, необходимо использовать внешнее рекурсивное самосоединение: SELECT A.Fio "Абонент", B.Fio "Управляющий" FROM Abonent A LEFT OUTER JOIN Abonent B ON A.Head_Account=B.AccountCD; Для формирования списка всех абонентов и управляющих их домов, если таковые имеются, запрос использует левостороннее внешнее соединение. 19
«Многотабличные и вложенные запросы» 👇
Готовые курсовые работы и рефераты
Купить от 250 ₽
Решение задач от ИИ за 2 минуты
Решить задачу
Помощь с рефератом от нейросети
Написать ИИ
Получи помощь с рефератом от ИИ-шки
ИИ ответит за 2 минуты

Тебе могут подойти лекции

Смотреть все 588 лекций
Все самое важное и интересное в Telegram

Все сервисы Справочника в твоем телефоне! Просто напиши Боту, что ты ищешь и он быстро найдет нужную статью, лекцию или пособие для тебя!

Перейти в Telegram Bot