Рассмотрим весьма специфичную и неочевидную проблему, с которой можно столкнуться при работе с прямыми запросами к базам данных 1С:Предприятие 7.7 в формате DBF. Допустим, мы пишем простой запрос для поиска в справочнике ЮрЛица (например, в конфигурации "Торговля и Склад") по части ИНН.
Проанализируем базовый текст запроса, который мы пытаемся выполнить через провайдер VFPOLEDB:
ТекстЗапроса = "
|SELECT
| ЮрЛица.ID as [Элемент $Справочник.ЮрЛица]
|FROM
| $Справочник.ЮрЛица as ЮрЛица
|WHERE $ЮрЛица.ИНН LIKE '%" + СокрЛП(СтрокаПоиска) + "%'";
Парадокс заключается в том, что в справочнике гарантированно есть искомый элемент, и обычным запросом 1С по четкому поиску результат находится успешно. Однако прямой запрос возвращает пустой результат. При этом, если мы запрашиваем другие поля (например, Наименование или Код), то они читаются корректно, а вот поле ИНН оказывается абсолютно пустым или содержит "мусор". Выясним причину такого странного поведения.
Если мы посмотрим на структуру данных через системные файлы 1С (например, 1Cv7.DD), мы можем обнаружить следующее: реквизит ИНН (допустим, поле sp494) хранится в таблице SC***.DBF корректно. Но проблема кроется не в самом ИНН, а в соседних реквизитах.
В ходе детального разбора структуры таблицы выясняется, что в справочнике присутствует другой текстовый реквизит (например, "Полное наименование"), длина которого установлена в 900 символов. Именно здесь кроется архитектурное ограничение.
Проблема возникает из-за ограничения формата DBF (в частности dBASE / FoxPro). Согласно спецификациям этого формата, максимальная длина обычного строкового поля (тип Character) жестко ограничена 254 символами.
Провайдер VFPOLEDB (Visual FoxPro OLE DB Provider), который традиционно используется для прямых запросов к DBF-версии 1С 7.7, строго следует этому стандарту. Когда драйвер встречает поле длиной больше 254 символов, его алгоритм расчета смещения байтов ломается. В результате все колонки, которые идут в таблице после этого "аномального" поля, считываются со сдвигом: драйвер берет куски данных из соседних колонок. Из-за этого наша колонка с ИНН при чтении запросом оказывается пустой или нерелевантной.
У вас может возникнуть логичный вопрос: почему сама 1С и внешние компоненты вроде 1sqlite читают базу без ошибок?
Рассмотрим несколько способов устранения сдвига колонок при использовании VFPOLEDB.
1SBLOB.DBF. Это полностью устранит "сдвиг" полей для любых внешних OLE DB провайдеров.Посмотрим на практический пример поиска без использования прямых запросов. Если в базе хранится совмещенный реквизит "ИНН\КПП", поиск обычным методом НайтиПоРеквизиту может не дать результата при вводе только ИНН. Разберем функцию для классического перебора справочника с отсечением КПП:
Функция НайтиКонтрагентаПоИННбезКПП(ИННКПП) Экспорт
ИНН = ВыделитьИНН(ИННКПП); // Ваша функция выделения ИНН из строки
Спр = СоздатьОбъект("Справочник.ЮрЛица");
ТЗ = СоздатьОбъект("ТаблицаЗначений");
ТЗ.НоваяКолонка("КодКонтрагента");
ТЗ.НоваяКолонка("ЮЛ", "Справочник.ЮрЛица");
ТЗ.НоваяКолонка("Контрагент", "Справочник.Контрагенты");
Спр.ВыбратьЭлементы(0);
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Если Спр.ЭтоГруппа() = 1 Тогда
Продолжить;
КонецЕсли;
Если СокрЛП(Спр.ИНН) = "" Тогда
Продолжить;
КонецЕсли;
ТекИНН = ВыделитьИНН(СокрЛП(Спр.ИНН));
Если ТекИНН = ИНН Тогда
ТЗ.НоваяСтрока();
ТЗ.КодКонтрагента = СокрЛП(Спр.Владелец.Код);
ТЗ.ЮЛ = Спр.ТекущийЭлемент();
ТЗ.Контрагент = Спр.Владелец;
КонецЕсли;
КонецЦикла;
Если ТЗ.КоличествоСтрок() = 0 Тогда
Возврат 0; // Ничего не нашли
КонецЕсли;
ТЗ.Сортировать("КодКонтрагента");
Возврат ТЗ.ПолучитьЗначение(1, 3); // Возвращаем первого найденного
КонецФункции
Такой подход может быть полезен, если база небольшая, и вы не хотите внедрять внешние компоненты или связываться с особенностями OLE DB. Однако при миллионных объемах данных использование прямых запросов (к SQLite или SQL-версии) с грамотной архитектурой таблиц (без полей > 254) останется наиболее оптимальным решением.