1C-CodeОсновы 1С → Виртуальные таблицы регистров

Виртуальные таблицы регистров

Откуда берутся остатки и обороты, если их никто не хранит. Пять таблиц, параметры вместо ГДЕ и граница периода, из-за которой документ не видит сам себя.

Глава 27 из 36 · чтение примерно 26 минут

В главе про регистры накопления мы выяснили: остаток не хранится, он считается по движениям. Здесь — про то, чем его считают.

Писать «сумма приходов минус сумма расходов» руками не надо: у каждого регистра есть готовые виртуальные таблицы. Виртуальные — потому что их нет в базе: платформа собирает их на лету из движений и хранимых итогов.

Какие бывают

ТаблицаОтвечает на вопросКогда берут
Остаткисколько на датупроверка перед списанием, отчёт по складу
Оборотысколько за периодпродажи за месяц, поступления за квартал
ОстаткиИОборотыбыло, пришло, ушло, сталооборотно-сальдовая ведомость
СрезПоследнихдействующее значение на датуцена, курс, оклад
СрезПервыхпервое значение с датыреже; про него спрашивают на собеседовании

Параметры, а не ГДЕ

Это главное правило главы, и оно про скорость, а не про красоту.

У виртуальной таблицы есть параметры: период, условие отбора, разрезы. Их пишут в скобках сразу после имени таблицы. Платформа передаёт их вглубь — и читает только нужные итоги.

Если тот же отбор поставить в ГДЕ, платформа сначала соберёт таблицу целиком, а потом выбросит лишнее. Результат одинаковый, работа разная — на большой базе в десятки раз.

Отбор внутри скобок

ВЫБРАТЬ
	О.Номенклатура,
	О.КоличествоОстаток
ИЗ
	РегистрНакопления.ОстаткиТоваров.Остатки(
		&НаДату,
		Склад = &Склад) КАК О
ЧастьЧто означает
.Остатки(виртуальная таблица, а не таблица движений
&НаДатупервый параметр — момент, на который считаем
Склад = &Складотбор ВНУТРИ скобок: платформа возьмёт только нужное
КоличествоОстатокимя ресурса плюс «Остаток» — так называются поля этой таблицы

Граница периода

Момент времени в 1С — это не только дата, но и позиция документа внутри неё. Отсюда два вида границы: включая и исключая.

Документ, который проверяет остаток при проведении, должен смотреть на момент перед собой — иначе он увидит собственное движение и решит, что товара хватает. Для этого берут Новый Граница(МоментВремени(), ВидГраницы.Исключая).

Ошибка здесь не падает и не видна глазами: она проявляется через месяц как «минус на складе».

Имена полей

Поля виртуальных таблиц называются не так, как ресурсы регистра, и это сбивает.

У ресурса Количество в таблице Остатки поле называется КоличествоОстаток. В таблице ОборотыКоличествоОборот, а если регистр остаточный, то ещё КоличествоПриход и КоличествоРасход.

В ОстаткиИОбороты их четыре: КоличествоНачальныйОстаток, КоличествоПриход, КоличествоРасход, КоличествоКонечныйОстаток.

На чём спотыкаются

Берут таблицу движений вместо виртуальной. ИЗ РегистрНакопления.ОстаткиТоваров — это все движения за всю историю, а не остаток. Работать будет, считать придётся руками, и на объёме это ляжет.

Забывают, что строки может не быть. Нет остатка — нет строки. Соединение с номенклатурой обязано быть левым, а результат обёрнут в ЕСТЬNULL.

Считают обороты через остатки на две даты. Разность остатков не равна обороту, если были и приход, и расход. Для оборота есть своя таблица.

Что такое «виртуальная» на самом деле

Таблицы с таким именем в базе нет. Когда вы пишете РегистрНакопления.ОстаткиТоваров.Остатки, платформа подставляет вместо этого имени целый запрос: к таблице итогов, к таблице движений, со своими соединениями и группировками.

Отсюда два следствия, которые объясняют всё остальное поведение виртуальных таблиц.

Параметры попадают внутрь этого запроса, а ГДЕ — нет. Отбор в параметрах платформа вставит в подставляемый текст, и лишние строки не будут даже посчитаны. Условие в ГДЕ применяется к уже готовому результату.

Соединять виртуальные таблицы между собой — дорого. Каждая из них разворачивается в свой подзапрос, и база соединяет два вычисленных набора, ничего не зная о них заранее.

Период и периодичность

У таблиц оборотов есть параметр Периодичность, и он отвечает на вопрос «сколько строк я хочу получить».

Период — одна строка на весь интервал. Месяц, День, Регистратор — строка на каждый месяц, день, документ. Указали Регистратор на годовом отчёте — получите строку на каждый документ за год.

Полезное следствие: график «продажи по месяцам» не требует ни группировки, ни функций работы с датой. Достаточно попросить периодичность «Месяц» — остальное сделает платформа.

Обороты по месяцам одной строкой

ВЫБРАТЬ
	Период,
	Номенклатура,
	КоличествоОборот
ИЗ
	РегистрНакопления.Продажи.Обороты(
		&Начало, &Конец, Месяц, Номенклатура В (&Список))
ЧастьЧто означает
&Начало, &Конецграницы периода; пусто означает «с самого начала» и «по сейчас»
Месяцпериодичность: строка на каждый месяц, где были движения
Номенклатура В (…)отбор — четвёртым параметром, а не в ГДЕ
КоличествоОбороту оборотов имена колонок кончаются на «Оборот», у остатков — на «Остаток»

Пустой период — это не «за всё время»

Оставить границы пустыми можно, и на демо-базе это работает. На настоящей — означает «посчитай обороты за всю историю базы», то есть по всем движениям с самого начала.

Отчёт при этом не сломается — он просто будет думать минуту вместо секунды, и никто не поймёт почему.

Поэтому границы задают всегда, даже когда «нужно всё»: у бизнеса «всё» обычно означает текущий год.

ОстаткиИОбороты: три набора колонок сразу

Оборотно-сальдовая ведомость — самый частый отчёт в учёте, и делается он одной виртуальной таблицей.

ОстаткиИОбороты отдаёт сразу четыре набора колонок: НачальныйОстаток, Приход, Расход, КонечныйОстаток — с именем ресурса впереди: КоличествоНачальныйОстаток, КоличествоПриход и так далее.

Считать начальный остаток отдельным запросом и вычитать руками не надо — это ровно то, что делают, не зная про эту таблицу.

Почему в отчёте «приход есть, остатка нет»

Знакомая картина: в обороты товар попал, а в остатки — нет. Обычно виноват не регистр, а границы.

Остатки считаются НА момент, и момент этот — мгновение. Остаток «на 31 марта» без времени означает «на 31 марта в 00:00», то есть до всех документов этого дня.

Отсюда правило из главы про даты: конец периода приводят к КонецДня. А в паре «остатки и обороты» платформа делает это сама — ещё одна причина брать её, а не собирать из кусков.

Когда виртуальная таблица не нужна

Есть случай, когда правильнее взять сами движения, а не итоги: когда нужен регистратор — кто это сделал.

«Покажи, из каких документов сложился этот остаток» — вопрос не к остаткам, а к движениям. В виртуальной таблице регистратора нет вовсе: она уже всё сложила.

Второй случай — когда движений мало и они все нужны: расшифровка по одному документу, проверка своего же проведения.

Упражнение 2. Обороты, а не остатки

Напишите ВыручкаЗаВсё(): сумма по колонке ВыручкаОборот регистра Продажи через виртуальную таблицу .Обороты, без ограничения периода. Ожидается 26300.

Решается в тренажёре: код запускается и проверяется сразу.

Упражнение 1. Позиций на остатке

Функция ПозицийНаОстатке() должна вернуть, по скольким позициям номенклатуры есть остаток. Возьмите виртуальную таблицу РегистрНакопления.ОстаткиТоваров.Остатки и посчитайте строки — писать «приход минус расход» руками не нужно.

Решается в тренажёре: код запускается и проверяется сразу.

Короткий свод

Виртуальные таблицы собираются на лету из движений и итогов. Остатки — на дату, Обороты — за период, ОстаткиИОбороты — всё сразу, СрезПоследних — действующее значение. Отбор передают параметром в скобках, не через ГДЕ. Момент времени бывает включающим и исключающим: документ при проведении смотрит на «перед собой». Имена полей — ресурс плюс «Остаток», «Оборот», «Приход», «Расход».

Как закрепить

Читать про код и писать код — разные умения. В тренажёре к этой главе идут упражнения: вы пишете решение, оно запускается на настоящем интерпретаторе 1С и проверяется сразу, без установки платформы.

Открыть эту главу в тренажёре

Соединения и NULL
Что тормозит и почему