Присвоить переменной результат запроса 1с

Обновлено: 04.07.2024

Довольно часто спрашивают, есть ли аналоги аналитических (оконных) функций в MySQL. Примечание. На момент написания статьи таких аналогов не было, однако статья и ныне представляет собой академический интерес в плане разбора оригинального для MySQL подхода к использованию переменных.

Для замены аналитических функций часто используют запросы с самосоединением, сложные подзапросы и прочее. Большинство таких решений оказываются неэффективными с точки зрения производительности.

Одним из этих средств является уникальный, нехарактерный для прочих СУБД механизм работы с переменными внутри запроса SQL. Мы можем объявить переменную внутри запроса, менять ей значение и подставлять в SELECT для вывода. Причем порядок обработки строк в запросе и, как следствие, порядок присвоения значений переменным можно задать в пользовательской сортировке!

Предупреждение. В статье подразумевается, что обработка выражений в предложении SELECT осуществляется слева направо, однако официального подтверждения такого порядка обработки в документации MySQL нет. Это необходимо иметь в виду при смене версии сервера. Для гарантии последовательности вычисления можно использовать фиктивный оператор CASE или IF.

Аналог рекурсии

Рассмотрим простой пример, который генерирует последовательность Фибоначчи (в последовательности Фибоначчи каждый член равен сумме двух предыдущих, а первые 2 равны единице):

Данный запрос генерирует 18 чисел Фибоначчи, не считая первых двух:


Разберём теперь как оно работает.

В строчках 5) 6) генерируется 9 записей. Тут ничего необычного.

В строчке 7) мы объявляем две переменные @I, @J и присваиваем им 1.

В строке 3) происходит следующее: сначала переменной @I присваивается сумма двух переменных. Затем то же самое присваиваем переменной @J, причем с учетом того, что значение @I уже поменялось.

Другими словами, вычисления в SELECT выполняются слева направо – см. также замечание в начале статьи.

Причем изменение переменных осуществляется в каждой из наших 9 записей, т.е. при обработке каждой новой строки в переменных @I и @J будут содержаться значения, вычисленные при обработке предыдущей строки.

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

Примечание:
Переменные нужно объявлять в отдельном подзапросе (строка 7), если бы мы объявили переменную в предложении SELECT, она, скорее всего, вычислилась бы только 1 раз (хотя конкретное поведение будет зависеть от версии сервера). Тип переменной определяется значением, которым она инициализирована. Этот тип может динамически меняться. Если переменной присвоить NULL, её типом будет BLOB.

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

Аналоги аналитических функций

Переменные также можно использовать для замены аналитических функций. Далее несколько примеров. Для простоты будем считать, что все поля NOT NULL, а сортировка и партиционирование (PARTITION BY) происходят по одному полю. Использование NULL значений и более сложных сортировок сделает примеры более громоздкими, но суть не поменяет.

Для примеров создадим таблицу TestTable:


где
group_id – идентификатор группы (аналог окна аналитической функции);
order_id – уникальное поле, по которому будет производиться сортировка;
value – некоторое числовое значение.

Заполним нашу таблицу тестовыми данными:


Примеры замены некоторых аналитических функций.

1) ROW_NUMBER() OVER(ORDER BY order_id)

group_id order_id value RowNum
1 1 1 1
1 2 2 2
1 3 2 3
2 4 1 4
2 5 2 5
2 6 3 6
3 7 1 7
3 8 2 8
4 9 1 9
3 11 2 10

2) ROW_NUMBER() OVER(PARTITION BY group_id ORDER BY order_id)

group_id order_id value RowNum
1 1 1 1
1 2 2 2
1 3 2 3
2 4 1 1
2 5 2 2
2 6 3 3
3 7 1 1
3 8 2 2
3 11 2 3
4 9 1 1

3) SUM(value) OVER(PARTITION BY group_id ORDER BY order_id)

group_id order_id value RunningTotal
1 1 1 1
1 2 2 3
1 3 2 5
2 4 1 1
2 5 2 3
2 6 3 6
3 7 1 1
3 8 2 3
3 11 2 5
4 9 1 1

4) LAG(value) OVER(PARTITION BY group_id ORDER BY order_id)

group_id order_id value LAG
1 1 1 NULL
1 2 2 1
1 3 2 2
2 4 1 NULL
2 5 2 1
2 6 3 2
3 7 1 NULL
3 8 2 1
3 11 2 2
4 9 1 NULL

Для LEAD всё то же самое, только нужно сменить сортировку на ORDER BY group_id, order_id DESC

Для функций COUNT, MIN, MAX всё несколько сложнее, поскольку, пока мы не проанализируем все строчки в группе(окне), мы не сможем узнать значение функции. MS SQL, например, для этих целей «спулит» окно (временно помещает строки окна в скрытую буферную таблицу для повторного к ним обращения), в MySQL такой возможности нет. Но мы можем для каждого окна вычислить значение функции в последней строке при заданной сортировке (т.е. после анализа всего окна), а затем, отсортировав строки в окне в обратном порядке, проставить вычисленное значение по всему окну.

Таким образом, нам понадобится две сортировки. Чтобы итоговая сортировка осталась той же, что и в примерах выше, отсортируем сначала по полям group_id ASC, order_id DESC, затем по полям group_id ASC, order_id ASC.

5) COUNT(*) OVER(PARTITION BY group_id)

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


group_id order_id value Cnt
1 1 1 3
1 2 2 3
1 3 2 3
2 4 1 3
2 5 2 3
2 6 3 3
3 7 1 3
3 8 2 3
3 11 2 3
4 9 1 1

Функции MAX и MIN вычисляются по аналогии. Приведу только пример для MAX:

6) MAX(value) OVER(PARTITION BY group_id)

group_id order_id value MaxVal
1 1 1 2
1 2 2 2
1 3 2 2
2 4 1 3
2 5 2 3
2 6 3 3
3 7 1 2
3 8 2 2
3 11 2 2
4 9 1 1

7) COUNT(DISTINCT value) OVER(PARTITION BY group_id)

Интересная вещь, которая отсутствует в MS SQL Server, но её можно вычислить с подзапросом, взяв MAX от RANK. Так же поступим и здесь. В первой сортировке вычислим RANK() OVER(PARTITION BY group_id ORDER BY value DESC), затем во второй сортировке проставим максимальное значение всем строкам в каждом окне:


group_id order_id value Cnt
1 1 1 2
1 2 2 2
1 3 2 2
2 4 1 3
2 5 2 3
2 6 3 3
3 7 1 2
3 8 2 2
3 11 2 2
4 9 1 1

Производительность

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

1) Классический способ с самомоединением

Что на 10000 записей в таблице TestTable выдаёт:

Duration / Fetch
16.084 sec / 0.016 sec

2) С использованием переменных:

Duration / Fetch
0.016 sec / 0.015 sec

Результат говорит сам за себя. Однако надо понимать, что вычисленные с помощью переменных значения не оптимально использовать в условиях фильтрации. Сортировка и вычисление будут происходить для ВСЕХ строк, несмотря на то, что в итоге нам нужна только малая их часть.

Рассмотрим более подробно на примере такой задачи:

Вывести по 2 первые строки из таблицы TestTable для каждого значения group_id, отсортированных по order_id.

Вот как эта задача решалась бы в СУБД с поддержкой аналитических функций:


Однако оптимизатор MySQL ничего не знает о том, по каким правилам мы вычисляем поле RowNum. Ему придётся пронумеровать ВСЕ строки, и только потом отобрать нужные.

Теперь представьте, что у нас 1 миллион записей и 20 уникальных значений group_id. Т.е. чтобы выбрать 40 строк, MySQL будет вычислять значение RowNum для миллиона строк! Красивого решения этой задачи одним запросом в MySQL нет. Но можно сначала получить список уникальных значений group_id, например, так:


Затем средствами любого другого языка программирования сгенерировать запрос вида:


20 лёгких запросов отработают намного быстрее, чем вычисление RowNum для миллиона строк.


Как присвоить значение переменной?
Ребята извините что не по теме но как мне переменой а присвоить значение 5?


Как присвоить значение переменной, исходя из значения другой переменной?
Всем привет. Нужна помощь. Есть переменная, например "month" которая может принимать значения.

Запрос.Текст = "ВЫБРАТЬ
|ГДЕ
| --------------- = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Переменная);
Выборка= Запрос.Выполнить().Выбрать();

Для вывода в печатную форму.

Для вывода в печатную форму.
ДоговорКонтрагента = что здесь написать?;
СтруктураПараметров = Новый Структура;
СтруктураПараметров.Вставить("Основание", ДоговорКонтрагента); Что Вам нужно то? Сначала, сформулируйте задачу, прежде чем просить о помощи.

Где:
Документ.КакойТоДокумент соответственно реальный документ которому присваивается имя КакаяТоТаблица
КакоеТоПоле реальное поле твоего документа, которое потом вернётся в виде Выборка.КакоетоЗначение
КакоеТоПолеДва то же реальное поле твоего документа, по которому будет отбор по значению Переменная

как то так, если на пальцах.
Возможны ошибки.

Выдает="ТаблицаЗначений". Как мне в переменную ДогКонтрагента занести результат запроса? Выдает="ТаблицаЗначений". Как мне в переменную ДогКонтрагента занести результат запроса? на пальцах: ДогКонтрагента = это набор данных.
ДогКонтрагента.Следующий() получишь очередную строку из запроса
Сообщить(ДогКонтрагента.Наименование )
получишь название Да не получаю название.Ошибка. Мне в .Параметры. заносить не надо. Мне в переменную итог запроса надо вогнать. этот вопрос решен. Другой появился. Поле(т.е переменная) выводит не все позиции-начало , концовки нет. Да не получаю название.Ошибка. Мне в .Параметры. заносить не надо. Мне в переменную итог запроса надо вогнать. этот вопрос решен. Другой появился. Поле(т.е переменная) выводит не все позиции-начало , концовки нет. Может вы всё же основы 1С программирования почитаете?
Если уж в код решили залезть.
Хелпером как нибудь воспользуетесь или просто поиском в инете Проблема выгружает значение не до конца(т.е. Договор № 765 от. ). Где остальная часть. В консоле выводит полностью это поле. В чем может быть проблема?

В том что телепатов на белом свете не существует.

как увеличить ширину этой переменной? Может через какую-то временную переменную надо? как увеличить ширину этой переменной? Может через какую-то временную переменную надо? Второй раз говорю. Телепатов нет угадывать где и что у тебя не получается впихнуть по ширине.
Научись скрины делать и сюда выкладывать

Как переменной описанной в программе присвоить значение переменной в Conditional Compilation Arguments?
Kak mozhno peremennij opisanoj v programme prisvoit` znachenie peremennoj v Conditional Compilation.


Присвоить логической переменной T значение true, если значение d-цифра, и значение false в противном случае
Имеется символьная переменная d, присвоить логической переменной T значение true, если значение.

Как php переменной присвоить значение переменной javascript?
есть переменная php как ей присвоить значение переменной javascript?


Переменной Y присвоить значение той переменной, которое находится между двумя другими на числовой оси
Даны три вещественных, не равных между собой числа a, b, c. Переменной Y присвоить значение той.

Значения в запрос можно передать несколькими способами:

Использование параметров запроса

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

В тексте запроса перед именем параметра ставится символ &. Установка значений параметров производится методом

УстановитьПараметр (< ИмяПараметра >, < ЗначениеПараметра >)

Пример передачи параметра в запрос:

Ключевое слово ЗНАЧЕНИЕ

В запросе можно обратиться к предопределенным данным конфигурации без использования параметров. При помощи ключевого слова ЗНАЧЕНИЕ в запрос можно передать такие данные, как:

  • значения перечислений;
  • предопределенные элементы справочников, планов видов характеристик, планов счетов, планов видов расчетов;
  • пустые ссылки;
  • значения точек маршрута бизнес-процессов;
  • значения системных перечислений (например, ВидДвиженияНакопления).

Пример обращения к предопределенным значениям в запросе:

Результатом запроса будут все элементы справочника Номенклатура с типом Услуга.

Ключевое слово ДАТАВРЕМЯ

К значениям типа дата в запросе можно обратиться при помощи конструкции

Пример обращения к пустой дате в запросе:

Результатом запроса будут все элементы справочника СоглашенияСПоставщиками, у которых не задана дата окончания действия.

Ключевое слово ТИП

Обращение к типу ТИП в запросе осуществляется конструкцией

Здесь ИмяТипа может принимать имя примитивного типа или имя таблицы ссылочного типа.
Примеры использования в запросе:

ТИП(Строка)
ТИП(Число)
ТИП(Справочник.Пользователи)
ТИП(Документ.РасходныйКассовыйОрдер)
ТИП(ПланВидовХарактеристик.СтатьиРасходов)

Обращение к примитивным типам в запросе

Значения типов Булево, Число, Строка, Неопределено в языке запросов задаются так же, как и во встроенном языке.
Пример обращения к примитивным типам в запросе:

Остались вопросы?
Спросите в комментариях к статье.

Запросы предназначены для извлечения и обработки информации из базы данных для предоставления пользователю в требуемом виде. Под обработкой здесь подразумевается группировка полей, сортировка строк, расчет итогов и т.д. Изменять данные с помощью запросов в 1С нельзя!

Схема работы с запросом

Общая схема работы с запросом состоит из нескольких последовательных этапов:

  1. Создание объекта Запрос и установка текста запроса;
  2. Установка параметров запроса;
  3. Выполнение запроса и получение результата;
  4. Обход результата запроса и обработка полученных данных.

1. Объект Запрос имеет свойство Текст, которому необходимо присвоить текст запроса.

3. После присвоения текста и установки параметров запрос необходимо выполнить и получить результат выполнения. Выполнение производится методом Выполнить () , который возвращает объект РезультатЗапроса. Из результата запроса можно:

  • получить выборку с помощью метода Выбрать (< ТипОбхода >, < Группировки >, < ГруппировкиДляЗначенийГруппировок >) ;
  • выгрузить значения в таблицу значений или дерево значений с помощью метода Выгрузить (< ТипОбхода >) .

// Получение выборки
РезультатЗапроса = Запрос . Выполнить ();
Выборка = РезультатЗапроса . Выбрать ();

// Получение таблицы значений
РезультатЗапроса = Запрос . Выполнить ();
Таблица = РезультатЗапроса . Выгрузить ();

4. Обойти выборку результата запроса можно с помощью цикла:

Пока Выборка . Следующий () Цикл
Сообщить ( Выборка . Курс );
КонецЦикла;

Полный пример работы с запросом может выглядеть так:

Состав текста запроса

Текст запроса состоит из нескольких секций:

Обязательной является только первая секция.

Временные таблицы и пакетные запросы

Часто можно столкнуться с ситуацией, когда в качестве источника запроса нужно использовать не таблицы базы данных, а результат выполнения другого запроса. Эту задачу можно решить с помощью вложенных запросов или временных таблиц. Применение временных таблиц позволяет упростить текст сложного запроса, разделив его на составные части, а также, в некоторых случаях, ускорить выполнение запроса и уменьшить количество блокировок. Для работы с временными таблицами используется объект МенеджерВременныхТаблиц. Создание временной таблицы производится при помощи ключевого слова ПОМЕСТИТЬ, за которым следует наименование временной таблицы.

Виртуальные таблицы

Существуют следующие виртуальные таблицы (в скобках указаны возможные параметры):

При работе с виртуальными таблицами следует накладывать отборы в параметрах виртуальных таблиц, а не в условии ГДЕ. От этого сильно зависит время выполнения запроса.

Конструктор запроса

Для ускорения ввода текстов запросов платформа имеет специальные инструменты: Конструктор запроса и Конструктор запроса с обработкой результата. Для вызова конструкторов необходимо щелкнуть правой кнопкой мыши и выбрать требуемый пункт:

Вызов конструктора запроса

Также конструкторы можно вызвать из главного меню Текст.

При помощи конструктора запроса программист может интерактивно сконструировать текст запроса. Для этого мышкой выбираются нужные таблицы и поля, устанавливаются связи, группировки, итоги и т.д. Данный подход позволяет экономить время и избавиться от возможных ошибок. В результате своей работы конструктор запроса формирует текст запроса.

Конструктор запроса с обработкой результата кроме формирования текста запроса создает готовый фрагмент кода для получения и обработки данных.

Конструктор запроса 1С

Объект СхемаЗапроса

Платформа позволяет программно создавать и редактировать текст запроса при помощи объекта СхемаЗапроса. Объект имеет единственное свойство ПакетЗапросов, в котором объекта хранятся свойства всех запросов, редактируемых в данный момент. Объект СхемаЗапроса поддерживает следующие методы:

Рассмотрим пример работы с объектом СхемаЗапроса. Для программного формирования текста запроса

ВЫБРАТЬ
Валюты.Ссылка КАК Валюта,
Валюты.Код
ИЗ
Справочник.Валюты КАК Валюты
ГДЕ
НЕ Валюты.ПометкаУдаления

УПОРЯДОЧИТЬ ПО
Валюты.Код

Код на встроенном языке может выглядеть так:

Остались вопросы?
Спросите в комментариях к статье.

Читайте также: