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

Общее
Способы обхода результата запроса
Линейный обход результата
Иерархический обход результата
Обход результата по группам
Работа с выборкой
Методы определения типа текущей записи

Основные приемы работы с запросами во встроенном языке 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

ДетальнаяЗапись

 

 

1C:Enterprise Developer's Community