Работа с запросами в 1С:Предприятие 7.7 имеет ряд специфических особенностей, которые могут поставить в тупик даже опытных разработчиков, привыкших к механизмам восьмой версии платформы. Одной из таких задач является необходимость быстрого позиционирования внутри сложной выборки для получения данных по конкретному объекту без использования последовательного перебора всех записей. В этой статье мы подробно разберем, как использовать метод Получить для точечного входа в группировки, выясним, почему директива Без Итогов может нарушить работу вашего кода, и рассмотрим правильные способы передачи параметров.
Представим ситуацию: у нас есть запрос с двумя группировками — Объект и Событие. Нам необходимо получить все события для одного конкретного объекта, который мы уже знаем (например, выбрали из списка или получили из другой части кода). Традиционный путь — обходить весь запрос циклом Пока Запрос.Группировка(1) = 1 Цикл и сравнивать значение текущего объекта с искомым — крайне неэффективен на больших объемах данных.
Логичным кажется использование метода Запрос.Получить(). Однако здесь разработчики часто сталкиваются с тем, что метод возвращает 0 (запись не найдена), хотя данные в запросе точно присутствуют. Проанализируем причины такого поведения и найдем верное решение.
Метод Запрос.Получить() предназначен для позиционирования на конкретную строку итогов или детальную запись. Его синтаксис подразумевает передачу значений группировок в том порядке, в котором они описаны в тексте запроса.
Важный нюанс: Если мы хотим спозиционироваться на уровне первой группировки (на «шапке» объекта), чтобы затем обойти все его события, нам нужно передать только один параметр. Рассмотрим пример:
// Правильное позиционирование на первую группировку
Если Запрос.Получить(ВыбранныйОбъект) = 1 Тогда
// Теперь мы «внутри» конкретного объекта
Пока Запрос.Группировка("Событие") = 1 Цикл
// Обходим только события этого объекта
Сообщить(Запрос.Событие);
КонецЦикла;
КонецЕсли;
Обратите внимание: если вы напишете Запрос.Получить(ВыбранныйОбъект, ) (с запятой в конце), система будет пытаться найти запись, где первая группировка равна объекту, а вторая группировка пустая. Если в базе нет событий с пустым значением, метод вернет 0. Поэтому лишние запятые в данном случае критичны.
Проанализируем одну из самых частых ошибок, упомянутых в обсуждении. Если в тексте запроса указана фраза Без Итогов (или Without Totals), структура группировок в памяти системы меняется коренным образом.
В обычном режиме запрос строит иерархическое дерево, где есть промежуточные узлы (итоги по группировкам). Метод Получить(Объект) ищет именно такой узел. Если же добавлена директива Без Итогов, запрос возвращает «плоскую» таблицу, состоящую только из детальных записей. В этом режиме промежуточных итогов не существует, и метод Получить() либо не срабатывает вовсе при передаче неполного набора параметров, либо требует передачи всех значений группировок одновременно для поиска конкретной строки.
Решение: Если вам нужно использовать иерархический обход и метод Получить для позиционирования на верхних уровнях, обязательно удалите Без Итогов из текста запроса.
Еще одна частая причина неудач при вызове метода Получить — передача неверного типа данных в качестве параметра. В 1С 7.7 объект справочника (созданный через СоздатьОбъект) и ссылка на элемент справочника — это разные сущности в контексте запроса.
Разберем, как гарантированно передать верное значение:
ТекущийЭлемент().Справочник.Сотрудники, а вы передаете элемент из Справочник.ФизЛица, позиционирование не сработает.Пример корректной подготовки данных:
Спр = СоздатьОбъект("Справочник.Клиенты");
Если Спр.НайтиПоНаименованию("Иванов", 0, 1) = 1 Тогда
НужныйОбъект = Спр.ТекущийЭлемент(); // Получаем ссылку
Если Запрос.Получить(НужныйОбъект) = 1 Тогда
// Успешное позиционирование
КонецЕсли;
КонецЕсли;
Проанализируем правильный алгоритм работы с выборкой, чтобы избежать ошибок «сбитого курсора»:
Получить(), особенно если до этого выполнялся обход в цикле, крайне желательно вызвать Запрос.ВНачалоВыборки(). Это гарантирует, что поиск начнется с чистого листа.Получить(). Если он вернул 0, дальнейший вызов Группировка() не имеет смысла.Группировка(2) (или по имени группировки). Система начнет перебор записей именно внутри выбранного родительского узла.Если работа с прямым позиционированием в запросе кажется слишком громоздкой или нестабильной (например, при очень сложных условиях), рассмотрим «золотой стандарт» разработчиков 1С 7.7 — выгрузку результата в Таблицу Значений (ТЗ).
ТЗ = СоздатьОбъект("ТаблицаЗначений");
Запрос.Выгрузить(ТЗ, 0, 0); // Выгружаем с группировками
ТЗ.ВыбратьСтроку(); // Для отладки
Работа с ТЗ дает несколько преимуществ:
НайтиЗначение() для быстрого поиска.
Однако помните, что выгрузка огромного запроса в ТЗ потребляет значительный объем оперативной памяти, поэтому для миллионов строк лучше все же освоить метод Получить().
Для успешного обхода конкретной ветки запроса в 1С 7.7 необходимо:
Без Итогов.ВНачалоВыборки() для подготовки курсора.Получить() именно ссылку (ТекущийЭлемент).Соблюдение этих правил позволит вам писать эффективный и быстрый код, сохраняя традиции качественной разработки на платформе 1С 7.7. Тем, кто планирует переходить на более современные программы 1С, будет полезен раздел с готовыми решениями для переноса данных из 1С 7.7.