Как правильно построить запрос на контроль остатков в 1С?

База знаний Одина — Одинэсника › Форумы › ODIN — Форум по 1С Предприятию › Как правильно построить запрос на контроль остатков в 1С?

Просмотр 1 ветки ответов
  • Автор
    Записи
    • #38862
      Фото аватараOdineski
      Участник

        Правильно ли я построил запрос на контроль остатков? Также объясни, почему мы выбираем именно такие параметры виртуальной таблицы. Ведь, вроде бы, мы делаем отбор номенклатуры через «связи», зачем делать это ещё раз?

        Запрос = Новый Запрос;
        Запрос.Текст =
        «ВЫБРАТЬ
        | РасходнаяНакладнаяСписокНоменклатуры.Номенклатура КАК Номенклатура,
        | СУММА(РасходнаяНакладнаяСписокНоменклатуры.Количество) КАК Количество
        |ПОМЕСТИТЬ втТЧТовары
        |ИЗ
        | Документ.РасходнаяНакладная.СписокНоменклатуры КАК РасходнаяНакладнаяСписокНоменклатуры
        |ГДЕ
        | РасходнаяНакладнаяСписокНоменклатуры.Ссылка = &Ссылка
        |
        |СГРУППИРОВАТЬ ПО
        | РасходнаяНакладнаяСписокНоменклатуры.Номенклатура
        |;
        |
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        | втТЧТовары.Номенклатура КАК Номенклатура,
        | втТЧТовары.Номенклатура.Представление КАК НоменклатураПредставление,
        | втТЧТовары.Количество КАК Количество,
        | ЕСТЬNULL(ОстаткиНоменклатурыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток
        |ИЗ
        | втТЧТовары КАК втТЧТовары
        | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки(
        | &МоментВремени,
        | Номенклатура В
        | (ВЫБРАТЬ
        | ОстаткиНоменклатуры.Номенклатура КАК Номенклатура
        | ИЗ
        | РегистрНакопления.ОстаткиНоменклатуры КАК ОстаткиНоменклатуры)
        | И Склад = &Склад) КАК ОстаткиНоменклатурыОстатки
        | ПО втТЧТовары.Номенклатура = ОстаткиНоменклатурыОстатки.Номенклатура»;

        Запрос.УстановитьПараметр(«МоментВремени», МоментВремени());
        Запрос.УстановитьПараметр(«Склад», Склад);
        Запрос.УстановитьПараметр(«Ссылка», Ссылка);

        РезультатЗапроса = Запрос.Выполнить();

      • #38863
        bot_avaOdin — Одинэсник
        Участник

          Запрос построен почти правильно, но в нем есть существенная ошибка в отборе номенклатуры.

          Сейчас у вас написано:

          Здесь подзапрос выбирает номенклатуру не из временной таблицы документа, а из самого регистра накопления. То есть условие фактически означает:

          > получить остатки по всей номенклатуре, которая когда-либо встречается в регистре.

          Нужно выбирать номенклатуру из втТЧТовары.

          Исправленный вариант:

          ## Зачем нужна группировка в первой части

          Первая часть запроса формирует список товаров текущего документа:

          Группировка нужна, чтобы объединить одинаковую номенклатуру, если она указана в табличной части несколько раз.

          Например:

          | Номенклатура | Количество |
          |—|—:|
          | Товар 1 | 3 |
          | Товар 1 | 5 |

          После группировки во временной таблице будет:

          | Номенклатура | Количество |
          |—|—:|
          | Товар 1 | 8 |

          Это важно для правильного контроля остатка. Проверять две строки отдельно было бы неправильно, потому что общий расход составляет 8 единиц.

          ## Зачем номенклатура отбирается еще и в параметрах виртуальной таблицы

          Вы правы в том, что номенклатура уже используется в связи:

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

          ### Связь

          Связь определяет, как соединить уже полученные наборы данных:

          Она отвечает на вопрос:

          > какие строки из результата виртуальной таблицы присоединить к строкам временной таблицы?

          ### Параметры виртуальной таблицы

          Параметры виртуальной таблицы задаются еще при формировании результата регистра:

          Они отвечают на другой вопрос:

          > какие данные вообще нужно получить из регистра?

          Это особенно важно для виртуальных таблиц регистров накопления. Без параметров виртуальная таблица может сначала сформировать остатки по большому объему данных регистра, а уже потом эти данные будут соединяться с втТЧТовары.

          ## Что произойдет без параметра Номенклатура В

          Если убрать этот отбор и оставить только связь:

          логически результат, скорее всего, останется правильным. В итог попадут товары документа.

          Но виртуальная таблица может быть рассчитана по всем товарам выбранного склада, а затем соединена с несколькими строками документа. Если в регистре сотни тысяч записей, это может ухудшить производительность.

          С параметром:

          вы сразу передаете виртуальной таблице ограниченный список товаров текущего документа.

          В вашем случае запрос должен получить остатки только для:

          ## Почему одного отбора по складу тоже недостаточно

          В параметрах виртуальной таблицы у вас два условия:

          Оба условия имеют смысл.

          Склад = &Склад ограничивает данные по складу.

          Номенклатура В (...) ограничивает данные по товарам документа.

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

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

          Для контроля остатков нужны оба измерения, если в регистре есть измерения:

          ## Важное замечание по виртуальной таблице

          Параметры виртуальной таблицы нужно задавать именно внутри круглых скобок после .Остатки():

          А не в обычном ГДЕ внешнего запроса.

          Вариант:

          может дать правильный результат, но для виртуальной таблицы это обычно менее удачный вариант. Фильтр лучше передать в ее параметры, чтобы ограничить получение данных регистра как можно раньше.

          ## Проверка результата

          После выполнения запроса проверку можно сделать так:

          Если нужно показать сообщение непосредственно в строке табличной части, одной временной таблицы с группировкой по номенклатуре будет недостаточно. Нужно дополнительно хранить номера строк табличной части либо отдельно получать строки документа.

          ## Обратите внимание на момент времени

          Строка:

          может быть правильной, но зависит от режима проведения и требований билета.

          Для оперативного проведения обычно дополнительно используется управляемая блокировка данных перед чтением остатков. Типовая последовательность:

          Если блокировка устанавливается после запроса остатков, два пользователя могут одновременно увидеть один и тот же остаток и оба провести расход.

          Также нужно следить, чтобы блокировка устанавливалась по тем же аналитикам, по которым читаются остатки:

          Если остатки контролируются еще по характеристике, серии или качеству, эти поля должны участвовать и в:

          — измерениях регистра;
          — временной таблице;
          — параметрах виртуальной таблицы;
          — условиях соединения;
          — блокировке.

          В вашем конкретном запросе главная ошибка только одна: в подзапросе нужно заменить обращение к регистру на обращение к временной таблице:

          Именно это обеспечивает отбор номенклатуры текущего документа, а не всей номенклатуры регистра.

      Просмотр 1 ветки ответов
      • Для ответа в этой теме необходимо авторизоваться.
      База знаний 1С