Например, чтобы с "т.з. учета в ЗУП" получить правильные данные о плановых начислениях, надо сделать выборку не только из РС.ПлановыеНачисления, но также из РС.ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудников и РС.ПлановыйФОТ. А чтобы получить кадровые данные сотрудников, механизмом извлекаются данные из более чем дюжины регистров.
ВЫБРАТЬ
ФизическоеЛицо,
ОтношениеКВоинскойОбязанности
ИЗ
РегистрСведений.ВоинскийУчет.СрезПоследних(&Дата, ФизическоеЛицо В (&ФизическиеЛица))
платформа заменяет на запрос вида
ВЫБРАТЬ
T1.ФизическоеЛицо КАК ФизическоеЛицо,
T1.ОтношениеКВоинскойОбязанности КАК ОтношениеКВоинскойОбязанности
ИЗ
(ВЫБРАТЬ
T4.ФизическоеЛицо КАК ФизическоеЛицо,
T4.ОтношениеКВоинскойОбязанности КАК ОтношениеКВоинскойОбязанности
ИЗ
(ВЫБРАТЬ
T3.ФизическоеЛицо КАК ФизическоеЛицо,
МАКСИМУМ(T3.Период) КАК МаксПериод
ИЗ
РегистрСведений.ВоинскийУчет КАК T3
ГДЕ
T3.Период <= &Дата
И T3.ФизическоеЛицо В(&ФизическиеЛица)
СГРУППИРОВАТЬ ПО
T3.ФизическоеЛицо) КАК T2
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ВоинскийУчет КАК T4
ПО T2.ФизическоеЛицо = T4.ФизическоеЛицо
И T2.МаксПериод = T4.Период) КАК T1
Этот запрос точно не будет эффективным при наличии в регистре 1 млн записей. Быстрее выполнится запрос с выделением максимальных периодов во временную таблицу
ВЫБРАТЬ
T3.ФизическоеЛицо КАК ФизическоеЛицо,
МАКСИМУМ(T3.Период) КАК МаксПериод
ПОМЕСТИТЬ ВТМаксПериоды
ИЗ
РегистрСведений.ВоинскийУчет КАК T3
ГДЕ
T3.Период <= &Дата
И T3.ФизическоеЛицо В(&ФизическиеЛица)
СГРУППИРОВАТЬ ПО
T3.ФизическоеЛицо
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
T4.ФизическоеЛицо КАК ФизическоеЛицо,
T4.ОтношениеКВоинскойОбязанности КАК ОтношениеКВоинскойОбязанности
ИЗ
ВТМаксПериоды КАК T2
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ВоинскийУчет КАК T4
ПО T2.ФизическоеЛицо = T4.ФизическоеЛицо
И T2.МаксПериод = T4.Период
И механизм сформирует примерно такой же запрос. Еще раз обращаю внимание: платформа генерирует заведомо неэффективный запрос, программисты 1С используют обходной манёвр (хех, на тему обходных маневров можете поискать как собираются базы начислений и удержаний). Для получения запроса понадобится временная таблица-фильтр по физическим лицам. Она должна обязательно содержать два поля: ФизическоеЛицо и Период. Причем поле Период может быть заполнено разными значениями. Для примера сделаем фильтр из таблицы значений
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| ФизическиеЛица.ФизическоеЛицо КАК ФизическоеЛицо,
| ФизическиеЛица.Период КАК Период
|ПОМЕСТИТЬ ВТФизическиеЛица
|ИЗ
| &ФизическиеЛица КАК ФизическиеЛица";
Запрос.УстановитьПараметр("ФизическиеЛица", ФизическиеЛицаТаблица);
ОписаниеФильтра = ЗарплатаКадрыПериодическиеРегистры.ОписаниеФильтраДляСоздатьВТИмяРегистра("ВТФизическиеЛица", "ФизическоеЛицо");
ТолькоРазрешенные = Истина;
СрезПоследних = Истина;
ЗапросСреза = ЗарплатаКадрыПериодическиеРегистры.ЗапросВТИмяРегистраСрез("ВоинскийУчет", ТолькоРазрешенные, ОписаниеФильтра, , СрезПоследних, "ВТВоинскийУчет");
ЗарплатаКадрыОбщиеНаборыДанных.ОбъединитьЗапросы(Запрос, ЗапросСреза);
Запрос.Выполнить();
В менеджере временных таблиц мы получим искомый срез в ВТВоинскийУчет. Если поковыряться в параметрах процедур, то вы обнаружите, что, например, поля ФизическоеЛицо и Период можно переобозначить (описывая эти и другие подробности, я никогда не закончу писать статью).
Но опять о преимуществах механизма. 1С придумали т.н. "интервальные" регистры сведений. Это своего рода программно реализуемая "виртуальная таблица", в которую помещаются периоды действия регистрируемых событий. Получение среза последних при наличии такого регистра сводится к одному соединению фильтра с таблицей регистра, то есть выполняется заведомо быстрее. Для РС.ГрафикРаботыСотрудников, у которого уже есть интервальный регистр, результат вызова ЗапросВТИмяРегистраСрез вернет следующий запрос
ВЫБРАТЬ
Сотрудники.Сотрудник КАК Сотрудник,
Сотрудники.Период КАК Период
ПОМЕСТИТЬ ВТСотрудники
ИЗ
&Сотрудники КАК Сотрудники
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ИзмеренияДаты.Период КАК Период,
РегистрСведений.ДействуетДо КАК ПериодВозвратногоСобытия,
ВЫБОР
КОГДА РегистрСведений.ПериодЗаписи = РегистрСведений.ДатаНачала
ТОГДА ЛОЖЬ
ИНАЧЕ ИСТИНА
КОНЕЦ КАК ЭтоВозвратноеСобытие,
РегистрСведений.РегистраторСобытия КАК Регистратор,
ИзмеренияДаты.Сотрудник КАК Сотрудник,
РегистрСведений.ДатаОкончания КАК ДатаОкончания,
РегистрСведений.ДатаНачала КАК ДатаНачала,
РегистрСведений.ГоловнаяОрганизация КАК ГоловнаяОрганизация,
РегистрСведений.ПериодЗаписи КАК ПериодЗаписи,
РегистрСведений.Год КАК Год,
РегистрСведений.ПериодПредыдущейЗаписи КАК ПериодПредыдущейЗаписи,
РегистрСведений.ГрафикРаботы КАК ГрафикРаботы,
РегистрСведений.РегистраторЗаписи КАК РегистраторЗаписи,
РегистрСведений.РегистраторСобытия КАК РегистраторСобытия,
РегистрСведений.ПустойИнтервал КАК ПустойИнтервал
ПОМЕСТИТЬ ВТГрафикРаботыСотрудников
{ВЫБРАТЬ
Период,
ПериодВозвратногоСобытия,
Регистратор,
Сотрудник,
ДатаОкончания,
ДатаНачала,
ГоловнаяОрганизация,
ПериодЗаписи,
Год,
ПериодПредыдущейЗаписи,
ГрафикРаботы,
РегистраторЗаписи,
РегистраторСобытия,
ПустойИнтервал}
ИЗ
ВТСотрудники КАК ИзмеренияДаты
{ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ГрафикРаботыСотрудниковИнтервальный КАК РегистрСведений
ПО (РегистрСведений.ДатаНачала <= КОНЕЦПЕРИОДА(ВЫБОР
КОГДА ИзмеренияДаты.Период = ДАТАВРЕМЯ(1, 1, 1)
ТОГДА ДАТАВРЕМЯ(3999, 12, 31, 23, 59, 59)
ИНАЧЕ ИзмеренияДаты.Период
КОНЕЦ, ДЕНЬ))
И (РегистрСведений.ДатаОкончания >= КОНЕЦПЕРИОДА(ВЫБОР
КОГДА ИзмеренияДаты.Период = ДАТАВРЕМЯ(1, 1, 1)
ТОГДА ДАТАВРЕМЯ(3999, 12, 31, 23, 59, 59)
ИНАЧЕ ИзмеренияДаты.Период
КОНЕЦ, ДЕНЬ))
И (РегистрСведений.Сотрудник = ИзмеренияДаты.Сотрудник)}
ГДЕ
ИСТИНА
{ГДЕ
РегистрСведений.Сотрудник.*}
То есть вызывая процедуру получения запроса для среза последних и т.п. мы получим функционально правильный и эффективный (будем надеяться) запрос.
Можно вместо запроса получить сразу ВТ. Соответственно, в параметре-менеджере временных таблиц уже должна быть готова ВТСотрудники
ЗарплатаКадрыОбщиеНаборыДанных.СоздатьВТИмяРегистраСрезПоследних(
"ГрафикРаботыСотрудников",
Запрос.МенеджерВременныхТаблиц,
Истина,
ЗарплатаКадрыОбщиеНаборыДанных.ОписаниеФильтраДляСоздатьВТИмяРегистра("ВТСотрудники", "Сотрудник"),
,
"ВТГрафикРаботыСотрудниковСрезПоследних");
Приведу еще один полезный пример для регистра, у которого два измерения, причем одно из них все еще называется ФизЛицо вместо принятого ныне ФизическоеЛицо, а в ВТ-фильтре поле называется как раз ФизическоеЛицо. Также в этом примере описывается дополнительный отбор, накладываемый на второе измерение
ПараметрыПостроения = ЗарплатаКадрыОбщиеНаборыДанных.ПараметрыПостроенияДляСоздатьВТИмяРегистраСрез();
ЗарплатаКадрыОбщиеНаборыДанных.ДобавитьВКоллекциюОтбор(ПараметрыПостроения.Отборы, "ВидДокумента", "=", ОбщегоНазначенияКлиентСервер.ПредопределенныйЭлемент("Справочник.ВидыДокументовФизическихЛиц.ПаспортРФ"));
ОписаниеФильтра = ЗарплатаКадрыПериодическиеРегистры.ОписаниеФильтраДляСоздатьВТИмяРегистра("ВТФизическиеЛица", "ФизЛицо");
ОписаниеФильтра.СоответствиеИзмеренийРегистраИзмерениямФильтра.Вставить("ФизЛицо", "ФизическоеЛицо");
ЗапросСреза = ЗарплатаКадрыПериодическиеРегистры.ЗапросВТИмяРегистраСрез("ДокументыФизическихЛиц", Истина, ОписаниеФильтра, ПараметрыПостроения, Истина, "ВТДокументыФизическихЛиц");
Также можно получить записи регистра. Это делается при помощи функций в общем модуле ЗарплатаКадрыПериодическиеРегистры: ЗапросВТИмяРегистра, СоздатьВТИмяРегистра.
Помимо срезов регистров сведений существует целый перечень готовых запросов/временных таблиц. С этим перечнем можно ознакомиться в функциях:
- ЗарплатаКадрыОбщиеНаборыДанныхРасширенный.ПолучитьЗапросПоПредставлению,
- ЗарплатаКадрыОбщиеНаборыДанныхБазовый.ПолучитьЗапросПоПредставлению.
Каждое из представлений, описанных в этих функциях, пожалуй, заслуживает отдельной темы. В этих функциях можно почерпнуть сведения о том, как получить соответствующие запросы и ВТ. Также можно глобальным поиском найти места, где это делают сами разработчики 1С.
Приведу ещё примеры использования некоторых из них. Например, данные учета времени и состояний сотрудников - таким образом вы получите ВТ с видом рабочего времени сотрудников на каждый день периода. Здесь при в сборе данных помимо регистров сведений участвуют и регистры накопления. Опять же, идейный смысл такого получения данных в том, что будут учтены отклонения, табели, индивидуальные графики и т.п.
ПараметрыЗаполнения = УчетРабочегоВремениРасширенный.ПараметрыДляЗапросВТДанныеУчетаВремениИСостоянийСотрудников();
ПараметрыЗаполнения.ИмяВТСотрудники = "ВТСотрудники";
ПараметрыЗаполнения.ИмяВТРезультат = "ВТУчетРабочегоВремени";
ПараметрыЗаполнения.РассчитыватьПлановоеВремя = Ложь;
ПараметрыЗаполнения.ДатаАктуальности = НачалоМесяца(ДатаОкончания);
ПараметрыЗаполнения.ДатаНачала = ДатаНачала;
ПараметрыЗаполнения.ДатаОкончания = ДатаОкончания;
ПараметрыЗаполнения.МесяцДатаНачала = НачалоМесяца(ДатаНачала);
ПараметрыЗаполнения.МесяцДатаОкончания = НачалоМесяца(ДатаОкончания);
ПараметрыЗаполнения.ВыделятьВыходныеВПериодыОтклонений = Ложь;
ПараметрыЗаполнения.ПолучатьУсловияТрудаИТерритории = Истина;
УчетРабочегоВремениРасширенный.СоздатьВТДанныеУчетаВремениИСостоянийСотрудников(Запрос.МенеджерВременныхТаблиц, Истина, ПараметрыЗаполнения);
Пример "двухступенчатой" выборки данных: сначала получаем кадровые данные, затем на их основании данные штатного расписания (ВТСотрудники должны быть подготовлены в МенеджерВременныхТаблиц). При этом, например, вам не надо думать, используется ли история изменения штатного расписания или нет. (Пример исправлен для 3.1.6.54)
ОписательВременныхТаблиц = КадровыйУчет.ОписательВременныхТаблицДляСоздатьВТКадровыеДанныеСотрудников(
МенеджерВременныхТаблиц,
"ВТСотрудники");
КадровыйУчет.СоздатьВТКадровыеДанныеСотрудников(ОписательВременныхТаблиц, Истина, "ДолжностьПоШтатномуРасписанию,ВидЗанятости");
ПараметрыПостроенияВТПозицииШтатногоРасписания = УправлениеШтатнымРасписанием.ПараметрыПостроенияВТШтатноеРасписаниеПоТаблицеФильтра("ВТКадровыеДанныеСотрудников");
ПараметрыПостроенияВТПозицииШтатногоРасписания.ИмяПоляПозицияШтатногоРасписания = "ДолжностьПоШтатномуРасписанию";
ИменаСведений = Неопределено; // в переменной можно указать строкой конкретные поля: "ОкладТариф, НадбавкаЗаВредностьРазмер"
УправлениеШтатнымРасписанием.СоздатьВТПозицииШтатногоРасписанияПоВременнойТаблице(
МенеджерВременныхТаблиц, Истина, ПараметрыПостроенияВТПозицииШтатногоРасписания, ИменаСведений);
Ну а причем здесь представления? Начнем с того, что представления запросов используются в СКД. Вы указываете в запросе, что надо выбрать из таблицы-представления, в событие ПриКомпоновкеДанных вставляете процедуру ЗарплатаКадрыОбщиеНаборыДанных.ЗаполнитьОбщиеИсточникиДанныхОтчета(ЭтотОбъект) и, вуаля, вместо представления запроса появляются несколько ВТ, помещенные в ваш запрос, правильно собирающие данные из базы. Пример для среза последних - получение графика работы на дату для штатных сотрудников
ВЫБРАТЬ РАЗРЕШЕННЫЕ
Сотрудники.Ссылка КАК Сотрудник,
ВЫБОР
КОГДА &Период < ТекущиеКадровыеДанныеСотрудников.ДатаПриема
ТОГДА ТекущиеКадровыеДанныеСотрудников.ДатаПриема
ИНАЧЕ &Период
КОНЕЦ КАК Период
ПОМЕСТИТЬ ВТСотрудники
ИЗ
Справочник.Сотрудники КАК Сотрудники
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК ТекущиеКадровыеДанныеСотрудников
ПО (Сотрудники.ФизическоеЛицо = ТекущиеКадровыеДанныеСотрудников.ФизическоеЛицо)
И (Сотрудники.Ссылка = ТекущиеКадровыеДанныеСотрудников.Сотрудник)
ГДЕ
ТекущиеКадровыеДанныеСотрудников.ДатаПриема <= &Период
И ТекущиеКадровыеДанныеСотрудников.ДатаПриема <> ДАТАВРЕМЯ(1, 1, 1)
И (ТекущиеКадровыеДанныеСотрудников.ДатаУвольнения = ДАТАВРЕМЯ(1, 1, 1)
ИЛИ ТекущиеКадровыеДанныеСотрудников.ДатаУвольнения >= &Период)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка) КАК Сотрудник,
ЗНАЧЕНИЕ(Справочник.ГрафикиРаботыСотрудников.ПустаяСсылка) КАК ГрафикРаботы
ПОМЕСТИТЬ Представления_СрезПоследних_ГрафикРаботыСотрудников
ИЗ
ВТСотрудники КАК ВТСотрудники
ГДЕ
"ТолькоРазрешенные" = ИСТИНА
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Представления_СрезПоследних_ГрафикРаботыСотрудников.Сотрудник КАК Сотрудник,
Представления_СрезПоследних_ГрафикРаботыСотрудников.ГрафикРаботы КАК ГрафикРаботы
ИЗ
Представления_СрезПоследних_ГрафикРаботыСотрудников КАК Представления_СрезПоследних_ГрафикРаботыСотрудников
Пример для "предопределенного" представления я бы привел для специфической таблицы Периоды
ВЫБРАТЬ
ДАТАВРЕМЯ(1, 1, 1) КАК Период
ПОМЕСТИТЬ Представления_Периоды
ГДЕ
"НачалоИнтервала" = &НачалоПериода
И "ОкончаниеИнтервала" = &КонецПериода
И "Периодичность" = "ДЕНЬ"
И "ИспользоватьКонецПериода" = ЛОЖЬ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Представления_Периоды.Период КАК Период
ИЗ
Представления_Периоды КАК Представления_Периоды
Не забудьте прописать процедуру в ПриКомпоновкеДанных, установить тип Дата в параметрах, добавить в структуру ДетальныеЗаписи, а в выбранные поля добавить Период. И получите таблицу дат с начала по конец периода.
Об использовании представлений в СКД больше расскажет конфигурация. Так что смотрите в ПолучитьЗапросПоПредставлению и пользуйтесь глобальным поиском, не забывая ставить флажок в Макеты. Стоит также отметить, что Представления охватывают лишь небольшую часть функций .СоздатьВТ.