Рассмотрим задачу соединения двух таблиц, когда первую таблицу нужно соединить с таблицей, которая является дополнением для второй таблицы (то есть содержит элементы некоторого множества, отсутствующие во второй таблице). В качестве примера используем задачу со студентами и оценками по семестрам. Итак, имеется Таблица значений ТЗ1 с колонками: НомерСтроки, Студент, ДатаСреза (разная для каждого студента), СеместрКонтроляОценки, Оценка. Требуется вернуть ТЗ2, содержащую строки НомерСтроки, Студент, для которых была найдена хоть одна оценка, отсутствующая в ТЗ1 для соответствующего семестра. В ТЗ1 могут содержаться пустые оценки. |
||
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ | Внешний.НомерСтроки КАК НомерСтроки, | Внешний.Студент КАК Студент, | Внешний.ДатаСреза, | Внешний.СеместрКонтроляОценки КАК СеместрКонтроляОценки, | Внешний.Оценка |ПОМЕСТИТЬ ТЗ1 |ИЗ | &ВнешнийИсточник КАК Внешний | |ИНДЕКСИРОВАТЬ ПО | НомерСтроки, | СеместрКонтроляОценки |; | |///////////////////////////////////// |ВЫБРАТЬ | ТЗ1.НомерСтроки КАК НомерСтроки, | ТЗ1.СеместрКонтроляОценки КАК СеместрКонтроляОценки, | Оценки.Ссылка КАК Оценка, | МАКСИМУМ(ТЗ1.Студент) КАК Студент, | МАКСИМУМ(ТЗ1.ДатаСреза) КАК ДатаСреза |ПОМЕСТИТЬ СтудентыПоСеместрамСоВсемиОценками |ИЗ | ТЗ1 КАК ТЗ1 | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Оценки КАК Оценки | ПО (ИСТИНА) | |СГРУППИРОВАТЬ ПО | ТЗ1.НомерСтроки, | ТЗ1.СеместрКонтроляОценки, | Оценки.Ссылка | |ОБЪЕДИНИТЬ ВСЕ | |ВЫБРАТЬ | ТЗ1.НомерСтроки, | ТЗ1.СеместрКонтроляОценки, | ЗНАЧЕНИЕ(Справочник.Оценки.ПустаяСсылка), | ТЗ1.Студент, | ТЗ1.ДатаСреза |ИЗ | ТЗ1 КАК ТЗ1 | |ИНДЕКСИРОВАТЬ ПО | Оценка, | СеместрКонтроляОценки, | НомерСтроки |; | |////////////////////////////////////// |ВЫБРАТЬ РАЗЛИЧНЫЕ | СтудентыПоСеместрамСоВсемиОценками.НомерСтроки КАК НомерСтроки, | СтудентыПоСеместрамСоВсемиОценками.Студент, | СтудентыПоСеместрамСоВсемиОценками.ДатаСреза, | СтудентыПоСеместрамСоВсемиОценками.СеместрКонтроляОценки, | СтудентыПоСеместрамСоВсемиОценками.Оценка |ИЗ | СтудентыПоСеместрамСоВсемиОценками КАК СтудентыПоСеместрамСоВсемиОценками | ЛЕВОЕ СОЕДИНЕНИЕ ТЗ1 КАК ТЗ1 | ПО СтудентыПоСеместрамСоВсемиОценками.НомерСтроки = ТЗ1.НомерСтроки | И СтудентыПоСеместрамСоВсемиОценками.СеместрКонтроляОценки = ТЗ1.СеместрКонтроляОценки | И СтудентыПоСеместрамСоВсемиОценками.Оценка = ТЗ1.Оценка |ГДЕ | ТЗ1.НомерСтроки ЕСТЬ NULL | |УПОРЯДОЧИТЬ ПО | НомерСтроки";
Запрос.УстановитьПараметр("ВнешнийИсточник", ТЗ1); ТЗ1_1 = Запрос.Выполнить().Выгрузить();
|
||
Полностью решать задачу нахождения ТЗ2 не будем, а с помощью приведенного запроса сведем ее к задаче «Требуется вернуть ТЗ2, содержащую строки НомерСтроки, Студент, для которых была найдена хоть одна оценка, имеющаяся в ТЗ1 для соответствующего семестра». То есть подменим таблицу ТЗ1. Основная идея получения соединения с дополнением множества заключается в том, чтобы сначала сделать соединение со всем множеством, а потом полученную таблицу соединить с исходной таблицей левым соединением и проверить любое поле из правой части результата на NULL. Отметим, что общепринятый тип условия «кроме» в данном случае не может быть использован, так как предназначен для получения данных из выборки. В нашем случае множество различных значений представлено отдельным справочником (оценки). | ||
Примеры |
||
Каковы могут быть примеры подобного типа из области учетных задач? Допустим, нужно построить таблицу с полями Покупатель и Номенклатура, содержащую строки с покупателями и позициями номенклатуры, которые не продавались за отчетный период (а, возможно, и не были в числе покупателей). В данном случае множества значений, для которых строятся дополнения, - это справочники Номенклатура и Контрагенты. | ||
Во втором запросе приведенного выше пакета запросов используется функция МАКСИМУМ. Смысл ее применения состоит в том, чтобы найти наиболее позднюю дату появления оценки. В последующем может понадобиться получить некоторую информацию на последнюю дату, различную для каждого студента. То есть виртуальная таблица СрезПоследнего не может быть использована, так как у каждого студента своя последняя дата. | ||
Рассмотрим еще один пример, как в условия связи для операции соединения можно включать произвольные условия (альтернатива условию ГДЕ), что повышает скорость выполнения запроса. В этом же примере показано условие связи «через таблицу» (выделенная строка в примере). Эта возможность, наоборот, может снизить скорость выполнения запроса, но позволяет упростить сам запрос, поэтому условиями связи «через таблицу» нужно пользоваться осторожно. | ||
|ВЫБРАТЬ | Обучение.Студент КАК Обучающийся, | МАКСИМУМ(Обучение.Период) КАК Период, | МАКСИМУМ(УчебныйПланСтудента.Период) КАК Период1 |ПОМЕСТИТЬ ДанныеПоСрезу |ИЗ | РегистрСведений.Обучение КАК Обучение | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТСтуденты КАК СтудентыДаты |ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.УчебныйПланСтудента КАК УчебныйПланСтудента | ПО СтудентыДаты.Студент = УчебныйПланСтудента.Студент | И СтудентыДаты.ДатаСреза >= УчебныйПланСтудента.Период | ПО (СтудентыДаты.Студент = Обучение.Студент) | И (УчебныйПланСтудента.Период >= Обучение.Период)
|
||
Приведём взятый из литературы классический пример соединения трёх таблиц с условием связи «через таблицу». | ||
Предположим, что мы хотим найти все заказы заказчиков, не находящихся в одном городе с агентом. Для этого требуется связать три таблицы: | ||
SELECT Orders.onum, Customers.cname, Orders.cnum, Orders.snum
FROM Salespeople, Customers, Orders WHERE Customers.city <> Salespeople.city AND Orders.cnum = Customers.cnum AND Orders.snum = Salespeople.snum
|
||
Если есть вопросы по материалу - обращайтесь! | ||
Семенов Сергей |