При разработке отчетов или алгоритмов проведения часто возникает ситуация, когда при соединении табличной части документа с регистром накопления запрос возвращает больше строк, чем содержится в самом документе (например, вместо 2 строк получается 4). Разберем причины возникновения таких дублей и рассмотрим правильные архитектурные подходы к построению запросов в 1С.
Рассмотрим типовой ошибочный запрос, с которого началось обсуждение:
ВЫБРАТЬ
ТоварыКПолучениюНаСкладыОстаткиИОбороты.ДокументПолучения,
ТоварыКПолучениюНаСкладыОстаткиИОбороты.Номенклатура,
ТоварыКПолучениюНаСкладыОстаткиИОбороты.ХарактеристикаНоменклатуры,
ТоварыКПолучениюНаСкладыОстаткиИОбороты.СерияНоменклатуры,
ТоварыКПолучениюНаСкладыОстаткиИОбороты.КоличествоКонечныйОстаток,
РасходныйОрдерНаТоварыТовары.Ссылка,
РасходныйОрдерНаТоварыТовары.Количество,
РасходныйОрдерНаТоварыТовары.ЕдиницаИзмерения,
РасходныйОрдерНаТоварыТовары.Коэффициент
ИЗ
Документ.РасходныйОрдерНаТовары.Товары КАК РасходныйОрдерНаТоварыТовары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыКПолучениюНаСклады.ОстаткиИОбороты(&НачДата, &КонДата, Регистратор, , ) КАК ТоварыКПолучениюНаСкладыОстаткиИОбороты
ПО РасходныйОрдерНаТоварыТовары.Ссылка = ТоварыКПолучениюНаСкладыОстаткиИОбороты.Регистратор
ГДЕ
РасходныйОрдерНаТоварыТовары.Ссылка.ДокументПередачи = &ПеремещениеТоваров
Выясним главные причины появления дублей в таком запросе:
Ссылка = Регистратор. Если в регистре учет ведется с дополнительной аналитикой (например, по характеристикам, сериям или складам), одна строка табличной части соединяется со всеми движениями документа в регистре, порождая кратное умножение строк.Регистратор в таблице ОстаткиИОбороты. При такой периодичности виртуальная таблица возвращает движения в разрезе каждого регистратора. Если один и тот же документ породил несколько движений по разной аналитике, на один документ сформируется несколько записей.Проанализируем архитектуру хранения данных в типовых конфигурациях. В большинстве случаев обращаться напрямую к табличной части документа вообще не требуется. Если нам нужно узнать количество к получению или фактические остатки, источником данных должен выступать сам регистр накопления.
Часто разработчики обращаются к табличной части только ради полей ЕдиницаИзмерения и Коэффициент. Однако эти данные являются условно-постоянными и привязаны к номенклатуре. Единица хранения остатков и ее коэффициент (всегда равный 1) берутся из реквизитов справочника Номенклатура.
Посмотрим на пример правильного запроса к виртуальной таблице Остатки без обращения к документам:
ВЫБРАТЬ
ТоварыКПолучениюОстатки.ДокументПолучения КАК ДокументПолучения,
ТоварыКПолучениюОстатки.Номенклатура КАК Номенклатура,
ТоварыКПолучениюОстатки.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
ТоварыКПолучениюОстатки.Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения,
1 КАК Коэффициент,
ТоварыКПолучениюОстатки.КоличествоОстаток КАК КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыКПолучениюНаСклады.Остатки(
&Период,
ДокументПолучения = &ПеремещениеТоваров
) КАК ТоварыКПолучениюОстатки
В этом варианте отбор передается непосредственно в параметры виртуальной таблицы, что обеспечивает максимальное быстродействие и полностью исключает задвоение строк.
Если специфика задачи действительно требует сопоставить строки документа и остатки регистра, разберем правильную схему реализации через временные таблицы.
Номенклатура, ХарактеристикаНоменклатуры и т.д.).Посмотрим на пример реализации:
ВЫБРАТЬ
РасходныйОрдерТовары.Ссылка КАК Ссылка,
РасходныйОрдерТовары.Номенклатура КАК Номенклатура,
РасходныйОрдерТовары.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
РасходныйОрдерТовары.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
РасходныйОрдерТовары.Коэффициент КАК Коэффициент,
СУММА(РасходныйОрдерТовары.Количество) КАК Количество
ПОМЕСТИТЬ ВТ_ТоварыДокумента
ИЗ
Документ.РасходныйОрдерНаТовары.Товары КАК РасходныйОрдерТовары
ГДЕ
РасходныйОрдерТовары.Ссылка.ДокументПередачи = &ПеремещениеТоваров
СГРУППИРОВАТЬ ПО
РасходныйОрдерТовары.Ссылка,
РасходныйОрдерТовары.Номенклатура,
РасходныйОрдерТовары.ХарактеристикаНоменклатуры,
РасходныйОрдерТовары.ЕдиницаИзмерения,
РасходныйОрдерТовары.Коэффициент
ИНДЕКСИРОВАТЬ ПО
Номенклатура,
ХарактеристикаНоменклатуры
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ТоварыДокумента.Ссылка КАК Документ,
ВТ_ТоварыДокумента.Номенклатура КАК Номенклатура,
ВТ_ТоварыДокумента.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
ВТ_ТоварыДокумента.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
ВТ_ТоварыДокумента.Коэффициент КАК Коэффициент,
ВТ_ТоварыДокумента.Количество КАК КоличествоВДокументе,
ЕСТЬNULL(ТоварыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток
ИЗ
ВТ_ТоварыДокумента КАК ВТ_ТоварыДокумента
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыКПолучениюНаСклады.Остатки(
&Период,
Номенклатура В (ВЫБРАТЬ РАЗЛИЧНЫЕ Т.Номенклатура ИЗ ВТ_ТоварыДокумента КАК Т)
) КАК ТоварыОстатки
ПО ВТ_ТоварыДокумента.Номенклатура = ТоварыОстатки.Номенклатура
И ВТ_ТоварыДокумента.ХарактеристикаНоменклатуры = ТоварыОстатки.ХарактеристикаНоменклатуры
Для предотвращения ошибок и обеспечения высокой производительности базы данных придерживаемся следующих правил:
ПОМЕСТИТЬ) с индексацией полей связи (ИНДЕКСИРОВАТЬ ПО).ГДЕ или условиях связи ПО.Остатки вместо ресурсоемкой таблицы ОстаткиИОбороты.