При попытке заглянуть «под капот» информационной базы 1С через SQL Server Management Studio (SSMS) многие разработчики сталкиваются с тем, что вместо привычных имен контрагентов, названий товаров или дат они видят странные наборы символов типа 0x80... или binary(16). В этой статье мы подробно разберем, почему платформа 1С хранит данные именно так, как сопоставить программные объекты с таблицами SQL и как написать запрос, который вернет человекочитаемую информацию.
Проанализируем архитектуру хранения данных 1С. Платформа 1С:Предприятие является объектно-ориентированной средой, а SQL Server — реляционной базой данных. Чтобы связать эти два мира, 1С использует собственную логику представления объектов. Самый важный элемент здесь — ссылка. Каждая запись в справочнике или документе имеет уникальный идентификатор (GUID). В SQL Server 1С хранит эти идентификаторы в полях с суффиксом RRef (например, _IDRRef, _Fld5812RRef) в формате binary(16).
Рассмотрим ситуацию: когда вы видите 0x80... в колонке «Грузоотправитель», вы видите не текст, а внутренний адрес объекта в базе данных. Для SQL Server это просто набор из 16 байт. Чтобы превратить этот набор в «ООО "Ромашка"», нам нужно «соединить» таблицу, где лежит ссылка, с таблицей, где лежит описание этого объекта.
Выясним причину, по которой невозможно сразу понять, что такое _Fld5812. 1С намеренно абстрагирует метаданные от физических таблиц. Чтобы найти «человеческое» название таблицы, не нужно гадать. Разберем основные способы получения структуры:
ПолучитьСтруктуруХраненияБазыДанных(). Она вернет таблицу, где указано, какому справочнику соответствует конкретная таблица SQL (например, _Reference80).Важно помнить: поле с суффиксом Ref всегда содержит ссылку на другую таблицу (справочник, документ, перечисление), а поле с суффиксом Description в таблицах справочников содержит наименование.
Рассмотрим пример запроса. Допустим, у нас есть таблица документов _Document150, в которой есть поле _Fld5812RRef (Грузоотправитель). Нам нужно получить наименование этого грузоотправителя из справочника _Reference80 (Контрагенты). Проанализируем логику соединения:
SELECT
Doc._Date_Time AS [Дата],
Doc._Number AS [Номер],
Contr._Description AS [НаименованиеГрузоотправителя]
FROM
_Document150 AS Doc
LEFT JOIN
_Reference80 AS Contr ON Doc._Fld5812RRef = Contr._IDRRef
WHERE
Doc._Marked = 0x00 -- Выбираем только не помеченные на удаление
В этом примере мы соединяем таблицу документа с таблицей справочника по бинарному ключу. Обратите внимание на _IDRRef — это первичный ключ в любой таблице справочника 1С.
Если вы посмотрите на поля типа datetime, вы можете увидеть даты типа «4023 год». Это не ошибка. Разберем, зачем это сделано: 1С добавляет к каждой дате 2000 лет. Это позволяет избежать проблем с минимальной датой в SQL Server (1753 год) при работе с пустыми датами 1С (0001 год).
Чтобы получить нормальную дату в SQL-запросе, используем функцию DATEADD. Посмотрим на пример:
SELECT
DATEADD(YEAR, -2000, _Date_Time) AS [РеальнаяДата]
FROM
_Document150
Проанализируем ситуацию с простыми типами данных. Булевы значения (Истина/Ложь) в 1С хранятся как binary(1). 0x01 — это Истина, 0x00 — Ложь.
С перечислениями (Enums) ситуация сложнее. Их текстовые представления (имена) не хранятся в SQL. В базе есть только таблицы типа _EnumX, где хранятся ссылки. Чтобы получить текст перечисления («Оплачено», «Не оплачено»), вам придется либо жестко прописывать их в CASE внутри SQL-запроса, основываясь на порядке в конфигураторе, либо использовать метаданные 1С.
Работа с SQL 1С напрямую — это большая ответственность. Выясним основные риски:
WITH (NOLOCK).INSERT, UPDATE или DELETE напрямую в SQL. 1С хранит итоги (остатки) в отдельных таблицах. Если вы измените количество товара в таблице записей, но не обновите таблицу итогов, вы получите «битую» базу.Соберем всё воедино и разберем сложный запрос, который выводит дату, номер и наименование контрагента с учетом всех особенностей:
SELECT
DATEADD(YEAR, -2000, T1._Date_Time) AS [ДатаДокумента],
T1._Number AS [Номер],
T2._Description AS [Контрагент]
FROM
_Document150 T1 WITH (NOLOCK)
LEFT JOIN
_Reference80 T2 WITH (NOLOCK) ON T1._Fld5812RRef = T2._IDRRef
WHERE
T1._Date_Time > '4023-01-01' -- Фильтр по 2023 году
ORDER BY
T1._Date_Time DESC
Резюмируем: Чтобы данные не выглядели как 0x80, нужно понимать структуру связей (RRef), использовать смещение дат (-2000 лет) и обязательно выполнять соединения таблиц через LEFT JOIN. Однако помните, что самый безопасный и правильный способ работы с данными 1С — это использование встроенного языка запросов 1С, который сам выполнит все эти преобразования за вас.