Запрос 8 2

Как выгрузить результаты запроса в таблицу значений, 1С:Предприятие 8.0,8.1,8.2?
Самый простой способ выгрузки, это воспользоваться методом результата запроса Выгрузить().
Пример:

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

в строке:

ТЗО = Запрос.Выполнить().Выгрузить();

выполняется запрос, его метод Выполнить(), затем применяется метод результат запроса Выгрузить ().
ТЗО — таблица значений, содержащая информацию о товаре.
Такая запись кода называется краткой. Можно разбить ее на несколько частей строк. В каждой строке будем записывать один метод, один объект.

Результат = Запрос.Выполнить(); ТЗО = Результат.Выгрузить();

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

Режим записи документов в 1С
Иерархический справочник в запросе 1С Упорядочивание по иерархии
Ошибка установки соединения с базой данных 1С
Как узнать итог по определенному полю в движении документа в 1С?
Настройка 1С

SashaM

Метод .Выгрузить() выгружает в ТабличныйДокумент весь запрос ( с сервера на клиент перетаскивается весь результат запроса ), а .Выбрать() открывает типа курсора на сверере, на сколько я понимаю выполнив запрос ( данные остаются на сервере ). А вот метод .Следующий() возвращает результат по одной записи (это типа ADO Recordset).
Запрос.Выполнить.Пустой() Быстрее не думаю что он будет быстрее .Выбрать(), хотя и такое возможно реализовать.

Ага, видимо так и есть

Основной особенностью динамических выборок является то, что они не считывают данные целиком в память, а получают их блоками по мере обхода выборки методом Следующий(). Это позволяет обходить большие объемы данных, не опасаясь, что возникнут проблемы с использованием памяти компьютера.
Технологические особенности
Выборка всегда считывает данные в некоторой последовательности сортировки (в одном из допустимых порядков). Обход выборки заключается в получении очередных блоков записей в соответствии с порядком и выдачи записей считанных блоков. Очередной блок считывается как множество записей, следующих в выбранном порядке после последней полученной записи предыдущего блока.
Для обеспечения эффективной работы динамической выборки задание отбора и сортировки ограничены так, чтобы при обходе выборки мог быть использован один из индексов.
В процессе обхода динамической выборки система считывает данные блоками по 25 записей. Для объектных данных (Справочников, Документов и т.д.) каждая запись является объектом, включающим все ее табличные части.
При обращении к свойствам выборки выдаются уже считанные данные. Кроме того, при получении из выборки объекта также не происходит его повторного считывания, а используются уже считанные выборкой данные.
Следует учитывать, что фактическое считывание очередного блока происходит после того, как получены (методом Следующий()) все записи считанного ранее блока. Таким образом, разработчик конфигурации не имеет контроля над актуальностью считываемой информации, даже если выборка инициирована в транзакции. При получении очередной записи нельзя различить ситуацию, когда она будет физически считана в этот момент или получена из ранее считанного блока. Очевидно, что последних ситуаций будет большинство.
Для иерархических данных (Справочников, Планов видов характеристик и Планов счетов) кроме обычной выборки, инициируемой методом Выбрать, существует иерархическая выборка, инициируемая методом ВыбратьИерархически. Она отличается тем, что выдает данные путем обхода записей по уровням. То есть после выдачи элемента выдается подчиненный ему элемент, если он существует. А если подчиненного не существует, то выдается следующий элемент. Каждое считывание подчиненных элементов реализовано как считывание нового блока.

Особенности использования
Следует учитывать, что если в процессе обхода выборки данные изменяются (в данной сессии, или другими сессиями), то могут возникать такие ситуации, как получение данных удаленного объекта, получение в выборке одного объекта два раза, не попадание некоторых записей в выборку и т.д.
Это объясняется описанными выше технологическими особенностями работы динамической выборки. Например, после считывания первого блока записей выполнено изменение одного из объектов и в результате значения полей по которым упорядочена выборка изменились. Тогда эта запись может попасть в выборку повторно, если в результате изменения она стала в порядке следования позже, чем была раньше. Если в процессе выборки выполняемой одной сессией в другой сессии объект изменился и в результате изменений в порядке выборки он стал раньше, чем был до изменения, то при определенном совпадении по времени этих процессов, объект вообще не попадет в выборку. Например, пока выборка обходила товары на букву «А», товар «Бета» переименовали в «Альфа». В этом случае, он может не «успеть» попасть в часть выборки на букву «Б» и «опоздать» попасть в часть выборки на букву «А».
При использовании динамических выборок для обхода и удаления иерархических данных следует учитывать тот факт, что при удалении элемента удаляются и все его подчиненные элементы. Соответственно при использовании прямой (неиерархической) выборки в процессе удаления объекта, могут удалиться подчиненные объекты уже считанные в текущем блоке. Соответственно, при попытке выполнить какие-либо действия с
полученными из выборки объектами будет выдаваться ошибка, так как в базе данных объекты уже не существуют. При использовании иерархической выборки такой проблемы не возникает, так как в один блок входят только элементы подчиненные одному родителю.
Эти особенности требуют обдуманного подхода к задачам, решаемым с помощью динамических выборок. Можно рекомендовать применять выборки либо для задач, не требующих ответственного чтения множества записей, либо для регламентных задач, допускающих использование монопольного режима. В любых случаях следует внимательно относится к изменению объектов в процессе обхода динамической выборки, так как это может повлиять на порядок их включения в выборку.

ПОДОБНО — Оператор проверки строки на подобие шаблону. Аналог LIKE в SQL.
Оператор ПОДОБНО позволяет сравнить значение выражения, указанного слева от него, со строкой шаблона, указанной справа. Значение выражения должно иметь тип строка. Если значение выражения удовлетворяет шаблону – результатом оператора будет ИСТИНА, иначе – ЛОЖЬ.
Следующие символы в строке шаблона являются служебными и имеют смысл, отличный от символа строки:
• % (процент): последовательность, содержащая любое количество произвольных символов
• _ (подчеркивание): один произвольный символ
• (в квадратных скобках один или несколько символов): любой одиночный символ из перечисленных внутри квадратных скобок
В перечислении могут встречаться диапазоны, например a-z, означающие произвольный символ, входящий в диапазон, включая концы диапазона.
• (в квадратных скобках значок отрицания, за которым следует один или несколько символов): любой одиночный символ, кроме тех, которые перечислены следом за значком отрицания
Любой другой символ означает сам себя и не несет никакой дополнительной нагрузки.
Если в качестве самого себя необходимо записать один из перечисленных символов, то ему должен предшествовать <Спецсимвол>. Сам <Спецсимвол> (любой подходящий символ) определяется в этом же операторе после ключевого слова СПЕЦСИМВОЛ.
Например, шаблон «%АБВ\_абв%” СПЕЦСИМВОЛ «\” означает подстроку, состоящую из последовательности символов:
буквы А; буквы Б; буквы В; одной цифры; одной из букв а, б, в или г; символа подчеркивания; буквы а; буквы б; буквы в.
Причем перед этой последовательностью может располагаться произвольный набор символов.
Примеры использования:
Код 1C v 8.х Процедура БанкОкончаниеВводаТекста(Элемент, Текст, Значение, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
//Делаем запрос с поиском по шаблону вида «%» + <Текст введенный пользователм в поле ввода> + «%»
Запрос = Новый Запрос;
Запрос.УстановитьПараметр(«Наименование», «%» + Текст + «%»);
Запрос.Текст = «ВЫБРАТЬ
| Банки.Ссылка
|ИЗ
| Справочник.Банки КАК Банки
|
|ГДЕ
| Банки.Наименование ПОДОБНО &Наименование»;
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Результат.Пустой() Тогда
//Ничего не нашли. Здесь можно вывести сообщение, или еще чего сделать
Иначе
//Получаем результаты
тзРезультаты = Результат.Выгрузить();
//Подготовим список значений который будет содержать найденные элементы.
Значение = Новый СписокЗначений();
Значение.ЗагрузитьЗначения(тзРезультаты.ВыгрузитьКолонку(«Ссылка»));
КонецЕсли;
КонецПроцедуры
Нужно, что бы в «Договора по умолчанию» попадали только Наименования Основной договор и т.д:
Код 1C v 8.х Выбор
Когда Наименование ПОДОБНО «Договор №%» тогда «Договора с номером» //Подходит любая строка, начинающаяся с «Договор №»
Когда Наименование ПОДОБНО «Основной договор%%» тогда «Договора по умолчанию» //Подходит любая строка, начинающаяся с «Основной договор»
Иначе «Прочие»
Конец Как ВидДоговора

Внимание! Перед вами ознакомительная версия урока, материалы которого могут быть неполными.

Войдите как ученик, чтобы получить доступ к материалам школы

Язык запросов 1С 8.3 для начинающих программистов: упорядочивание

Автор уроков и преподаватель школы: Владимир Милькин

Упорядочивание в запросах

Давайте напишем запрос, который получает из таблицы Справочник.Еда код и название еды:

ВЫБРАТЬ Код, Наименование ИЗ Справочник.Еда

Как всегда, выполните этот запрос у себя на компьютере.

С большой долей вероятности у вас получится следующий результат:

Возможно вы удивитесь, но при таком написании запроса никто не гарантирует нам именно такого порядка выдачи записей в таблице. В случае использования клиент-серверного режима работы на различных СУБД результат мог бы быть и такой:

И такой:

И …, ну в общем вы поняли, что если мы не указываем порядок сортировки (упорядочивания) результата запроса, то этот самый порядок может быть абсолютно любым.

Секция УПОРЯДОЧИТЬ ПО

Поля по которым требуется упорядочить запрос перечисляются в секции УПОРЯДОЧИТЬ ПО через запятую:

Следом за именем поля упорядочивания может идти одно из двух ключевых слов:

  • ВОЗР — упорядочивание по возрастанию.
  • УБЫВ — упорядочивание по убыванию.

Если не указывать ни одно из этих слов, считается, что сортировка идёт по возрастанию.

Вооружившись знаниями, давайте упорядочим результат нашего запроса по убыванию поля Код:

ВЫБРАТЬ Код, Наименование ИЗ Справочник.Еда УПОРЯДОЧИТЬ ПО Код УБЫВ

По возрастанию поля Наименование (алфавитный порядок):

ВЫБРАТЬ Код, Наименование ИЗ Справочник.Еда УПОРЯДОЧИТЬ ПО Наименование ВОЗР

А теперь упорядочим следующую таблицу

так, чтобы сначала шла сортировка по полю Вкус по возрастанию, а затем (среди строчек с одинаковым значением поля Вкус) шла сортировка по полю Цвет по убыванию:

ВЫБРАТЬ Вкус, Цвет ИЗ Справочник.Еда УПОРЯДОЧИТЬ ПО Вкус.Наименование ВОЗР, Цвет.Наименование УБЫВ

Отдельно обращаю ваше внимание на то, что мы указали сортировку не по самим полям Вкус и Цвет, а по их строковому реквизиту Наименование. Вы читаете ознакомительную версию урока, полноценные уроки находятся .

Это связано с тем, что сортировка возможна лишь по полям имеющим один из типов: Строка, Число, Дата.

А поля Вкус и Цвет являются ссылками на элементы справочников Вкус и Цвет, сортировать по которым не имеет смысла (в этом случае сортировка будет вестись по внутреннему идентификатору ссылки). Зато можно сделать сортировку по одному из реквизитов этих элементов. Наиболее подходящим в нашем случае будет строковый реквизит Наименование.

Возможность автоупорядочивания

Ключевое слово АВТОУПОРЯДОЧИВАНИЕ позволяет включить режим автоматического формирования полей для упорядочивания результатов запроса.

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

Итак, поехали.

Прежде всего, ключевое слово АВТОУПОРЯДОЧИВАНИЕ может быть расположено в запросе сразу за или вместо секции УПОРЯДОЧИТЬ ПО:

Автоупорядочивание работает по следующим принципам:

Случай #1

Если в запросе:

  • есть секция УПОРЯДОЧИТЬ ПО

Тогда ссылка на каждую таблицу в этой секции будут заменена полями, по которым по умолчанию сортируется эта таблица.

Для таблиц справочников полями сортировки по умолчанию являются код и наименование, выбор из которых осуществляется в соответствии с настройками справочника в конфигураторе:

Для таблиц документов полем сортировки по умолчанию является дата документа.

Рассмотрим пример:

ВЫБРАТЬ Наименование ИЗ Справочник.Клиенты УПОРЯДОЧИТЬ ПО ЛюбимыйЦвет АВТОУПОРЯДОЧИВАНИЕ

Так как поле сортировки ЛюбимыйЦвет имеет тип Справочник.Цвета, в настройках которого основным представлением выбрано поле Наименование, то этот запрос эквивалентен:

ВЫБРАТЬ Наименование ИЗ Справочник.Клиенты УПОРЯДОЧИТЬ ПО ЛюбимыйЦвет.Наименование

Случай #2

Если в запросе:

  • отсутствует секция УПОРЯДОЧИТЬ ПО
  • но есть секция ИТОГИ ПО (её мы будем проходить позже)

В этом случае результат запроса будет упорядочен по полям итогов (в той же последовательности).

Если среди этих полей есть ссылки на таблицы, то они также будут заменены полями, по которым сортируются эти таблицы по умолчанию.

Случай #3

Если в запросе:

  • отсутствует секция УПОРЯДОЧИТЬ ПО
  • отсутствует секция ИТОГИ ПО
  • но есть секция СГРУППИРОВАТЬ ПО (группировку мы проходили )

В этом случае результат запроса будет упорядочен по полям группировки (в той же последовательности).

Если среди этих полей есть ссылки на таблицы, то они также будут заменены полями, по которым сортируются эти таблицы по умолчанию.

Рассмотрим пример:

ВЫБРАТЬ Город, СУММА(Количество) ИЗ Документ.ПрибытиеГостей СГРУППИРОВАТЬ ПО Город АВТОУПОРЯДОЧИВАНИЕ

Так как поле группировки Город имеет тип Справочник.Города, в настройках которого основным представлением выбрано поле Наименование, то этот запрос эквивалентен:

ВЫБРАТЬ Город, СУММА(Количество) ИЗ Документ.ПрибытиеГостей СГРУППИРОВАТЬ ПО Город УПОРЯДОЧИТЬ ПО Город.Наименование

Случай #4

Наконец, если в запросе:

  • отсутствует секция УПОРЯДОЧИТЬ ПО
  • отсутствует секция ИТОГИ ПО
  • отсутствует секция СГРУППИРОВАТЬ ПО

В этом случае результат запроса будет упорядочен по полям сортировки по умолчанию для таблиц, из которых выбираются данные, в порядке их появления в запросе.

Рассмотрим пример:

ВЫБРАТЬ Код, Наименование ИЗ Справочник.Еда АВТОУПОРЯДОЧИВАНИЕ

Так как данные выбираются из справочника Еда, в настройках которого основным представлением выбрано поле Наименование, то этот запрос будет эквивалентен:

ВЫБРАТЬ Код, Наименование ИЗ Справочник.Еда УПОРЯДОЧИТЬ ПО Наименование

Почему использование автоупорядочивания нежелательно

Автоупорядочивание подходит:

  • для универсальных запросов, когда разработчик не может предвидеть из каких таблиц будут запрашиваться данные
  • для случаев, когда получаемый порядок записей не важен, но при этом он должен быть одинаковым в независимости от применяемой СУБД

Во всех остальных случаях использовать возможность автоупорядочивания нежелательно, так как поля, которые являются полями сортировки сегодня, могут перестать быть такими завтра.

Например, сегодня мы можем написать код, чувствительный к тому, чтобы результаты запроса из справочника Еда были отсортированы по полю Наименование.

А завтра фирма «1С» (или другой разработчик) изменят настройки базы в конфигураторе так, что полем сортировки по умолчанию для справочника Еда станет, к примеру, поле Код. И, если мы использовали автоупорядочивание в запросе, то наш отчет сломается, ведь порядок сортировки уже будет другим. Вы читаете ознакомительную версию урока, полноценные уроки находятся .

Поэтому всегда старайтесь указывать конкретные поля и конкретный порядок сортировки по ним в секции УПОРЯДОЧИТЬ ПО, такой запрос уже не сломать просто так:

ВЫБРАТЬ Код, Наименование ИЗ Справочник.Еда УПОРЯДОЧИТЬ ПО Наименование ВОЗР

Пройдите тест

Начать тест

Решил написать статью о том, как вытягивать данные из 1С путем SQL запросов. Все нижесказанное касается 1С версии 8.2, оно также должно работать и в 1С версии 8.1. Особое внимание уделено проблеме с извлечением заголовков перечислений.

Культурный способ

В идеале выборку данных из 1С должен делать 1С-программист. Хорошо, если он создаст обработку, которая выдаст данные в так называемую «буферную базу»: csv файлы, таблицы в SQL – что угодно. Проектировщик ХД и ETL должен брать данные из буфера.
В этом случае все работает предельно хорошо: зоны ответственности разделены, если найдена ошибка в данных отчета – ее вначале ищут в кубе, если в кубе все ОК – ищут в ХД, если в ХД все ОК – ищут в ETL, если в ETL все хорошо – значит пускай 1С-программист сам разбирается где у него ошибка в обработке, заполняющей «буферную БД».
Но не всегда такой способ доступен. Бывает, что 1С-специалиста либо вообще нет, либо слишком занят, либо мощностей железа не хватает, чтобы «выталкивать» данные из 1С с помощью обработки. И остается одно – делать извлечение данных с помощью SQL запросов.

Не очень культурный способ

Вот это собственно и есть этот способ – «сделать SQL запрос на 1С-базу». Главная задача – корректно написать сами запросы. Я думаю, ни для кого не есть секретом, что в 1С структура данных «хитрая», и что поля и таблицы имеют замысловатые названия. Задача проектировщика ETL – вытянуть данные из этой структуры.

Просмотр метаданных

Существуют обработки, дающие возможность просмотреть то, какие поля справочников/документов в каких таблицах/полях базы данных находятся.
Вы можете скачать несколько таких обработок (которые мы «отфильтровали» путем перебора десяток подобных, выбрав наилучшие). Они делают почти одно и то же – позволяют посмотреть все поля, понять какое поле на какой справочник ведет, и даже предлагают автоматически построить запрос:

Таким образом, начинаем исследовать нужные нам документы:

Дальше открываем любой из них, и находим то, куда он записывается – в какие регистры:

Ну а дальше найти этот регистр и сгенерировать SQL запрос с помощью показанных выше обработок (как на первом рисунке) не составляет труда.
Мы делаем как правило два уровня SQL запросов: «нижний уровень» — вьюхи для переименования полей, «верхний уровень» – вьюхи, которые берут данные из нижнего уровня, и уже они делают необходимые джойны.

Перечисления

Есть одна большая проблема – это перечисления. Пример:

И теперь если попытаться вытянуть это поле из базы напрямую, то получим вот что:

Да, мы нашли где заголовки перечислений сидят: таблица называется Config, в ней – image поля, в которых сидит зазипованный набор байт, который если раззиповать – получим непонятной структуры набор символов, разделителей и т.д. К сожалению, этот формат данных не документирован.
Поэтому мы нашли другой способ. Мы сделали на C# небольшую программку, которая использует COM-объект 1С-ки для того, чтобы установить с ней соединение, и вытянуть все значения всех перечислений в одну таблицу.
Вы можете скачать ее отсюда.
Код:
using System; using System.Data; using System.Data.SqlClient; namespace _1CEnumParser { class Program { /// <summary> /// Пробегается по всем перечислениям и заполняет таблицу с тремя полями: название перечисления, название значения, порядок /// </summary> private static void DataTableFill(DataTable aTable, dynamic a1CConn) { foreach (dynamic catalog in a1CConn.Metadata.Enums) { string enumName = catalog.Name; dynamic query = a1CConn.NewObject(«Query»); query.Text = «select * from enum.» + enumName; dynamic items = query.Execute().Unload(); // бежим по строкам for (int i = 0; i < items.Count(); i++) { string enumValue = null; int enumOrder = -1; for (int j = 0; j < items.Columns.Count(); j++) { string colName = items.Columns.Get(j).Name; dynamic colValue; try { colValue = a1CConn.String(items.Get(i).Get(j)); } catch { colValue = «-1»; } switch (colName.ToLower()) { case «ссылка»: enumValue = colValue.ToString(); break; case «порядок»: enumOrder = int.Parse(colValue.ToString()); break; default: throw new ApplicationException(«unknown column name in enum.recordset: » + colName); } } // получили 3 заполненные значения: enumName, enumValue, enumOrder. вставка в таблицу aTable.Rows.Add(new object {enumName, enumValue, enumOrder}); } } } /// <summary> /// Устанавливает все соединения, заполняет DataTable с перечислениями, записывает в БД /// </summary> /// <param name=»aConnectionString1C»></param> /// <param name=»aConnectionStringSQL»></param> /// <param name=»aTableName»></param> private static void ConnectAndFill(string aConnectionString1C, string aConnectionStringSQL, string aTableName) { // входим в SQL базу и удаляем все из таблицы var connSQL = new SqlConnection(aConnectionStringSQL); connSQL.Open(); // входим в 1С var connector1C = new V82.COMConnector(); dynamic conn1C = connector1C.Connect(aConnectionString1C); // удаляем из таблицы все данные var command = new SqlCommand(«delete from » + aTableName, connSQL); command.ExecuteNonQuery(); // заполняем таблицу var da = new SqlDataAdapter(«select EnumName, EnumValue, EnumOrder from » + aTableName, connSQL); var thisBuilder = new SqlCommandBuilder(da); var ds = new DataSet(); da.Fill(ds); DataTableFill(ds.Tables, conn1C); da.Update(ds); // закрываем коннект connSQL.Close(); } static void Main() { string args = Environment.GetCommandLineArgs(); string aConnectionString1C = args; string aConnectionStringSQL = args; string aTableName = args; ConnectAndFill(aConnectionString1C, aConnectionStringSQL, aTableName); } } }

Запускается вот так:
1cEnumParser.exe «строчка_соединения_1С» » строчка_соединения_SQL» «таблица_в_SQL»
Делает следующее: коннектится к 1С с помощью COM, берет оттуда все перечисления, и кладет их в указанную вами таблицу указанной базы, предварительно почистив ее. Таблица должна иметь следующую структуру
CREATE TABLE .( (1024) NULL, (2014) NULL, NULL ) ON
Дальше понятно, что SSIS-пакет (или другой механизм) может запустить этот код перед тем, как извлекать данные фактов/справочников, и мы получим заполненную таблицу

и дальше вы уже можете строить джойн по полю _EnumOrder: справочник ссылается на _Enum таблицу по IDRRef, в ней поле _EnumOrder которое ссылается на поле EnumOrder вашей таблицы, которую только что вытянул C# код.
Если у Вас будут замечания или дополнительные идеи – все они с радостью принимаются, пишите на ibobak at bitimpulse dot com.

Оставьте комментарий