Основные приемы работы
Общее
Способы обхода результата запроса
Линейный обход результата
Иерархический обход результата
Обход результата по группам
Работа с выборкой
Методы определения типа текущей записи
Основные приемы работы с запросами во встроенном языке 1С:Предприятия удобнее всего рассматривать на примерах. Приведем типичный пример использования запроса:
Запрос = Новый Запрос("ВЫБРАТЬ Товар.Наименование Наименование, |Товар.Родитель.Наименование НаименованиеРодителя |ИЗ Справочник.Товары Товар"); // Выполним запрос и запишем результат в переменную РезультатЗапроса. РезультатЗапроса = Запрос.Выполнить(); // Получим выборку из результата запроса. Выборка = РезультатЗапроса.Выбрать(); // Пока в выборке есть записи ... Пока Выборка.Следующий() Цикл // ... выведем в окно сообщений поля из результата. Товар = Выборка.Наименование; Родитель = Выборка.НаименованиеРодителя; Сообщить("Товар: " + Товар + " Родитель: " + Родитель); КонецЦикла; |
Как видно из этого примера, работа с запросом ведется при помощи трех основных объектов:
- Запрос – объект, выполняющий сам запрос. Представлен в примере переменной с именем Запрос.
- РезультатЗапроса – объект, содержащий полученные при выполнении запроса данные. Представлен в примере переменной с именем РезультатЗапроса.
- ВыборкаИзРезультатаЗапроса – объект, позволяющий обходить (т.е. перебрать) записи из результата. Представлен в примере переменной с именем Выборка.
Рассмотрим подробнее объект ВыборкаИзРезультатаЗапроса. Для этого нам понадобится следующий текст запроса:
ВЫБРАТЬ
Товар, Количество
ИЗ
Документ.РасхНакл.Состав
УПОРЯДОЧИТЬ ПО Товар
ИТОГИ Сумма(Количество) ПО Товар Иерархия
Его результат представлен в таблице:
N |
Товар |
Количество |
1 |
Сантехника |
104 |
2 |
Кран |
84 |
3 |
Кран |
10 |
4 |
Кран |
8 |
5 |
Кран |
44 |
6 |
Кран |
22 |
7 |
Смеситель |
20 |
8 |
Смеситель |
5 |
9 |
Смеситель |
1 |
10 |
Смеситель |
14 |
11 |
Мебель |
134 |
12 |
Стол |
26 |
13 |
Стол |
1 |
14 |
Стол |
15 |
15 |
Стол |
10 |
16 |
Стул |
108 |
17 |
Стул |
55 |
18 |
Стул |
5 |
19 |
Стул |
32 |
20 |
Стул |
16 |
В эту таблицу добавлена колонка "N", которой нет в результате запроса, но которая будет использоваться нами в дальнейшем для идентификации записи в результате. Итоговые записи в таблице выделены курсивом, итоговые записи для иерархических уровней справочника выделены жирным шрифтом.
Способы обхода результата запроса
Линейный обход результата
Первый, и самый простой способ обхода – линейный. При линейном обходе выборка будет выдавать записи в той последовательности, в которой они располагаются в результате запроса. В нашем примере это будут записи с номерами 1, 2, 3, 4, 5 и так далее до записи с номером 20.
Для получения линейной выборки из результата необходимо вызвать метод Выбрать объекта РезультатЗапроса без параметров, либо с параметром ОбходРезультатаЗапроса.Прямой.
Пример:
СпособВыборки = ОбходРезультатаЗапроса.Прямой; Выборка1 = РезультатЗапроса.Выбрать(СпособВыборки); // что равнозначно записи Выборка1 = РезультатЗапроса.Выбрать(); |
Иерархический обход результата
Следующий способ обхода результата – иерархический. При данном обходе обходятся только записи, находящиеся на одном уровне. Для получения иерархической выборки из результата необходимо вызвать метод Выбрать() объекта РезультатЗапроса с параметром ОбходРезультатаЗапроса.ПоГруппировкамСИерархией.
Пример:
СпособВыборки = ОбходРезультатаЗапроса.ПоГруппировкамСИерархией; Выборка2 = РезультатЗапроса.Выбрать(СпособВыборки); |
Выборка из результата с иерархическим обходом в нашем примере обойдет только записи с номерами 1 и 11, так как только эти две записи находятся на самом верхнем уровне. Проиллюстрируем это, представив наш результат в виде дерева, где узлами будут итоговые записи, а листьями дерева будут детальные записи. Вот что у нас получится:
Из этого рисунка видно, что именно записи с номерами 1 и 11, и только они находятся на первом уровне дерева, в результате чего только они и попадают в первый проход иерархической выборки.
Возникает вопрос, как получать остальные записи результата запроса. Для этого у объекта ВыборкаИзРезультатаЗапроса можно получить еще одну выборку, которая будет обходить подчиненные записи текущей записи выборки. В нашем примере в момент, когда объект Выборка2 будет позиционирован на запись с номером 1, мы запросим у него иерархическую выборку. Таким образом, мы получим выборку, которая нам вернет записи с номерами 2, 7. А когда Выборка2 будет спозиционирована на записи с номером 11, то полученная у нее иерархическая выборка вернет записи с номерами 12, 16. Так реализуется иерархический обход результатов запроса. Заметим, что у выборки можно получать вложенные выборки любого типа. Так, если бы мы запросили у Выборки2, спозиционированной на записи 1, линейную выборку, то с ее помощью мы бы получили записи с номерами записей со 2-го по 10-й. Проиллюстрируем описанную методику на примере.
Пример:
Процедура ВыполнитьЗапрос() // Создадим запрос. Запрос = Новый Запрос; // Установим текст запроса Запрос.Текст = "ВЫБРАТЬ |Товар, Количество |ИЗ |Документ.РасхНакл.Состав |УПОРЯДОЧИТЬ ПО Товар |ИТОГИ Сумма(Количество) ПО Товар, Товар Иерархия"; // Выполним запрос и запишем результат в переменную // РезультатЗапроса. РезультатЗапроса = Запрос.Выполнить(); // Получим выборку из результата запроса. СпособВыборки = ОбходРезультатаЗапроса.ПоГруппировкамСИерархией; Выборка = РезультатЗапроса.Выбрать(СпособВыборки); ВыдатьРекурсивно(Выборка); КонецПроцедуры Процедура ВыдатьРекурсивно(Выборка) // Пока в выборке есть записи ... Пока Выборка.Следующий() Цикл // ... выведем в окно сообщений поля из результата Товар = Выборка.Наименование; Количество = Выборка.Количество; Сообщить("Товар: " + Товар + " Количество: " + Количество); // Продолжим выборку подчиненных записей СпособВыборки = ОбходРезультатаЗапроса.ПоГруппировкамСИерархией; Если Выборка.ТипЗаписи() = ТипЗаписиЗапроса.ИтогПоИерархии Тогда ДочерняяВыборка = Выборка.Выбрать(СпособВыборки, Выборка.Группировка()); Иначе ДочерняяВыборка = Выборка.Выбрать(СпособВыборки); КонецЕсли; ВыдатьРекурсивно(ДочерняяВыборка); КонецЦикла; КонецПроцедуры |
Обход результата по группам
Третий, и последний способ обхода результата – по группам. Он сходен с иерархическим обходом, но с одним различием: записи с иерархическими итогами при обходе в нем рассматриваются как детальные записи, а не как узловые. Для получения выборки по группам из результата запроса необходимо вызвать метод Выбрать объекта РезультатЗапроса с параметром ОбходРезультатаЗапроса.ПоГруппировкам.
Пример:
СпособВыборки = ОбходРезультатаЗапроса.ПоГруппировкам; Выборка2 = РезультатЗапроса.Выбрать(СпособВыборки); |
Перебрав в ней всё, мы получим записи с номерами 1, 2, 7, 11, 12, 16.
Пример:
Процедура ВыполнитьЗапрос() // Создадим запрос. Запрос = Новый Запрос; // Установим текст запроса Запрос.Текст = "ВЫБРАТЬ |Товар, Количество |ИЗ |Документ.РасхНакл.Состав |УПОРЯДОЧИТЬ ПО Товар |ИТОГИ Сумма(Количество) ПО Товар, Товар Иерархия"; // Выполним запрос и запишем результат в переменную // РезультатЗапроса. РезультатЗапроса = Запрос.Выполнить(); // Получим выборку из результата запроса СпособВыборки = ОбходРезультатаЗапроса.ПоГруппировкам; Выборка = РезультатЗапроса.Выбрать(СпособВыборки); // Пока в выборке есть записи ... Пока Выборка.Следующий() Цикл // ... выведем в окно сообщений поля из результата Товар = Выборка.Наименование; Количество = Выборка.Количество; Сообщить("Товар: "+Товар+" Итого по товару: "+Количество); ВыдатьДочерниеЗаписи(Выборка.Выбрать()); КонецЦикла; КонецПроцедуры Процедура ВыдатьДочерниеЗаписи (Выборка) // Пока в выборке есть записи ... Пока Выборка.Следующий() Цикл // ... выведем в окно сообщений поля из результата Товар = Выборка.Наименование; Количество = Выборка.Количество; Сообщить("Товар: "+Товар+" Количество: "+Количество); КонецЦикла; КонецПроцедуры |
Работа с выборкой
Объект ВыборкаИзРезультатаЗапроса предназначен для обхода записей результата запроса. Можно представить себе выборку как некоторый объект, который содержит указатель на текущую запись в результате и предоставляет программе доступ ко всем полям текущей записи. Для навигации по записям запроса используются три метода:
- Следующий() – перейти к следующей записи результата в соответствии с порядком обхода выборки. При первом вызове позиционирует выборку на первую запись. Когда будут выбраны все записи, данный метод просигнализирует об этом, вернув значение Ложь.
- СледующийПоЗначениюПоля() – получить следующую запись со значением в заданном поле, отличающимся от значения в этом поле текущей записи.
- НайтиСледующий () – найти запись, с заданными значениями некоторых полей.
Использование метода СледующийПоЗначениюПоля
Метод позволяет сгруппировать записи результата по значениям полей.
Пример запроса:
ВЫБРАТЬ
Док.Товар, Док.Получатель, Док.Количество
ИЗ
Документ.РасхНакл.Состав Док
УПОРЯДОЧИТЬ ПО Док.Товар.Наименование, Док.Получатель.Наименование
Его результат:
N |
Товар |
Получатель |
Количество |
1 |
Смеситель |
Маг. "Гигант" |
14 |
2 |
Смеситель |
Маг. "Хозяин" |
1 |
3 |
Смеситель |
Мосгорторг |
5 |
4 |
Кран |
Маг. "Гигант" |
44 |
5 |
Кран |
Маг. "Хозяин" |
8 |
6 |
Кран |
Мосгорторг |
10 |
7 |
Кран |
Мосгорторг |
22 |
8 |
Стол |
Маг. "Гигант" |
10 |
9 |
Стол |
Маг. "Мебель" |
15 |
10 |
Стол |
Мосгорторг |
1 |
11 |
Стул |
Маг. "Гигант" |
32 |
12 |
Стул |
Маг. "Мебель" |
55 |
13 |
Стул |
Маг. "Хозяин" |
5 |
14 |
Стул |
Мосгорторг |
16 |
Получим линейную выборку из результата запроса и обойдем выборку при помощи метода СледующийПоЗначениюПоля.
Пример:
Выборка = РезультатЗапроса.Выбрать(); Пока Выборка.СледующийПоЗначениюПоля("Товар") Цикл // здесь мы получим записи с номерами 1, 4, 8, 11 Пока Выборка.СледующийПоЗначениюПоля("Получатель") Цикл // здесь мы сначала получим записи с номерами 1, 2, 3 // затем 4, 5, 6 // затем 8, 9, 10 // затем 11, 12, 13, 14 КонецЦикла; КонецЦикла; |
Следует обратить внимание на то, что во внутреннем цикле не была выбрана запись с номером 7, т.к. в ней такое же значение поля "Получатель" как и в предыдущей записи.
Заметим, что если в цикле получения по значению поля получать записи при помощи метода Следующий(), то будут выбраны все записи с равным значением поля, заданного в предыдущем вызове метода СледующийПоЗначениюПоля().
Пример:
Выборка = РезультатЗапроса.Выбрать(); Пока Выборка.СледующийПоЗначениюПоля("Товар") Цикл // здесь мы получим записи с номерами 1, 4, 8, 11 Пока Выборка.Следующий() Цикл // здесь мы сначала получим записи с номерами 1, 2, 3 // затем 4, 5, 6, 7 // затем 8, 9, 10 // затем 11, 12, 13, 14 КонецЦикла; КонецЦикла; |
Методы определения типа текущей записи
В тот момент, когда выборка позиционирована на записи, мы можем у выборки узнать характеристики этой записи. Получение характеристик записи осуществляется методами:
- Уровень() – определяет уровень записи в результате запроса.
- ТипЗаписи() – определяет принадлежность записи к одному из следующих типов:
- групповой итог;
- итого по иерархии;
- детальная запись;
- общий итог.
- Группировка() – определяет имя поля, по которому были рассчитаны итоги.
Для иллюстрации работы этих методов посмотрим, что они будут возвращать записей для запроса, рассматриваемого в начале главы:
ВЫБРАТЬ
Товар, Количество Количество
ИЗ
Документ.РасхНакл.Состав
УПОРЯДОЧИТЬ ПО Товар
ИТОГИ Сумма(Количество) ПО Товар, Товар Иерархия
Результат представлен в таблице:
N |
Товар |
Количество |
Уровень |
ТипЗаписи |
Группировка |
1 |
Сантехника |
104 |
0 |
ИтогПоИерархии |
Товар |
2 |
Кран |
84 |
1 |
ИтогПоГруппировке |
Товар |
3 |
Кран |
10 |
2 |
ДетальнаяЗапись |
|
4 |
Кран |
8 |
2 |
ДетальнаяЗапись |
|
5 |
Кран |
44 |
2 |
ДетальнаяЗапись |
|
6 |
Кран |
22 |
2 |
ДетальнаяЗапись |
|
7 |
Смеситель |
20 |
1 |
ИтогПоГруппировке |
Товар |
8 |
Смеситель |
5 |
2 |
ДетальнаяЗапись |
|
9 |
Смеситель |
1 |
2 |
ДетальнаяЗапись |
|
10 |
Смеситель |
14 |
2 |
ДетальнаяЗапись |
|
11 |
Мебель |
134 |
0 |
ИтогПоИерархии |
Товар |
12 |
Стол |
26 |
1 |
ИтогПоГруппировке |
Товар |
13 |
Стол |
1 |
2 |
ДетальнаяЗапись |
|
14 |
Стол |
15 |
2 |
ДетальнаяЗапись |
|
15 |
Стол |
10 |
2 |
ДетальнаяЗапись |
|
16 |
Стул |
108 |
1 |
ИтогПоГруппировке |
Товар |
17 |
Стул |
55 |
2 |
ДетальнаяЗапись |
|
18 |
Стул |
5 |
2 |
ДетальнаяЗапись |
|
19 |
Стул |
32 |
2 |
ДетальнаяЗапись |
|
20 |
Стул |
16 |
2 |
ДетальнаяЗапись |
|