В данной статье я расскажу и приведу пример, каким образом, используя вложенные запросы, можно решить данную проблему.
Для написания статьи я создал простенькую конфигурацию и слегка заполнил данными.
Итак, имеем:
- документ "Договор" с реквизитами "Сумма" и "Сотрудник";
- справочник "Сотрудники" с ФИО сотрудника;
- регистр накопления периодический в пределах секунды "Руководители" с измерением "Сотрудник" типа Справочник.Сотрудники и ресурсом "Руководитель" типа Справочник.Сотрудники.
Наполнение:
- Сотрудник Иванов И.И.
- Сотрудник Петров П.П.
- Сотрудник Сидоров С.С.
- Запись регистра накопления: Сотрудник Иванов И.И., Руководитель Петров П.П., период 15.06.2009 00:00:00
- Запись регистра накопления: Сотрудник Иванов И.И., Руководитель Сидоров С.С., период 15.05.2009 00:00:00
- Договор № 1 от 05.06.2009 12:00:00, сумма 200, сотрудник Иванов И.И.
- Договор № 2 от 20.06.2009 12:00:00, сумма 300, сотрудник Иванов И.И.
Необходимо сделать отчет за период с 01.06.2009 00:00:00 по 01.07.2009 00:00:00 в котором отразить на какую сумму договора каждый из руководителей заключил с помощью своих сотрудников. И сделать отчет нужно обязательно в компановщике, а значит данные должны быть выданы 1 запросом.
В голову сразу приходит следующий запрос:
ВЫБРАТЬ
Договор.Ссылка КАК Договор,
СУММА(Договор.Сумма) КАК Сумма,
РуководителиСрезПоследних.Руководитель
ИЗ
Документ.Договор КАК Договор
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Руководители.СрезПоследних(&Дата2, ) КАК РуководителиСрезПоследних
ПО Договор.Сотрудник = РуководителиСрезПоследних.Сотрудник
ГДЕ
Договор.Дата МЕЖДУ &Дата1 И &Дата2
СГРУППИРОВАТЬ ПО
РуководителиСрезПоследних.Руководитель,
Договор.Ссылка
Скажу честно, аналогичный запрос сразу же был представлен и мной. Но что же получается в итоге:
Руководитель | Договор 000000001 от 05.06.2009 12:00:00 | Договор 000000002 от 20.06.2009 12:00:00 | Итого |
Сумма | Сумма | Сумма | |
Петров П.П. | 200,00 | 300,00 | 500,00 |
Итого | 200,00 | 300,00 |
500,00 |
А по документам первый договор был заключен под руководством Сидорова и премию по этому договору он не получит. А значит наш отчет выдал совсем не то, что есть на самом деле.
Что делать? Все очень просто. Забыть про СрезПоследних(). Именно этот механизм, во многих случаях облегчающий написание запросов, сейчас играет не в нашу пользу. А вот вложенные запросы, которыми не всегда любят пользоваться программисты, могут сделать достаточно много. В моей практике были запросы до 10 вложенностей. Как результат - очень быстрое построение отчета одним большим (огромным) запросом. Всегда есть минус - такие запросы очень сложно переделывать. Но вернемся к теме. Для начала нам необходимо получить всех руководителей, период записи которых меньше или равен дате договора. Потом все поля, кроме периода сделать группировочными, а период взять максимальный. После этого зная сотрудника и период записи можно сделать соединение и получить руководителя на дату договора.
На практике наш новый запрос выглядит вот так:
ВЫБРАТЬ
ВложенныйЗапрос.Ссылка КАК Договор,
ВложенныйЗапрос.Сумма,
Руководители.Руководитель
ИЗ
(ВЫБРАТЬ
Договор.Сумма КАК Сумма,
Договор.Ссылка КАК Ссылка,
МАКСИМУМ(Руководители.Период) КАК Период,
Договор.Сотрудник КАК Сотрудник
ИЗ
Документ.Договор КАК Договор
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Руководители КАК Руководители
ПО Договор.Сотрудник = Руководители.Сотрудник
И Договор.Дата >= Руководители.Период
ГДЕ
Договор.Дата МЕЖДУ &Дата1 И &Дата2
СГРУППИРОВАТЬ ПО
Договор.Сумма,
Договор.Ссылка,
Договор.Сотрудник) КАК ВложенныйЗапрос
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Руководители КАК Руководители
ПО ВложенныйЗапрос.Период = Руководители.Период
И ВложенныйЗапрос.Сотрудник = Руководители.Сотрудник
ZyZer (спасибо ему) подсказал вариант запроса с временной таблицей:
ВЫБРАТЬ
Договор.Сумма КАК Сумма,
Договор.Ссылка КАК Ссылка,
МАКСИМУМ(Руководители.Период) КАК Период,
Договор.Сотрудник КАК Сотрудник
ПОМЕСТИТЬ РуководителиДоговоров
ИЗ
Документ.Договор КАК Договор
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Руководители КАК Руководители
ПО Договор.Сотрудник = Руководители.Сотрудник
И Договор.Дата >= Руководители.Период
ГДЕ
Договор.Дата МЕЖДУ &Дата1 И &Дата2
СГРУППИРОВАТЬ ПО
Договор.Сумма,
Договор.Ссылка,
Договор.Сотрудник
;
ВЫБРАТЬ
РуководителиДоговоров.Ссылка КАК Договор,
РуководителиДоговоров.Сумма,
Руководители.Руководитель
ИЗ
РуководителиДоговоров КАК РуководителиДоговоров
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Руководители КАК Руководители
ПО РуководителиДоговоров.Период = Руководители.Период
И РуководителиДоговоров.Сотрудник = Руководители.Сотрудник
Смотрим результат:
Руководитель | Договор 000000001 от 05.06.2009 12:00:00 | Договор 000000002 от 20.06.2009 12:00:00 | Итого |
Сумма | Сумма | Сумма | |
Петров П.П. |
300,00 | 300,00 | |
Сидоров С.С. | 200,00 | 200,00 | |
Итого | 200,00 | 300,00 | 500,00 |
Вот теперь у нас все правильно.
Ну а если Вам необходимо вместо а-ля СрезПоследних сделать СрезПервых, просто в запросе меняем больше на меньше и максимум на минимум. Все просто.
Изучите данную базу и Вы поймете: не все полезно, что облегчает нашу жизнь.
Спасибо за внимание. И не забываем ставить плюсы.