Почему не работает ВыбратьПоЗначению в журнале расчетов 1С 7.7 на SQL?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При длительной эксплуатации конфигураций на платформе 1С:Предприятие 7.7 разработчики нередко сталкиваются с ситуацией, когда проверенный годами код выборки данных журнала расчетов внезапно перестает работать. Цикл обхода записей просто игнорируется, хотя входные параметры заполнены корректно. При этом в файловой (DBF) копии базы данных или в архивных копиях тот же самый код отрабатывает без нареканий.

Проанализируем типовой фрагмент кода, в котором возникает ошибка:


ЖЗП.ВыбратьПоЗначению("Подразделение", ТекПодр, ДН, ДК);
Пока ЖЗП.ПолучитьЗапись() = 1 Цикл
    // Обработка записей журнала расчетов
КонецЦикла;

Выясним причину такого поведения платформы при работе с Microsoft SQL Server и разберем практические способы решения этой проблемы.

Причины некорректной работы выборки на SQL-версии

Разница в поведении между файловым движком и клиентом MS SQL Server кроется в механизмах трансляции платформенных команд в запросы к СУБД:

  1. Передача типа «Дата» вместо объекта «Период журнала расчетов». Метод ВыбратьПоЗначению в качестве параметров интервала выборки ожидает специальные агрегатные объекты расчетного периода. В файловом режиме (DBF) внутренний обработчик платформы часто выполняет неявное приведение обычной даты к расчетному периоду. Однако на стороне SQL платформа генерирует прямой запрос к таблице журнала расчетов (CJ*). Если передана дата, а не период, транслятор условий формирует некорректный фильтр по границам действия записей, из-за чего результирующий набор данных оказывается пустым.
  2. Отбор по группам справочников. При работе с SQL-версией отбор по графам и реквизитам журнала расчетов выполняет строгое сравнение внутренних строковых идентификаторов (ID). Если в переменную ТекПодр передается группа справочника, прямое сравнение на уровне СУБД не находит вхождений, так как автоматическое разворачивание иерархии в данном методе не выполняется.
  3. Сбои индексов и расхождение словаря данных (1CV7.DDS). Регламентное тестирование и исправление (ТИИ) не всегда перестраивает системные индексы таблиц расчета в базе SQL. При нарушении целостности индекса или рассинхронизации структуры между словарем 1CV7.DDS и базой данных MS SQL Server выборка по индексированной графе журнала перестает возвращать строки.

Способ 1. Явное приведение дат к периодам журнала расчетов

Разберем первый и самый надежный способ исправления платформенного вызова. Преобразуем стандартные переменные даты начала и даты окончания в объекты расчетного периода с помощью метода ПериодПоДате() самого журнала расчетов.

Посмотрим на пример правильного вызова:


ПерНач = ЖЗП.ПериодПоДате(ДН);
ПерКон = ЖЗП.ПериодПоДате(ДК);

// Проверяем, что передается элемент, а не группа справочника
Если (ПустоеЗначение(ТекПодр) = 0) И (ТекПодр.ЭтоГруппа() = 0) Тогда
    ЖЗП.ВыбратьПоЗначению("Подразделение", ТекПодр, ПерНач, ПерКон);
    Пока ЖЗП.ПолучитьЗапись() = 1 Цикл
        // Обработка записей журнала
    КонецЦикла;
КонецЕсли;

Если требуется получить выборку строго в рамках одного расчетного периода, передадим один и тот же объект периода в качестве начальной и конечной границы:


ТекПер = ЖЗП.ПериодПоДате(ДН);
ЖЗП.ВыбратьПоЗначению("Подразделение", ТекПодр, ТекПер, ТекПер);
Пока ЖЗП.ПолучитьЗапись() = 1 Цикл
    // Обработка записей журнала
КонецЦикла;

Способ 2. Обход записей через ВыбратьПериод с программным фильтром

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

Рассмотрим реализацию данного обходного пути:


ПерНач = ЖЗП.ПериодПоДате(ДН);
ПерКон = ЖЗП.ПериодПоДате(ДК);

ЖЗП.ВыбратьПериод(ПерНач, ПерКон);
Пока ЖЗП.ПолучитьЗапись() = 1 Цикл
    // Фильтруем записи по значению подразделения
    Если ЖЗП.Подразделение <> ТекПодр Тогда
        Продолжить;
    КонецЕсли;

    // Полезный код обработки записи
КонецЦикла;

Данный вариант полностью устраняет зависимость от внутреннего механизма выборки по значению графы журнала на сервере СУБД.

Способ 3. Использование встроенного механизма запросов

Альтернативным и более производительным решением для больших объемов данных является использование объекта Запрос. Встроенный язык запросов 1С 7.7 корректно транслирует условия отбора в синтаксис T-SQL без сбоев на уровне агрегатных периодов.

Посмотрим, как построить такой запрос:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"//{{ЗАПРОС(ВыборкаЖР)
|Период С ДН По ДК;
|ТекущаяЗапись = ЖурналРасчетов.Зарплата.ТекущаяЗапись;
|Подр = ЖурналРасчетов.Зарплата.Подразделение;
|Группировка ТекущаяЗапись;
|Условие(Подр = ТекПодр);
|"//}}ЗАПРОС
;

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка("ТекущаяЗапись") = 1 Цикл
        // Доступ к текущей записи журнала через Запрос.ТекущаяЗапись
    КонецЦикла;
КонецЕсли;

Способ 4. Восстановление структуры и индексов базы данных на сервере

Если замена кода нежелательна, а сбой выборки возник внезапно без изменения конфигурации (файла 1cv7.md), выполним административное обслуживание базы данных:

  1. Выгрузка и загрузка данных. Запустим «Конфигуратор», перейдем в меню «Администрирование» — «Выгрузить данные» и сохраним архивную копию базы. Затем создадим на MS SQL Server чистую базу данных и выполним операцию «Загрузить данные». Это действие заново сформирует физические таблицы CJ* и полностью перестроит индексы в соответствии с описанием метаданных.
  2. Переиндексация и обновление статистики на стороне СУБД. В среде SQL Server Management Studio выполним регламентные команды для таблиц расчетов:
    
    -- Обновление статистики для базы
    EXEC sp_updatestats;
    
← На главную