Мы сталкиваемся с ситуацией, когда условие исключения счетов в запросе 1С, например, НЕ Счет В (&Счета), не дает ожидаемого результата, и в выборку все равно попадают счета, которые должны быть исключены. Давайте вместе разберем эту проблему и найдем эффективные решения, учитывая особенности работы с планами счетов и виртуальными таблицами регистра бухгалтерии.
Автор столкнулся с такой проблемой при написании запроса к виртуальной таблице РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты. Его запрос выглядел следующим образом:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Регистр.Регистратор КАК Регистратор,
Регистр.Счет КАК Счет
ИЗ
РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(, , Регистратор, , НЕ Счет В (&Счета), , ЖурналОпераций = &Журнал) КАК Регистр
Несмотря на использование оператора НЕ Счет В (&Счета), фильтрация не работала. Чтобы решить эту задачу, мы должны рассмотреть несколько ключевых моментов.
Одной из наиболее распространенных причин некорректной работы фильтрации по счетам является несоответствие типов данных. Когда мы передаем массив в параметр запроса &Счета, крайне важно, чтобы элементы этого массива имели тот же тип, что и поле Счет в регистре бухгалтерии. В 1С поле Счет всегда имеет тип ПланСчетов.Хозрасчетный.Ссылка.
Если в массив &Счета передаются строковые коды счетов, их наименования или какие-либо другие типы данных, отличные от ссылки на элемент плана счетов, платформа 1С не сможет корректно сравнить эти значения. Оператор В (или НЕ В) в запросах 1С работает на основе сравнения ссылок для ссылочных типов. Строковое сравнение будет производиться только если поле в регистре имеет строковый тип, что не относится к счету бухгалтерского учета.
Что нужно сделать:
&Счета, содержит ссылки на элементы плана счетов (например, ПланыСчетов.Хозрасчетный.НайтиПоКоду("60.01") или ссылки, полученные из других запросов/объектов).Пример формирования массива счетов для параметра:
// Пример формирования массива счетов на стороне 1С-кода
МассивСчетовДляИсключения = Новый Массив();
// Добавляем ссылки на конкретные счета
МассивСчетовДляИсключения.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("60.01"));
МассивСчетовДляИсключения.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("76"));
// ...можно получить счета из таблицы значений или другой коллекции
// Например, если у вас есть таблица значений с колонкой "СчетСсылка"
// Для Каждого СтрокаТЗ Из МояТаблицаСчетов Цикл
// МассивСчетовДляИсключения.Добавить(СтрокаТЗ.СчетСсылка);
// КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ
| Регистр.Регистратор КАК Регистратор,
| Регистр.Счет КАК Счет
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , НЕ Счет В (&Счета), , ) КАК Регистр";
// Устанавливаем параметры запроса
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("Счета", МассивСчетовДляИсключения);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Регистратор: " + Выборка.Регистратор + ", Счет: " + Выборка.Счет);
КонецЦикла;
План счетов в 1С имеет иерархическую структуру. Это означает, что счета могут иметь субсчета (подчиненные счета). Например, счет 60 "Расчеты с поставщиками и подрядчиками" может иметь субсчета 60.01 "Расчеты с поставщиками" и 60.02 "Расчеты по авансам выданным".
Оператор В (и соответственно НЕ В) в запросе проверяет только прямое вхождение элемента в переданный список. Он не учитывает иерархию. То есть, если вы добавите в массив &Счета только ссылку на счет 60, оператор НЕ Счет В (&Счета) исключит только сам счет 60, но не его субсчета 60.01 и 60.02. Если проводки были сделаны по субсчетам, они все равно попадут в выборку.
Для корректного исключения счетов вместе с их субсчетами (и всей иерархией), необходимо использовать оператор В ИЕРАРХИИ.
Применение оператора В ИЕРАРХИИ вместо В позволяет запросу учитывать всю ветку иерархии, исключая как сам указанный счет (или группу счетов), так и все его дочерние элементы.
Пример изменения запроса:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Регистр.Регистратор КАК Регистратор,
Регистр.Счет КАК Счет
ИЗ
РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(, , Регистратор, , НЕ Счет В ИЕРАРХИИ (&Счета), , ЖурналОпераций = &Журнал) КАК Регистр
Обратите внимание на НЕ Счет В ИЕРАРХИИ (&Счета). Теперь, если в массиве &Счета будет счет 60, из выборки будут исключены все проводки как по счету 60, так и по всем его субсчетам (60.01, 60.02 и т.д.).
Этот оператор критически важен при работе с иерархическими справочниками и планами счетов, когда требуется комплексная фильтрация.
В вашем первоначальном запросе условие НЕ Счет В (&Счета) правильно размещено в параметрах виртуальной таблицы РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты. Это является стандартным и наиболее эффективным способом фильтрации данных на уровне формирования виртуальной таблицы, что позволяет СУБД выполнить фильтрацию до того, как данные будут переданы в 1С, значительно улучшая производительность.
Однако, мы должны убедиться, что другие параметры виртуальной таблицы также установлены корректно и не конфликтуют с нашим условием исключения счетов. Например, период выборки, вид движения (остатки, обороты, приход, расход), условия по регистратору или другим измерениям должны соответствовать вашим требованиям.
Параметры виртуальной таблицы ОстаткиИОбороты:
<НачалоПериода><КонецПериода><ВидДвижения> (Например, 'Итоги', 'Приход', 'Расход' или пусто, если не требуется)<Регистратор> (Если нужна фильтрация по конкретному регистратору)<УсловиеСчет> (Это наш случай: НЕ Счет В ИЕРАРХИИ (&Счета))<УсловиеСубконто> (Если нужна фильтрация по субконто)<УсловиеОрганизация> (Если нужна фильтрация по организации)<УсловиеВалюта> (Если нужна фильтрация по валюте)<УсловиеСчетКорреспондирующий> (Если нужна фильтрация по корреспондирующему счету)<УсловиеСубконтоКорреспондирующее> (Если нужна фильтрация по субконто корреспондирующего счета)<УсловиеВидСубконто><УсловиеВидСубконтоКорреспондирующее><Балансовый> (Ложь/Истина, влияет на вид остатков)<РазрешенныеСубконто>Важно помнить, что если вы не используете какой-либо параметр, его нужно либо пропустить (поставив запятую, как в вашем примере), либо передать пустое значение, если это допустимо.
Если вы все еще сталкиваетесь с проблемами, критически важно проверить содержимое массива &Счета непосредственно перед выполнением запроса в режиме отладчика. Это позволит вам убедиться, что:
МассивСчетовДляИсключения содержит именно те счета, которые вы ожидаете.ПланСчетов.Хозрасчетный.Ссылка.Для этого установите точку останова перед строкой Результат = Запрос.Выполнить(); и посмотрите значения переменных МассивСчетовДляИсключения и Запрос.Параметры.Счета.
Что произойдет, если массив &Счета окажется пустым? В большинстве случаев, если массив пуст, условие НЕ Счет В (&Счета) не будет оказывать никакого влияния на выборку, то есть фактически не будет никакой фильтрации по счетам. Это может быть как желаемым, так и нежелаемым поведением, в зависимости от логики вашей задачи.
Если вам нужно, чтобы при пустом массиве условие НЕ Счет В (&Счета) всегда применялось (например, чтобы ничего не выбрать или выбрать все), вам может потребоваться динамически изменять текст запроса:
1 = 0).Обычно поступают так: если массив счетов пуст, то условие фильтрации по счетам вообще не добавляют в запрос. Это можно реализовать с помощью условных операторов при формировании текста запроса.
Пример динамического формирования текста запроса:
// Предположим, что МассивСчетовДляИсключения уже сформирован
Если МассивСчетовДляИсключения.Количество() > 0 Тогда
УсловиеПоСчетам = "НЕ Счет В ИЕРАРХИИ (&Счета)";
Иначе
// Если массив пуст, условие не применяется, выбираем все счета
УсловиеПоСчетам = "";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ
| Регистр.Регистратор КАК Регистратор,
| Регистр.Счет КАК Счет
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , " + УсловиеПоСчетам + ", , ) КАК Регистр";
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));
Если МассивСчетовДляИсключения.Количество() > 0 Тогда
Запрос.УстановитьПараметр("Счета", МассивСчетовДляИсключения);
КонецЕсли;
Результат = Запрос.Выполнить();
// ... дальнейшая обработка
Чтобы окончательно решить проблему с исключением счетов в запросе 1С, рекомендуем придерживаться следующего алгоритма:
&Счета, состоит из элементов типа ПланСчетов.Хозрасчетный.Ссылка. Используйте отладчик для проверки.В ИЕРАРХИИ: Если ваши счета имеют иерархическую структуру и вы хотите исключить не только родительские счета, но и все их субсчета, измените условие на НЕ Счет В ИЕРАРХИИ (&Счета).ОстаткиИОбороты (период, вид движения и т.д.) установлены корректно и не влияют на результат выборки счетов.&Счета может быть пустым, рассмотрите возможность динамического изменения текста запроса, чтобы условие фильтрации по счетам применялось только при наличии счетов в массиве.Соблюдение этих рекомендаций позволит нам эффективно и корректно управлять фильтрацией счетов в запросах 1С, избегая распространенных ошибок и получая ожидаемый результат.