Работа с базой данных 1С напрямую через SQL-запросы — это задача, требующая предельной осторожности и глубокого понимания внутренней структуры хранения данных. Одной из типичных трудностей, с которыми сталкиваются разработчики, является вставка или обновление полей, содержащих значения перечислений. В этой статье мы подробно разберем, как формат хранения данных в 1С соотносится с типами данных MS SQL Server, и как правильно составить INSERT запрос, чтобы избежать ошибок приведения типов.
При попытке выполнить прямой запрос INSERT или UPDATE к таблице 1С (например, к регистру сведений), разработчики часто пытаются передать идентификатор значения перечисления в виде строки. Рассмотрим типичную ситуацию: у нас есть поле _Fld14559RRef, которое в SQL имеет тип binary(16). Если мы попытаемся передать в него значение как строку '0xbc6649eb0a03abb74f3bcabc7117e72a', SQL Server выдаст ошибку:
"Неявное преобразование из типа данных varchar в binary не разрешено. Для выполнения этого запроса используйте функцию CONVERT."
Это происходит потому, что SQL воспринимает данные в кавычках как текстовую строку, а не как последовательность байтов. Проанализируем, как решить эту задачу правильно.
Самое простое и эффективное решение — передать HEX-последовательность напрямую, используя префикс 0x. В языке T-SQL префикс 0x сообщает серверу, что следующие за ним символы являются шестнадцатеричным представлением двоичных данных.
Разберем пример правильного запроса:
INSERT INTO _InfoRg14479([_Fld14483], [_Fld14481], [_Fld14480], [_Fld14482], [_Fld14559RRef])
VALUES ('2021-05-07 17:01:21', '2', '233608', 'ААА', 0xBC6649EB0A03ABB74F3BCABC7117E72A)
Обратите внимание: значение 0xBC6649EB... указано без кавычек. Именно это позволяет SQL Server корректно интерпретировать данные как binary(16) без дополнительных функций преобразования.
Чтобы узнать, какой именно набор байтов соответствует конкретному значению перечисления в вашей базе, можно воспользоваться несколькими приемами.
1. Использование SQL Profiler
Мы можем запустить трассировку запросов в SQL Profiler и выполнить простой запрос на встроенном языке 1С:
Запрос = Новый Запрос("ВЫБРАТЬ ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Новый)");
Запрос.Выполнить();
В профайлере мы увидим системный вызов sp_executesql, в котором платформа передает значение в формате 0x.... Это самый надежный способ увидеть "глазами SQL", как выглядит значение метаданных.
2. Программное получение HEX-строки в 1С
Если нам нужно сформировать текст SQL-запроса динамически внутри кода 1С, мы можем воспользоваться методом ЗначениеВСтрокуВнутр(). Рассмотрим функцию, которая преобразует ссылку в формат, пригодный для SQL:
Функция ПолучитьХексДляСкуля(Ссылка) Экспорт
Если Ссылка.Пустая() Тогда
Возврат "0x00000000000000000000000000000000";
КонецЕсли;
// Получаем внутреннее строковое представление
ВнутрСтр = ЗначениеВСтрокуВнутр(Ссылка);
// Извлекаем GUID и формируем HEX-литерал
// Обычно GUID находится в конце внутренней строки
Результат = "0x" + Лев(Прав(ВнутрСтр, 33), 32);
Возврат Результат;
КонецФункции
Важно помнить, что 1С хранит GUID в формате со смещенными группами байтов (Byte Swapping). Если вы берете "чистый" GUID из внешних систем, его порядок байтов может отличаться от того, что ожидает 1С в поле _IDRRef.
Для более глубокого понимания ситуации выясним, как устроены таблицы перечислений в SQL. Каждое перечисление имеет свою таблицу вида _Enum<N>. В ней всегда присутствуют два ключевых поля:
_IDRRef — тот самый binary(16), который является ссылкой на значение._EnumOrder — порядок значения, установленный в конфигураторе.Если вы не знаете точный _IDRRef, вы можете найти его запросом к таблице перечисления, зная порядок (индекс) значения:
SELECT _IDRRef FROM _Enum123 WHERE _EnumOrder = 0 -- получим первое значение перечисления
Проанализируем критические риски, которые возникают при прямой вставке данных в обход объектной модели 1С:
INSERT напрямую в таблицы регистров через SQL, вы берете на себя ответственность за корректность всех связанных полей. 1С не сможет выполнить свои стандартные проверки (например, при подписках на события или в модулях набора записей).Для того чтобы успешно указать значение перечисления в SQL-запросе, придерживайтесь следующего алгоритма:
_IDRRef нужного значения (через профайлер или таблицу _Enum).CAST(0xBC66... AS binary(16)).Следуя этим правилам, вы обеспечите техническую корректность выполнения ваших запросов к СУБД.