Power BI и 1С: три способа интеграции и живой отчёт о продажах

Интеграция Power BI и 1С — это способ превратить таблицы из вашей учётной базы в интерактивный визуальный отчёт: с отборами по годам, менеджерам, городам и номенклатуре, который открывается даже с телефона. В этой статье я разберу, как подключить 1С к Power BI тремя разными способами — напрямую через OData, через выгрузку во внешний MS SQL и через облачный Azure SQL — покажу реальный код обработки и модуля 1С, скрипты создания таблиц и M-запросы Power BI, а в конце объясню, какой способ выбрать под вашу задачу.

Что вы узнаете

  • Чем интеграция 1С с Power BI полезна руководителю и аналитику и что в итоге получается на экране
  • Как опубликовать стандартный интерфейс OData из 1С и вытащить данные прямо в Power BI
  • Как выгружать данные из 1С в MS SQL через внешние источники данных — объектной моделью и хранимой процедурой
  • Как поднять облачный Azure SQL и залить туда документы вместе с табличной частью
  • Как настроить связи таблиц и собрать интерактивный отчёт «Анализ продаж»
  • Какой из трёх способов выбрать под лицензии, безопасность и облако

Зачем связывать 1С и Power BI

Привет, на связи Илья Низамов. Ситуация, знакомая почти всем, кто ведёт учёт в 1С: у руководителя есть цифры, но они лежат в отчётах-таблицах. Чтобы понять, какой менеджер работает хорошо, какое подразделение убыточно и в каком городе проседают продажи, нужно сидеть и глазами разбирать колонки чисел. Таблицы — это хорошо и точно, но плохо считывается картина в целом.

Power BI решает ровно эту боль: он берёт данные из 1С и показывает их визуально — круговые диаграммы по менеджерам, продажи на карте городов, срезы по годам и месяцам, отбор по конкретному контрагенту или номенклатуре. Всё интерактивно: двигаешь срез — графики пересчитываются. И это работает не только на десктопе, но и в мобильном приложении Power BI: поставил руководителю на телефон, опубликовал отчёт — он заходит и смотрит онлайн-цифры без всякого мобильного клиента 1С.

Ниже — тот самый отчёт в миниатюре. Подвигайте срезы по году и менеджеру: продажи по городам пересчитаются вживую, ровно как в настоящем Power BI поверх данных 1С.

Сразу видно, что Москва тянет основной объём, а одно из подразделений в европейском городе — заведомо убыточное. Такой отчёт руководителю читать в разы приятнее, чем простыню в таблице.

Три способа интеграции: что выбрать

Данные в Power BI из 1С можно получить по-разному, и выбор способа зависит от ваших ограничений. Я в курсе показываю три, и они закрывают почти все реальные ситуации:

  1. OData напрямую. Публикуем стандартный интерфейс OData на веб-сервере и Power BI читает базу 1С по HTTP. Ноль дополнительного кода, но каждый отчёт держит открытым сеанс 1С и требует опубликованной базы.
  2. Выгрузка в локальный MS SQL. Через внешние источники данных 1С пишет консолидированные данные в отдельную базу MS SQL, а Power BI берёт их оттуда. Способ экономит лицензии 1С и снимает нагрузку с рабочей базы.
  3. Облачный Azure SQL. Тот же механизм выгрузки, но приёмник — облачная база Azure SQL. Отчёт доступен откуда угодно, свой сервер поднимать не нужно, базу 1С наружу публиковать не надо.

Чтобы не гадать, отметьте ограничения вашей задачи — виджет подскажет, с какого способа начать.

Дальше пройдём по всем трём по порядку — с публикацией, кодом и сборкой отчёта.

Готовим рабочее место и демобазу

Для примеров я собрал демобазу на основе типовых справочников: организации, контрагенты, договоры, подразделения, номенклатура, менеджеры и документ «Реализация товаров и услуг». Продажи мы будем строить именно по этому документу — у него есть шапка с реквизитами-срезами и табличная часть с номенклатурой, количеством и ценами.

Чтобы не заполнять базу вручную, в демобазе есть общая команда «Сформировать демоданные» и общий модуль, который наполняет базу случайными документами. Логика простая: собираем в массивы ссылки на заполненные справочники, а потом в цикле создаём сто документов со случайными комбинациями и разнесённой по времени датой — чтобы потом было что фильтровать по месяцам и годам.

Процедура СформироватьДемоДанные() Экспорт

	СписокОрганизаций = ПолучитьСписокОрганизаций();
	КоличествоОрганизаций = СписокОрганизаций.Количество() - 1;

	СписокКонтрагентов = ПолучитьСписокКонтрагентов();
	КоличествоКонтрагентов = СписокКонтрагентов.Количество() - 1;

	СписокМенеджеров = ПолучитьСписокМенеджеров();
	КоличествоМенеджеров = СписокМенеджеров.Количество() - 1;

	СписокНоменклатуры = ПолучитьСписокНоменклатуры();
	КоличествоНоменклатуры = СписокНоменклатуры.Количество() - 1;

	НачальнаяДатаДокументов = НачалоМесяца(ТекущаяДата());
	Для Счетчик = 1 По 100 Цикл
		ДанныеЗаполнения = Новый Структура;
		ДанныеЗаполнения.Вставить("Организация", ПолучитьСлучайнуюОрганизация(СписокОрганизаций, КоличествоОрганизаций));
		ДанныеЗаполнения.Вставить("Контрагент", ПолучитьСлучайногоКонтрагента(СписокКонтрагентов, КоличествоКонтрагентов));
		ДанныеЗаполнения.Вставить("Менеджер", ПолучитьСлучайногоМенеджера(СписокМенеджеров, КоличествоМенеджеров));
		ДанныеЗаполнения.Вставить("Товары", СформироватьТаблицуТовары(СписокНоменклатуры, КоличествоНоменклатуры));
		ДанныеЗаполнения.Вставить("СуммаДокумента", ДанныеЗаполнения.Товары.Итог("Сумма"));

		НовДок = Документы.РеализацияТоваровИУслуг.СоздатьДокумент();
		НовДок.Дата = НачальнаяДатаДокументов;
		НовДок.УстановитьНовыйНомер();
		ЗаполнитьЗначенияСвойств(НовДок, ДанныеЗаполнения);
		Для Каждого Строка Из ДанныеЗаполнения.Товары Цикл
			НовСтр = НовДок.Товары.Добавить();
			ЗаполнитьЗначенияСвойств(НовСтр, Строка);
		КонецЦикла;
		НовДок.Записать();

		НачальнаяДатаДокументов = НачальнаяДатаДокументов + 3600 * 24 * 14;
	КонецЦикла;

КонецПроцедуры

Обратите внимание на пару подходов, которые я использую здесь. Во-первых, ЗаполнитьЗначенияСвойств — он копирует одноимённые поля из структуры в объект и из строки таблицы в строку документа, так что не нужно вручную присваивать каждый реквизит. Во-вторых, дата каждого следующего документа сдвигается на две недели вперёд — так сто документов растягиваются на пару лет, и потом в отчёте есть что резать по годам и месяцам.

Отдельная деталь — свой генератор случайного числа. В серверном контексте 1С нет привычного Randomize, поэтому я получаю случайность из GUID: беру Новый УникальныйИдентификатор, оставляю только цифры и перевожу шестнадцатеричную строку в дробное число от 0 до 1, а затем масштабирую в нужный диапазон. Приём неочевидный, но надёжный и не требует внешних зависимостей.

Способ 1. OData: Power BI читает базу 1С напрямую

Самый быстрый способ — стандартный интерфейс OData. Начиная с версии 8.3.5 платформа умеет отдавать данные по протоколу OData без единой строчки кода: нужно только опубликовать базу на веб-сервере и указать, какие объекты выставить наружу.

В демобазе для этого есть специальная обработка «Редактирование состава стандартного интерфейса OData»: в ней один раз отмечаем справочники и документы, которые хотим отдавать, и сохраняем. Если публикуете регистры — там же можно добавить и их. Дальше идём в «Администрирование → Публикация на веб-сервере» и публикуем интерфейс OData на локальном Apache (если не умеете настраивать веб-сервер — у меня есть отдельный урок по публикации базы 1С на Apache, ссылку оставлю в перелинковке).

После публикации по адресу вида http://localhost/powerbi/odata/standard.odata/ открывается XML со списком всех выставленных сущностей. Каждому справочнику и документу соответствует своя лента. Именно эти адреса мы и будем добавлять в Power BI.

Чтобы не собирать адрес ленты руками и не ошибиться в префиксе (Catalog_ для справочника, Document_ для документа, а табличная часть документа — отдельная лента с суффиксом), я сделал конструктор. Заполните поля объекта — получите готовый URL и M-запрос для Power BI.

Дальше в Power BI жмём «Получить данные → Другое → Канал OData», вставляем адрес и подключаемся. Под капотом Power BI формирует запрос на языке M. Вот как выглядит реальный запрос к справочнику организаций из моего отчёта:

shared Организации = let
    Источник = OData.Feed("http://localhost/powerbi/odata/standard.odata/Catalog_Организации", null, [Implementation="2.0"])
in
    Источник;

Одна тонкость: поля в OData приходят с типовыми английскими именами. Наименование справочника лежит в поле Description. Чтобы в отчёте оно читалось по-человечески, я сразу переименовываю колонку — тоже средствами M:

shared Контрагенты = let
    Источник = OData.Feed("http://localhost/powerbi/odata/standard.odata/Catalog_Контрагенты", null, [Implementation="2.0"]),
    Переименовано = Table.RenameColumns(Источник,{{"Description", "Контрагент"}})
in
    Переименовано;

Так добавляем все нужные ленты: организации, контрагенты, подразделения, номенклатуру, договоры, менеджеров и сам документ реализации. Важный момент — документ реализации состоит из двух лент: шапка (Document_РеализацияТоваровУслуг) и табличная часть (Document_РеализацияТоваровУслуг_Товары). Их Power BI тянет отдельно, и связывать их придётся вручную.

После загрузки переходим в «Модель данных». Здесь для программиста 1С кроется главный порог входа: в 1С связи между справочниками и документами платформа прячет от нас, а в Power BI (как и в любой реляционной СУБД) их надо настроить руками. Связи идут через ссылки: у каждой ленты есть поле Ref_Key — это, по сути, наша ссылка из 1С. Берём ссылку организации и связываем её с полем Организация_Key в документе реализации, тип связи — один ко многим (одна организация встречается во многих документах). Так же связываем контрагентов, менеджеров, номенклатуру, а табличную часть — с шапкой документа через Ref_Key.

Если вы никогда не работали с реляционными базами, стоит почитать теорию про связи «один к одному», «один ко многим» и «многие ко многим» — без этого модель данных будет казаться магией. На деле 1С делает ровно то же самое, просто автоматически.

Собираем отчёт «Анализ продаж»

Когда таблицы связаны, начинается самое приятное — визуализация. Логика везде одинаковая: кидаем на холст визуальный элемент, в него — измерение (менеджер, город, номенклатура) и меру (сумму документа). Пара приёмов, которые делают отчёт живым:

  • Круговая диаграмма по менеджерам. Измерение — наименование менеджера, значение — сумма документа. В настройках диаграммы включаем метки, чтобы прямо на секторах были видны и сумма, и процент от общего дохода. Сразу понятно, кто из менеджеров тянет выручку, а кто отстаёт.
  • Срезы по годам и месяцам. Power BI автоматически распознаёт поле даты документа и позволяет сделать срез. Ставим срез по годам сверху, по месяцам — снизу, включаем в настройках среза режим «между / список», чтобы можно было выбирать диапазон или отдельные месяцы.
  • Продажи на карте. Берём поле города (у меня это сегмент), тип визуализации — карта. В «Размер» кладём сумму — и на карте пузырями видно, где продаж больше. Москва — крупный пузырь, убыточный европейский город — крошечный.
  • Формат чисел. Мелочь, но важная: у суммы документа по умолчанию стоит общий формат. Включаем «десятичное число» и отображение в тысячах — отчёт сразу выглядит опрятнее.

Отдельно стоит опубликовать отчёт в облачный сервис Power BI, чтобы он открывался с телефона. При первой публикации сервис попросит зарегистрироваться — здесь нюанс: для России регистрация сейчас закрыта, при регистрации нужно указать другую страну. После публикации не забудьте собрать макет для мобильного устройства: в Power BI есть отдельный режим «Макет телефона», куда перетаскиваются те же визуализации, но компонуются под вертикальный экран.

Полный разбор с публикацией, мобильным макетом и всеми настройками визуализаций — в видео ниже.

Способ 2. Выгрузка в MS SQL через внешние источники данных

OData хорош скоростью старта, но у него два минуса: базу 1С надо публиковать в сеть, и каждый отчёт занимает сеанс 1С. Не всем это подходит — кто-то не может опубликовать базу наружу, кому-то жалко лицензии. Решение — выгружать данные из 1С в отдельную базу MS SQL, а Power BI цеплять уже к ней. Плюс мы получаем консолидированное хранилище, в котором можно копить историю.

Работать с внешней СУБД из 1С позволяет механизм внешних источников данных. Сначала на стороне SQL Server создаём базу и таблицы. Я предпочитаю делать это скриптом — так нагляднее и вам будет проще повторить:

CREATE DATABASE powerbi;
GO
USE powerbi;
GO

-- Сводная таблица продаж (шапка документа)
CREATE TABLE dbo.Sales
   (_IDRRef nchar(36) PRIMARY KEY NOT NULL,
    _Date_Time datetime2 NOT NULL,
    Organization nvarchar(150) NULL,
    Unit nvarchar(150) NULL,
    Partner nvarchar(150) NULL,
    Contract nvarchar(150) NULL,
    Manager nvarchar(150) NULL,
    PriceAll numeric(15,2) NULL)
GO

-- Табличная часть документа
CREATE TABLE dbo.SalesRow
   (_IDRRef nchar(36) NOT NULL,
    Nomenclature nvarchar(150) NULL,
    Number numeric(10) NULL,
    Price numeric(15,2) NULL,
    Amount numeric(15,2) NULL)
GO

Ключевой момент — поле _IDRRef типа nchar(36). Это уникальный идентификатор документа из 1С, приведённый к строке из 36 символов. По нему мы связываем запись в SQL с документом в 1С: если документ перезаписали — в SQL находим ту же строку по _IDRRef и обновляем, а не плодим дубли.

Параметры подключения к SQL я храню в константах базы (сервер, логин, пароль, имя базы, строка соединения) и заполняю их через форму констант. Само подключение к внешнему источнику делаю программно в общем модуле PowerBIСервер:

Функция ПодключитьсяКMSSQL() Экспорт

	ПараметрыСоединения = ВнешниеИсточникиДанных.SQLEXPRESS.ПолучитьОбщиеПараметрыСоединения();
	ПараметрыСоединения.ИмяПользователя = Константы.Логин.Получить();
	ПараметрыСоединения.Пароль = Константы.Пароль.Получить();
	ПараметрыСоединения.СтрокаСоединения = Константы.СтрокаСоединения.Получить();
	ПараметрыСоединения.СУБД = "MSSQLServer";

	Попытка
		ВнешниеИсточникиДанных.SQLEXPRESS.УстановитьОбщиеПараметрыСоединения(ПараметрыСоединения);
		ВнешниеИсточникиДанных.SQLEXPRESS.УстановитьСоединение();
	Исключение
		ОбщегоНазначения.СообщениеПользователю("Ошибка подключения к MS SQL" + Символы.ПС + ОписаниеОшибки());
		Возврат Ложь;
	КонецПопытки;

	Возврат Истина;
КонецФункции

Здесь важно обязательно указать СУБД = "MSSQLServer" в параметрах соединения. Если этого не сделать, вы сможете только читать данные из внешнего источника, а записывать через объектную модель — нет.

Дальше — сама выгрузка. Я сделал два варианта записи, и это осознанный подход: показать разницу между объектной моделью и хранимой процедурой.

Вариант первый — объектная модель. Для программиста 1С он самый привычный: работа с внешней таблицей ничем не отличается от работы со справочником или документом. Пытаемся получить ссылку по идентификатору; если запись есть — берём объект и обновляем, если нет — создаём новый:

Функция ВыгрузитьДокументВMSSQL(СсылкаНаДокумент) Экспорт

	УникальныйИдентификатор = Строка(СсылкаНаДокумент.УникальныйИдентификатор());

	СсылкаНаОбъект = ВнешниеИсточникиДанных.SQLEXPRESS.Таблицы.dbo_Sales.ПолучитьСсылку(УникальныйИдентификатор);
	Если ЗначениеЗаполнено(СсылкаНаОбъект._IDRRef) Тогда
		ДокументSQL = СсылкаНаОбъект.ПолучитьОбъект();
	Иначе
		ДокументSQL = ВнешниеИсточникиДанных.SQLEXPRESS.Таблицы.dbo_Sales.СоздатьОбъект();
		ДокументSQL._IDRRef = УникальныйИдентификатор;
	КонецЕсли;

	ДокументSQL._Date_Time  = СсылкаНаДокумент.Дата;
	ДокументSQL.Organization = Строка(СсылкаНаДокумент.Организация);
	ДокументSQL.Partner      = Строка(СсылкаНаДокумент.Контрагент);
	ДокументSQL.Manager      = Строка(СсылкаНаДокумент.Менеджер);
	ДокументSQL.Unit         = Строка(СсылкаНаДокумент.Подразделение);
	ДокументSQL.PriceAll     = СсылкаНаДокумент.СуммаДокумента;
	ДокументSQL.Записать();

КонецФункции

Вариант второй — хранимая процедура. Здесь вся логика «найти и обновить или добавить» уезжает на сторону SQL Server, а 1С только передаёт параметры. Со стороны 1С код становится совсем коротким:

Функция ВыгрузитьДокументВMSSQL_ХранимаяПроцедура(СсылкаНаДокумент) Экспорт

	УникальныйИдентификатор = Строка(СсылкаНаДокумент.УникальныйИдентификатор());
	Попытка
		ВнешниеИсточникиДанных.SQLEXPRESS.dbo_AddDoc(
			УникальныйИдентификатор,
			СсылкаНаДокумент.Дата,
			Строка(СсылкаНаДокумент.Организация),
			Строка(СсылкаНаДокумент.Подразделение),
			Строка(СсылкаНаДокумент.Контрагент),
			Строка(СсылкаНаДокумент.Договор),
			Строка(СсылкаНаДокумент.Менеджер),
			СсылкаНаДокумент.СуммаДокумента);
	Исключение
		ОбщегоНазначения.СообщениеПользователю(ОписаниеОшибки());
	КонецПопытки;

КонецФункции

А вот сама хранимая процедура на T-SQL. Логика «обнови, если есть, иначе вставь» — классический upsert:

CREATE PROCEDURE dbo.AddDoc
   (
        @_IDRRef nchar(36),
        @_Date_Time datetime2,
        @Organization nvarchar(150),
        @Unit nvarchar(150),
        @Partner nvarchar(150),
        @Contract nvarchar(150),
        @Manager nvarchar(150),
        @PriceAll numeric(15,2)
   )
 AS
 BEGIN
	IF(EXISTS (SELECT Sales._IDRRef FROM Sales WHERE _IDRRef = @_IDRRef))
        BEGIN
            UPDATE Sales
            SET _Date_Time = @_Date_Time, Organization = @Organization, Unit = @Unit,
                Partner = @Partner, Contract = @Contract, Manager = @Manager, PriceAll = @PriceAll
            WHERE _IDRRef = @_IDRRef
        END
    ELSE
        BEGIN
            INSERT INTO Sales(_IDRRef, _Date_Time, Organization, Unit, Partner, Contract, Manager, PriceAll)
                VALUES (@_IDRRef, @_Date_Time, @Organization, @Unit, @Partner, @Contract, @Manager, @PriceAll)
        END
END
GO

Какой вариант лучше? Объектная модель нагляднее и проще в отладке, хранимая процедура — быстрее на больших объёмах и переносит логику на сервер БД. В учебной базе разница незаметна, на проде — выбирайте по нагрузке.

Массовую выгрузку я вешаю на общую команду, которая обходит все документы запросом и по каждому дёргает выгрузку. Именно такую команду потом можно поставить на регламентное задание — и данные в SQL, а значит и в Power BI, будут обновляться по расписанию сами. Это и есть главный смысл способа: одно регламентное задание вместо постоянно открытого сеанса 1С.

Процедура ВыгрузитьДокументыВMSSQL() Экспорт

	Если НЕ ПараметрыПодключенияЗаполнены() Тогда
		Возврат;
	КонецЕсли;
	Если ПодключитьсяКMSSQL() = Ложь Тогда
		Возврат;
	КонецЕсли;

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	РеализацияТоваровИУслуг.Ссылка КАК Ссылка
	|ИЗ
	|	Документ.РеализацияТоваровИУслуг КАК РеализацияТоваровИУслуг";

	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		ВыгрузитьДокументВMSSQL(Выборка.Ссылка);
	КонецЦикла;

КонецПроцедуры

В Power BI подключение к своей базе SQL даже проще, чем к OData: «Получить данные → База данных SQL Server», указываем сервер и базу, выбираем таблицу Sales — и данные уже готовы к визуализации, без ручной настройки связей (у сводной таблицы они не нужны).

Способ 3. Облачный Azure SQL

Третий способ — та же выгрузка через внешние источники, но приёмник вынесен в облако Microsoft Azure. Плюсы: не нужен свой сервер, отчёт доступен откуда угодно, а базу 1С не приходится публиковать наружу. При регистрации Azure даёт бесплатный лимит на пробный период — этого достаточно, чтобы всё попробовать.

Порядок такой: в консоли Azure создаём SQL-сервер (задаём короткое имя, логин и обязательно сложный пароль), затем базу данных. После создания важно не забыть про два шага, на которых обычно спотыкаются:

  1. Файрвол. По умолчанию Azure не пускает никого. Нужно в настройках сервера добавить свой IP-адрес клиента — иначе даже через Management Studio не подключиться.
  2. Драйвер ODBC. Для подключения из 1С через внешний источник нужен ODBC Driver для SQL Server. Скачиваем актуальную версию (у меня 17-я) — и внимание: в строке подключения Azure по умолчанию подставляет версию 13, её нужно вручную исправить на установленную.

Таблицы создаём тем же скриптом, что и для локального MS SQL. А вот выгрузка табличной части здесь отличается — и это самый интересный код во всём курсе. Дело в том, что в табличной части документа одна и та же номенклатура может встречаться в нескольких строках, а нам в аналитике нужны сгруппированные данные. Поэтому перед записью я группирую строки запросом, а потом переписываю набор записей:

// Записываем табличную часть в Azure SQL: сначала группируем, потом перезаписываем набор
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	РеализацияТоваровИУслугТовары.Номенклатура КАК Номенклатура,
|	СУММА(РеализацияТоваровИУслугТовары.Количество) КАК Количество,
|	МАКСИМУМ(РеализацияТоваровИУслугТовары.Цена) КАК Цена,
|	СУММА(РеализацияТоваровИУслугТовары.Сумма) КАК Сумма
|ИЗ
|	Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
|ГДЕ
|	РеализацияТоваровИУслугТовары.Ссылка = &Ссылка
|СГРУППИРОВАТЬ ПО
|	РеализацияТоваровИУслугТовары.Номенклатура,
|	РеализацияТоваровИУслугТовары.Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
РезультатЗапроса = Запрос.Выполнить();

// Чистим старые строки этого документа: отбор по идентификатору + запись пустого набора
НаборЗаписей = ВнешниеИсточникиДанных.SQLAZURE.Таблицы.dbo_SalesRow.СоздатьНаборЗаписей();
НаборЗаписей.Отбор._IDRRef.Установить(УникальныйИдентификатор);
НаборЗаписей.Записать();

// Пишем сгруппированные строки менеджером записи
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
	НоваяЗапись = ВнешниеИсточникиДанных.SQLAZURE.Таблицы.dbo_SalesRow.СоздатьМенеджерЗаписи();
	НоваяЗапись._IDRRef      = УникальныйИдентификатор;
	НоваяЗапись.Nomenclature = Строка(Выборка.Номенклатура);
	НоваяЗапись.Number       = Выборка.Количество;
	НоваяЗапись.Price        = Выборка.Цена;
	НоваяЗапись.Amount       = Выборка.Сумма;
	НоваяЗапись.Записать();
КонецЦикла;

Здесь табличная часть работает как регистр сведений: у неё есть измерения (_IDRRef и номенклатура), по которым мы сначала очищаем старые записи документа, а потом добавляем новые. Честно скажу: запрос выполняется для каждого документа в цикле, и это не самый оптимальный подход — на большом объёме я бы группировал сразу все документы одним запросом. Но для понимания учебной задачи так нагляднее, и это осознанный компромисс.

Подключение Azure к Power BI: «Получить данные → в поиске Azure → База данных SQL Azure», указываем имя облачного сервера и базу, вводим учётные данные. Тут приятный бонус — Power BI при загрузке сам определяет связь «один ко многим» между шапкой и табличной частью, так что модель почти не приходится настраивать вручную.

Так какой способ выбрать

Если свести три способа в одну картину:

  • OData — когда нужен результат сегодня и нет своего SQL-сервера. Минус: сеанс 1С на каждый отчёт и публикация базы в сеть.
  • Локальный MS SQL — когда жалко лицензии и мощность рабочей базы, нужно копить историю и считать на стороне БД. Плюс регламентное задание вместо онлайна.
  • Azure SQL — когда отчёт нужен из любой точки без своего сервера и без публикации базы 1С наружу.

На практике эти способы не конкурируют, а дополняют друг друга: начать можно с OData, чтобы быстро показать руководителю ценность, а под нагрузку и историю — перейти на выгрузку в SQL. Механизм внешних источников данных при этом один и тот же, меняется только приёмник.

Если хотите системно разобраться в интеграции 1С с внешними системами — не только с Power BI, но и с SQL, веб-сервисами и сайтами — это большой отдельный курс. А ниже расскажу, куда идти дальше тем, кто уже наигрался с отчётами.

Похожие статьи

От отчётов к ИИ-агенту над данными 1С

Power BI отвечает на вопрос «что произошло»: показывает срезы, диаграммы, динамику. Но следующий логичный шаг для аналитика — не смотреть на готовые графики, а спрашивать данные на естественном языке: «покажи топ-5 убыточных подразделений за прошлый квартал» или «какие контрагенты снизили закупки». Это уже территория ИИ-агентов над данными 1С.

Технически это тот же путь, что мы прошли выше: агент получает доступ к данным 1С (через тот же OData или выгрузку в SQL), а поверх него работает языковая модель, которая переводит вопрос человека в запрос к данным и формулирует ответ. Именно этому — как построить ИИ-агента, который работает с вашей базой 1С через LangChain, RAG и MCP-серверы — посвящён мой флагманский курс «ИИ-агент для 1С: LangChain, RAG и MCP-серверы». Если вы уже умеете вытаскивать данные из 1С для аналитики, это ваш следующий уровень: превратить статичные отчёты в диалог с данными.

Все демобазы, скрипты и отчёты из этой статьи можно скачать в блоге, а если что-то не заработает — задавайте вопросы, разберём.

Частые вопросы