Запрос синтаксическая ошибка 1с

Синтаксическая ошибка в запросе

Я
   pnamik

01.03.15 — 10:40

Добрый день

1С 8.0.18.2. самописная конфа.

При сформировании отчета валовая прибыль выдает ошибку:

{Форма.Форма(107)}: Ошибка при вызове метода контекста (Выполнить): {(29, 8)}: Синтаксическая ошибка «КАК»

КОНЕЦ <<?>>КАК Рентабельность

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

Не понимаю, как исправить. Помогите, пожалуйста

Часть текста запроса:

        Запрос = Новый Запрос(«ВЫБРАТЬ

                              |    ДвиженияПоПартиям.Период,

                              |    ДвиженияПоПартиям.Регистратор,

                              |    ДвиженияПоПартиям.КодОперации,

                              |    ДвиженияПоПартиям.Номенклатура КАК Номенклатура,

                              |    ДвиженияПоПартиям.Склад КАК Склад,

                              |    ДвиженияПоПартиям.Партия КАК Партия,

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              | -1*0 ИНАЧЕ 1 КОНЕЦ * ДвиженияПоПартиям.Количество КАК Количество,

                              | ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА -Чеки.СуммаВсего*0 ИНАЧЕ

                              |    ДвиженияПоПартиям.СуммаПрод КОНЕЦ  КАК Выручка,

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              | -1 ИНАЧЕ 0 КОНЕЦ * ДвиженияПоПартиям.Количество КАК КоличествоВозврат,

                              | ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА -Чеки.СуммаВсего ИНАЧЕ

                              |    0 КОНЕЦ  КАК ВыручкаВозврат,

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              | -1 ИНАЧЕ 1 КОНЕЦ *    ДвиженияПоПартиям.Сумма КАК Себестоимость,

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              |    (Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма)*-1 ИНАЧЕ ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма КОНЕЦ  КАК ВаловаяПрибыль,

                              |    ВЫБОР

                              |        КОГДА ЕСТЬNULL(ДвиженияПоПартиям.Сумма, 0) = 0

                              |            ТОГДА 0

                              |        ИНАЧЕ

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              | (Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма)*-1 ИНАЧЕ (ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма) КОНЕЦ / ДвиженияПоПартиям.Сумма * 100

                              |    КОНЕЦ КАК Наценка,

                              |     ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ  ТОГДА

                              | (Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма)*-1 ИНАЧЕ (ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма) КОНЕЦ / ДвиженияПоПартиям.СуммаПрод * 100

                              |    КОНЕЦ КАК Рентабельность

                              |ИЗ

                              |    РегистрНакопления.ДвиженияПоПартиям КАК ДвиженияПоПартиям

                              | ЛЕВОЕ СОЕДИНЕНИЕ Документ.КассовыйЧек.Покупки КАК Чеки

                              | ПО Чеки.Ссылка = ДвиженияПоПартиям.Регистратор

                              | И Чеки.НомерСтроки = ДвиженияПоПартиям.НомерСтроки

                              |ГДЕ

                              |    ДвиженияПоПартиям.Период МЕЖДУ &НачалоПериода И &КонецПериода

                              |    И ДвиженияПоПартиям.Регистратор ССЫЛКА Документ.КассовыйЧек» +

                              ?(МассивНоменклатуры.Количество() > 0, » И ДвиженияПоПартиям.Номенклатура В ИЕРАРХИИ(&МассивНоменклатуры)», «») +

                              ?(СкладЗаполнен = Истина, » И ДвиженияПоПартиям.Склад В ИЕРАРХИИ(&Склад)», «») +

                              ?(ПартияЗаполнен = Истина, » И ДвиженияПоПартиям.Партия В ИЕРАРХИИ(&Партия)», «») + »

                              |ИТОГИ

                              |    СУММА(КоличествоВозврат),

                              |    СУММА(ВыручкаВозврат),

                              |    СУММА(Количество),

                              |    СУММА(Выручка),

                              |    СУММА(Себестоимость),

                              |    СУММА(ВаловаяПрибыль),

                              |    СУММА(Наценка),

                              |    СУММА(Рентабельность)

                              |ПО

                              |    ОБЩИЕ,

                              |    Номенклатура ИЕРАРХИЯ»);

        Запрос.УстановитьПараметр(«КВ», Перечисления.КодыОпераций.ВозвратОтПокупателя);

        Запрос.УстановитьПараметр(«НачалоПериода», НачалоДня(НачалоПериода));

        Запрос.УстановитьПараметр(«КонецПериода», КонецДня(КонецПериода));

        Запрос.УстановитьПараметр(«МассивНоменклатуры», МассивНоменклатуры);

        Запрос.УстановитьПараметр(«Склад», Склад);

        Запрос.УстановитьПараметр(«Партия», Партия);

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

        Выборка = РезультатЗапроса.Выбрать();

        ОбработкаПрерыванияПользователя();

        
        Макет = ПолучитьМакет(«МакетВариант1»);

   pnamik

1 — 01.03.15 — 10:41

Запрос = Новый Запрос(«ВЫБРАТЬ

                              |    ДвиженияПоПартиям.Период,

                              |    ДвиженияПоПартиям.Регистратор,

                              |    ДвиженияПоПартиям.КодОперации,

                              |    ДвиженияПоПартиям.Номенклатура КАК Номенклатура,

                              |    ДвиженияПоПартиям.Склад КАК Склад,

                              |    ДвиженияПоПартиям.Партия КАК Партия,

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              | -1*0 ИНАЧЕ 1 КОНЕЦ * ДвиженияПоПартиям.Количество КАК Количество,

                              | ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА -Чеки.СуммаВсего*0 ИНАЧЕ

                              |    ДвиженияПоПартиям.СуммаПрод КОНЕЦ  КАК Выручка,

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              | -1 ИНАЧЕ 0 КОНЕЦ * ДвиженияПоПартиям.Количество КАК КоличествоВозврат,

                              | ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА -Чеки.СуммаВсего ИНАЧЕ

                              |    0 КОНЕЦ  КАК ВыручкаВозврат,

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              | -1 ИНАЧЕ 1 КОНЕЦ *    ДвиженияПоПартиям.Сумма КАК Себестоимость,

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              |    (Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма)*-1 ИНАЧЕ ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма КОНЕЦ  КАК ВаловаяПрибыль,

                              |    ВЫБОР

                              |        КОГДА ЕСТЬNULL(ДвиженияПоПартиям.Сумма, 0) = 0

                              |            ТОГДА 0

                              |        ИНАЧЕ

                              |    ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              | (Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма)*-1 ИНАЧЕ (ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма) КОНЕЦ / ДвиженияПоПартиям.Сумма * 100

                              |    КОНЕЦ КАК Наценка,

                              |     ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ  ТОГДА

                              | (Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма)*-1 ИНАЧЕ (ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма) КОНЕЦ / ДвиженияПоПартиям.СуммаПрод * 100

                              |    КОНЕЦ КАК Рентабельность

                              |ИЗ

                              |    РегистрНакопления.ДвиженияПоПартиям КАК ДвиженияПоПартиям

                              | ЛЕВОЕ СОЕДИНЕНИЕ Документ.КассовыйЧек.Покупки КАК Чеки

                              | ПО Чеки.Ссылка = ДвиженияПоПартиям.Регистратор

                              | И Чеки.НомерСтроки = ДвиженияПоПартиям.НомерСтроки

                              |ГДЕ

                              |    ДвиженияПоПартиям.Период МЕЖДУ &НачалоПериода И &КонецПериода

                              |    И ДвиженияПоПартиям.Регистратор ССЫЛКА Документ.КассовыйЧек» +

                              ?(МассивНоменклатуры.Количество() > 0, » И ДвиженияПоПартиям.Номенклатура В ИЕРАРХИИ(&МассивНоменклатуры)», «») +

                              ?(СкладЗаполнен = Истина, » И ДвиженияПоПартиям.Склад В ИЕРАРХИИ(&Склад)», «») +

                              ?(ПартияЗаполнен = Истина, » И ДвиженияПоПартиям.Партия В ИЕРАРХИИ(&Партия)», «») + »

                              |ИТОГИ

                              |    СУММА(КоличествоВозврат),

                              |    СУММА(ВыручкаВозврат),

                              |    СУММА(Количество),

                              |    СУММА(Выручка),

                              |    СУММА(Себестоимость),

                              |    СУММА(ВаловаяПрибыль),

                              |    СУММА(Наценка),

                              |    СУММА(Рентабельность)

                              |ПО

                              |    ОБЩИЕ,

                              |    Номенклатура ИЕРАРХИЯ»);

        Запрос.УстановитьПараметр(«КВ», Перечисления.КодыОпераций.ВозвратОтПокупателя);

        Запрос.УстановитьПараметр(«НачалоПериода», НачалоДня(НачалоПериода));

        Запрос.УстановитьПараметр(«КонецПериода», КонецДня(КонецПериода));

        Запрос.УстановитьПараметр(«МассивНоменклатуры», МассивНоменклатуры);

        Запрос.УстановитьПараметр(«Склад», Склад);

        Запрос.УстановитьПараметр(«Партия», Партия);

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

        Выборка = РезультатЗапроса.Выбрать();

        ОбработкаПрерыванияПользователя();

        
        Макет = ПолучитьМакет(«МакетВариант1»);

   ДенисЧ

2 — 01.03.15 — 10:46

(Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма)*-1

тут ошибка

   Записьдампа

3 — 01.03.15 — 10:49

КОНЕЦ разделить на Сумму и умножить на 100 КОНЦОВ

=)

   hhhh

4 — 01.03.15 — 10:55

два раза КОНЕЦ впендюрил, элементарно же.

   pnamik

5 — 01.03.15 — 11:15

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

….

ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

                              | (Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма)*-1 ИНАЧЕ (ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма) КОНЕЦ / ДвиженияПоПартиям.Сумма * 100

                              |    КОНЕЦ КАК Наценка,

по аналогии хотел добавить в текст запроса рентабельность (в макет добавил)

ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ  ТОГДА

                              | (Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма)*-1 ИНАЧЕ (ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма) КОНЕЦ / ДвиженияПоПартиям.СуммаПрод * 100

                              |    КОНЕЦ КАК Рентабельность

выдал ошибку (0).

Думаю (2) прав. чем заменить это выражение, не знаю.

   ДенисЧ

6 — 01.03.15 — 11:17

второй конец убери. А то как-то неприлично получается…

   Wobland

7 — 01.03.15 — 11:17

-(Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма). внезапно, правда?

   pnamik

8 — 01.03.15 — 11:29

предлагаемые варианты (6) и (7) попробовал. та же синтаксическая ошибка. не понимание — это ужас.

   pnamik

9 — 01.03.15 — 11:31

{Форма.Форма(107)}: Ошибка при вызове метода контекста (Выполнить): {(27, 2)}: Синтаксическая ошибка «ВЫБОР»

<<?>>ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ ТОГДА

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

   Wobland

10 — 01.03.15 — 11:33

(9) выборы и концы пересчитал?

   pnamik

11 — 01.03.15 — 11:33

варианты

ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ  ТОГДА

                              | -(Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма) ИНАЧЕ (ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма) КОНЕЦ / ДвиженияПоПартиям.СуммаПрод * 100

                              |    КОНЕЦ КАК Рентабельность

или

ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ  ТОГДА

                              | -(Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма) ИНАЧЕ (ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма) / ДвиженияПоПартиям.СуммаПрод * 100

                              |    КОНЕЦ КАК Рентабельность

или же

ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ  ТОГДА

                              | -(Чеки.СуммаВсего — ДвиженияПоПартиям.Сумма) ИНАЧЕ (ДвиженияПоПартиям.СуммаПрод — ДвиженияПоПартиям.Сумма) КОНЕЦ / ДвиженияПоПартиям.СуммаПрод * 100

                              |    КАК Рентабельность

или же еще в разных вариациях

   Wobland

12 — 01.03.15 — 11:35

я вижу ошибку в поле, которое заканчивается на 26й строке

   pnamik

13 — 01.03.15 — 11:37

т.е. в этой строке:

ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ  ТОГДА ?

   pnamik

14 — 01.03.15 — 11:38

(9) имеется ввиду это?

|ИТОГИ

                              |    СУММА(КоличествоВозврат),

                              |    СУММА(ВыручкаВозврат),

                              |    СУММА(Количество),

                              |    СУММА(Выручка),

                              |    СУММА(Себестоимость),

                              |    СУММА(ВаловаяПрибыль),

                              |    СУММА(Наценка),

                              |    СУММА(Рентабельность)

   Записьдампа

15 — 01.03.15 — 11:40

Лишний конец уравновешивается выбором! =)

ВЫБОР
    КОГДА ЕСТЬNULL(ДвиженияПоПартиям.Сумма, 0) = 0
    ТОГДА
        0
    ИНАЧЕ 
        ВЫБОР
            КОГДА ДвиженияПоПартиям.КодОперации = &КВ
            ТОГДА
                Чеки.СуммаВсего - ДвиженияПоПартиям.Сумма)*-1 
            ИНАЧЕ 
                (ДвиженияПоПартиям.СуммаПрод - ДвиженияПоПартиям.Сумма) 
        КОНЕЦ / ДвиженияПоПартиям.Сумма * 100

КОНЕЦ КАК Наценка,


ВЫБОР
    КОГДА ЕСТЬNULL(ДвиженияПоПартиям.СуммаПрод, 0) = 0
    ТОГДА
        0
    ИНАЧЕ
        ВЫБОР КОГДА ДвиженияПоПартиям.КодОперации = &КВ
            ТОГДА
                (Чеки.СуммаВсего - ДвиженияПоПартиям.Сумма)*-1 
            ИНАЧЕ 
                (ДвиженияПоПартиям.СуммаПрод - ДвиженияПоПартиям.Сумма) 
        КОНЕЦ / ДвиженияПоПартиям.СуммаПрод * 100

КОНЕЦ КАК Рентабельность

   Wobland

16 — 01.03.15 — 11:40

(13) сам считай свои строки

   pnamik

17 — 01.03.15 — 11:49

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

  

pnamik

18 — 01.03.15 — 11:57

(16), (6), (4), (2) также спасибо за участие в обсуждении

Синтаксическая ошибка ВЫБРАТЬ при выполнении запроса

Синтаксическая ошибка «ВЫБРАТЬ»<?> ВЫБРАТЬ возникает в 1С, когда в тексте запроса идут его блоки в подряд без разделения между собой.

Синтаксическая ошибка ВЫБРАТЬ

Рис.1 Скриншот ошибки «Выбрать»

Например, в случаях:

  • объединения запросов, когда подзапросы должны отделяться служебными словами «ОБЪЕДИНИТЬ» или «ОБЪЕДИНИТЬ ВСЕ«
  • два запроса идущие в подряд для последующей выборки методом ВыбратьПакет(): требуется их разделение » ; «
  • последующая выборка из временной таблицы: также необходимо разделение » ; «
  • неверный синтаксис во вложенном запросе в конструкции ГДЕ Значение В (Выбрать ссылка из Справочники.ПримерСправочника): доступно только сравнение » В ()«, а не «=«, «>» и прочее

Замечу, что такая ошибка возникает при ручной правке текста, поскольку при формировании  конструктором запроса, он вставляет разделители самостоятельно:

Разделение подзапросов

Цифры в начале ошибки (на рисунке — 386,1) —  это номер строки в запросе. При большом тексте  такая информация поможет быстрее локализовать ошибку.

Поведение системы

Выполнение запроса прерывается, но система продолжает работать

Реклама всегда менее актуальна, чем думают ее создатели.

0 / 0 / 0

Регистрация: 24.03.2018

Сообщений: 2

1

24.03.2018, 18:19. Показов 10497. Ответов 3


Студворк — интернет-сервис помощи студентам

Ошибка при выполнении обработчика — ‘ОбработкаПроведения’
по причине:
{Документ.ОказаниеУслуги.МодульОбъекта(42)}: Ошибка при вызове метода контекста (Выполнить)
РезультатЗапроса = Запрос.Выполнить();
по причине:
{(19, 4)}: Синтаксическая ошибка «ОказаниеУслугиПереченьНоменклатуры.НаборСвойств»
<<?>>ОказаниеУслугиПереченьНоменклатуры.НаборСвойств

P.S Я по книги делаю, Радченко, 100 раз все проверил, все сделал как там.
Изначально запрос строился в конструкторе, но после добавление Плана видов характеристик, в документ Оказание услуг добавили поле НаборСвойств и запрос дополнил в ручную этой строкой!

Объясните поподробнее пожалуйста, а то я в 1С пару дней!

код

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
Процедура ОбработкаПроведения(Отказ, Режим)
    
    
    Движения.ОстаткиМатериалов.Записывать = Истина;
    Движения.СтоимостьМатериалов.Записывать = Истина;
    Движения.Продажи.Записывать = Истина;
    
    // Создать менеджер временных таблиц
    МенеджерВТ = Новый МенеджерВременныхТаблиц;
    
    #Область НоменклатураДокумента
 
    Запрос = Новый Запрос;
    
     // Укажем, какой менеджер временных таблиц использует этот запрос
    Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
 
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
        |   ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры 
        |                                                     КАК ВидНоменклатуры,
        |   ОказаниеУслугиПереченьНоменклатуры.НаборСвойств,
        |   СУММА(ОказаниеУслугиПереченьНоменклатуры.Количество) 
        |                                       КАК КоличествоВДокументе,
        |   СУММА(ОказаниеУслугиПереченьНоменклатуры.Сумма) 
        |                                    КАК СуммаВДокументе
        |ПОМЕСТИТЬ НоменклатураДокумента
        |ИЗ
        |   Документ.ОказаниеУслуги.ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
        |ГДЕ
        |   ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка
        |
        |СГРУППИРОВАТЬ ПО
        |   ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
        |   ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры
        |   ОказаниеУслугиПереченьНоменклатуры.НаборСвойств ";
 
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
 
    РезультатЗапроса = Запрос.Выполнить();
    #КонецОбласти
    
    
     #Область ДвиженияДокумента
    
    Запрос2 = Новый Запрос;
    Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
    Запрос2.Текст = "ВЫБРАТЬ
                    |    НоменклатураДокумента.Номенклатура,
                    |    НоменклатураДокумента.ВидНоменклатуры,
                    |    НоменклатураДокумента.НаборСвойств,
                    |    НоменклатураДокумента.КоличествоВДокументе,
                    |    НоменклатураДокумента.СуммаВДокументе,
                    |   ЕСТЬNULL(СтоимостьМатериаловОстатки.СтоимостьОстаток, 0) КАК Стоимость,
                    |   ЕСТЬNULL(ОстаткиМатериаловОстатки.КоличествоОстаток, 0) КАК Количество
                    |ИЗ
                    |    НоменклатураДокумента КАК  НоменклатураДокумента
                    |       ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(
                    |               ,
                    |               Материал В
                    |                   (ВЫБРАТЬ
                    |                       НоменклатураДокумента.Номенклатура
                    |                   ИЗ
                    |                       НоменклатураДокумента)) КАК ОстаткиМатериаловОстатки
                    |       ПО  НоменклатураДокумента.Номенклатура = ОстаткиМатериаловОстатки.Материал
                    |       ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьМатериалов.Остатки(
                    |               ,
                    |               Материал В
                    |                   (ВЫБРАТЬ
                    |                       НоменклатураДокумента.Номенклатура
                    |                   ИЗ
                    |                       НоменклатураДокумента)) КАК СтоимостьМатериаловОстатки
                    |       ПО  НоменклатураДокумента.Номенклатура = СтоимостьМатериаловОстатки.Материал  ";
                    
                    
        // Установим необходимость блокировки данных в регистрах СтоимостьМатериалов
         // и ОстаткиМатериалов
      Движения.СтоимостьМатериалов.БлокироватьДляИзменения = Истина;
      Движения.ОстаткиМатериалов.БлокироватьДляИзменения = Истина;
                    
    // Запишем пустые наборы записей, чтобы читать остатки без учета данных в документе
    Движения.СтоимостьМатериалов.Записать();
    Движения.ОстаткиМатериалов.Записать();
                    
    РезультатЗапроса = Запрос2.Выполнить();
    
    
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
 
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        
        Если ВыборкаДетальныеЗаписи.Количество = 0 Тогда
              СтоимостьМатериала = 0;
         Иначе
              СтоимостьМатериала =
              ВыборкаДетальныеЗаписи.Стоимость / ВыборкаДетальныеЗаписи.Количество;
        КонецЕсли;
        
        
        
        Если ВыборкаДетальныеЗаписи.ВидНоменклатуры =
            Перечисления.ВидыНоменклатуры.Материал Тогда 
            // регистр ОстаткиМатериалов Расход
        Движение = Движения.ОстаткиМатериалов.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
        Движение.Период = Дата;
        Движение.Материал = ВыборкаДетальныеЗаписи.Номенклатура;
        Движение.НаборСвойств = ВыборкаДетальныеЗаписи.НаборСвойств;
        Движение.Склад = Склад;
        Движение.Количество = ВыборкаДетальныеЗаписи.КоличествоВДокументе;
        // регистр СтоимостьМатериалов Расход
        Движение = Движения.СтоимостьМатериалов.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
        Движение.Период = Дата;
        Движение.Материал = ВыборкаДетальныеЗаписи.Номенклатура;
        Движение.Стоимость = ВыборкаДетальныеЗаписи.КоличествоВДокументе * СтоимостьМатериала;
                                                                  
                                                                   
    КонецЕсли;
    
    // Регистр Продажи
        Движение = Движения.Продажи.Добавить();
        Движение.Период = Дата;
        Движение.Номенклатура = ВыборкаДетальныеЗаписи.Номенклатура;
        Движение.Клиент = Клиент;
        Движение.Мастер = Мастер;
        Движение.Количество = ВыборкаДетальныеЗаписи.КоличествоВДокументе;
        Движение.Выручка = ВыборкаДетальныеЗаписи.СуммаВДокументе;
        Движение.Стоимость = СтоимостьМатериала * ВыборкаДетальныеЗаписи.КоличествоВДокументе;
 
    
 
    КонецЦикла;
    Движения.Записать();
    #КонецОбласти
    
    
    #Область КонтрольОстатков
           Если Режим = РежимПроведенияДокумента.Оперативный Тогда
           // Проверить отрицательные остатки
           Запрос3 = Новый Запрос;
           Запрос3.МенеджерВременныхТаблиц = МенеджерВТ;
           Запрос3.Текст = "ВЫБРАТЬ
                           |    ОстаткиМатериаловОстатки.Материал,
                           |    ОстаткиМатериаловОстатки.НаборСвойств,
                           |    ОстаткиМатериаловОстатки.КоличествоОстаток
                           |ИЗ
                           |    РегистрНакопления.ОстаткиМатериалов.Остатки(,(Материал, НаборСвойств)В
                           |                    (ВЫБРАТЬ
                           |                        НоменклатураДокумента.Номенклатура
                           |                        НоменклатураДокумента.НаборСвойств
                           |                    ИЗ
                           |                        НоменклатураДокумента)
                           |                И Склад = &Склад) КАК ОстаткиМатериаловОстатки
                           |ГДЕ
                           |    ОстаткиМатериаловОстатки.КоличествоОстаток < 0 ";
                           
           Запрос3.УстановитьПараметр("Склад", Склад);
           РезультатЗапроса = Запрос3.Выполнить();
           ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
           
              Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
              Сообщение = Новый СообщениеПользователю();
              Сообщение.Текст = "Не хватает " + Строка(- ВыборкаДетальныеЗаписи.КоличествоОстаток) +
                       " единиц материала """ + ВыборкаДетальныеЗаписи.Материал + """" + 
                       " из набора свойств """ + ВыборкаДетальныеЗаписи.НаборСвойств + """";
               Сообщение.Сообщить();
                    Отказ = Истина;
КонецЦикла;
 
            КонецЕсли;
 
#КонецОбласти   
КонецПроцедуры

Миниатюры

Синтаксическая ошибка в запросе 1С
 



0



kulkrise
04.11.2013 17:37 Прочитано: 2871

1С 8.2 БП 2.0 Обычное приложениеКод 1C v 8.2 УП

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

Выдается сообщение «Синтаксическая ошибка». В чем ошибка?

Yandex
Возможно, вас также заинтересует

Реклама на портале

E_Migachev
04.11.2013 21:53 Ответ № 1

(0) kulkrise, так а на что ругается?

kulkrise
04.11.2013 22:13 Ответ № 2

{(3, 1)}: Синтаксическая ошибка «Список.Контрагент.Наименование»
<<?>>Список.Контрагент.Наименование КАК Наименование

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

E_Migachev
04.11.2013 22:25 Ответ № 3

а кто это написал: |ИЗ Документ.РеализацияТоваровУслуг КАК Список, Документ.ПоступлениеТоваровУслуг КАК Список»; ?
из может быть только из одной таблицы, например:
|ИЗ Документ.РеализацияТоваровУслуг КАК Список

kulkrise
04.11.2013 22:32 Ответ № 4

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

Дополнительно: мне подсказали. что у меня нет запятой после каждого
выбираемого параметра, что и было мной исправлено, добавлено ОБЪДИНИТЬ ВСЕ.

Код 1C v 8.2 УП

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

выводится сообщение об ошибке
{(17, 1)}: Синтаксическая ошибка «ИЗ»
<<?>>ИЗ Документ.РеализацияТоваровУслуг

kulkrise
04.11.2013 22:51 Ответ № 5

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

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

Код 1C v 8.2 УП

    Если НЕ РезультатЗапроса.ПометкаУдаления Тогда

Код 1C v 8.2 УП

 Пока РезультатЗапроса.Следующий() Цикл
// Исключение объектов, помеченных на удаление
Если НЕ РезультатЗапроса.ПометкаУдаления Тогда
// Тело цикла
КонецЕсли;
КонецЦикла;
E_Migachev
04.11.2013 23:41 Ответ № 6

(5) kulkrise, так создавай запрос через конструктор и не будет проблем
эти запросы совершенно неправильные

Mokey
05.11.2013 11:23 Ответ № 7

В первом посте запятых нет вообще, во втором — лишняя перед ИЗ, вот и весь вопрос

DJ_Serega
05.11.2013 11:28 Ответ № 8

Непонятен смысл запроса. А на ошибки уже указали.

Подсказка: Вы можете приложить к ответу файл или изображение щелкнув по значку или в редакторе.

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

Рассмотрим основные моменты работы с данным механизмом:

  • Контекст работы с запросами
  • Структура запросов и методика их использования
  • Атрибуты запросов
  • Методы запросов
  • Введение в язык запросов
  • Атрибуты, доступные при описании внутренних переменных
  • Правила объявления внутренних переменных
  • Операторы языка запросов
  • Примеры использования запросов
  • Способы оптимизации формирования отчётов

Контекст работы с запросами

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

При создании объекта типа "Запрос" в качестве параметра функции СоздатьОбъект() используется ключевое слово «Запрос» (англоязычный синоним — «Query»).

Запрос = СоздатьОбъект("Запрос");

Структура запросов и методика их использования

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

Запросы можно использовать не только для построения отчётов, но и для реализации других процедур конфигурации, требующих получения из базы данных некой сводной информации. Например, реализация алгоритма списания стоимости товара по методам FIFO или LIFO.

Работа с запросами предполагает следующий порядок:

  • при помощи функции СоздатьОбъект() создаётся объект типа "Запрос" и ссылка на него присваивается какой-либо переменной. Далее обращение к запросу производится посредством этой ссылки;
  • после создания переменной типа "Запрос" следует обращение к методу Выполнить(), которому в качестве параметра передаётся текст запроса, написанный на специальном языке запросов. Метод Выполнить() анализирует текст запроса, выполняет в соответствии с ним выборку данных и формирует временный выходной набор данных (выборку);
  • после этого организуется циклическая обработка сформированного временного набора данных (выборки) с целью получения требуемого отчёта.

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

НашЗапрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|СКЛАД = Регистр.ТоварныйЗапас.Склад;
|ТОВАР = Регистр.ТоварныйЗапас.Товар;
|КОЛИЧЕСТВО = Регистр.ТоварныйЗапас.Количество;
|Группировка ТОВАР Упорядочить По ТОВАР.Код;
|Группировка СКЛАД Упорядочить По СКЛАД.Код;
|Функция КОЛ = КонОст(КОЛИЧЕСТВО);
|"
;

Если НашЗапрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Структура временного набора данных, созданная запросом НашЗапрос после его выполнения, представлена на следующем рисунке.

Структура временного набора данных

После выполнения запроса в программе можно использовать полученный временный набор данных. Изначально объект НашЗапрос спозиционирован на первой записи временного набора данных, где содержится общий итог по запросу. Поэтому общие итоги по запросу можно использовать сразу же после выполнения запроса.

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

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

Продолжение примера:

 . . .
Пока НашЗапрос.Группировка("Товар") = 1 Цикл
   
    . . .
КонецЦикла;

 . . .

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

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

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

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

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

Продолжение примера:

 . . .
Пока НашЗапрос.Группировка("Товар") = 1 Цикл
   
    . . .
   Пока НашЗапрос.Группировка("Склад") = 1 Цикл
      
       . . .
   КонецЦикла;
   
    . . .
КонецЦикла;

 . . .

После выхода из процедуры, где была определена переменная, содержащая объект типа "Запрос" (в нашем примере НашЗапрос) или после уничтожения объекта типа "Запрос" (Наш3апрос = 0;), временный набор данных на локальной машине пользователя уничтожается.

Из приведенного выше примера можно сделать несколько важных заключений:

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

Примера обработки запроса:

Пока Запрос.Группировка("Товар") = 1 Цикл
   Если (Запрос.Товар = НужныйТовар) Тогда
      Пока Запрос.Группировка("Отдел") = 1 Цикл
         Если (Запрос.Отдел = НужныйОтдел) Тогда
            Пока Запрос.Группировка("Сотрудник") = 1 Цикл
               Если (Запрос.Сотрудник = НужныйСотрудник) Тогда
                  Пока Запрос.Группировка("Док") = 1 Цикл
                     Док = Запрос.Док;
                     Если Запрос.ПрихКол <> 0 Тогда
                        Таб.ВывестиСекцию("Приход");
                     ИначеЕсли Запрос.РасхКол <> 0 Тогда
                        Приращение = Запрос.РасхКол;
                        Таб.ВывестиСекцию("Расход");
                     КонецЕсли;
                  КонецЦикла;
               КонецЕсли;
            КонецЦикла;
         КонецЕсли;
      КонецЦикла;
   КонецЕсли;
КонецЦикла;

Атрибуты запросов

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

Методы запросов

Выполнить запрос позволяет метод Выполнить() (англоязычный синоним — Execute()). Он анализирует описание, содержащееся в тексте запроса, выполняет выборку данных, формирует временный выходной набор данных (выборку) и вычисляет значения функций запроса. Возвращаемым значением метода является число 1, если запрос выполнен успешно, или 0, если зафиксирована ошибка при выполнении запроса (синтаксическая или времени выполнения).

Синтаксис метода:

Выполнить(<ТекстЗапроса>)

где <ТекстЗапроса> — строковое выражение, содержащее текст запроса на языке запросов.

Пример использования:

Процедура Сформировать()
   
   ЖР = СоздатьОбъект("ЖурналРасчетов.Зарплата");
   _Дата = ЖР.НачалоТекущегоПериода();
   
   Запрос = СоздатьОбъект("Запрос");
   ЗапросКат = СоздатьОбъект("Запрос");
   флаг1 = Запрос.Выполнить(
   "//({ЗАПРОС(Двойной)
   |Период с _Дата по _Дата;
   |Оклад = Справочник.Сотрудники.Оклад;
   |Пдр = Справочник.Сотрудники.МестоРаботы.Владелец;
   |Ктг = Справочник.Сотрудники.Категория;
   |Условие((Ктг.Выбран() = 1) И (Пдр.Выбран() = 1));
   |Группировка Пдр без групп;
   |Группировка Ктг без групп;
   |Функция Всего = Сумма(Оклад);
   |"
   );
   Флаг2 = ЗапросКат.Выполнить(
   "//{{ЗАПРОС(Одинарный)
   |Период с _Дата по _Дата;
   |Оклад = Справочник.Сотрудники.Оклад;
   |Ктг = Справочник.Сотрудники.Категория;
   |Условие(Ктг.Выбран() = 1);
   |Группировка Ктг без групп;
   |Функция Всего = Сумма(Оклад);
   |"
   );
   
   Если ((Флаг1 = 0) ИЛИ (Флаг2 = 0)) Тогда
      Сообщить("Ошибка в запросе!");
      Возврат;
   КонецЕсли;
   
   Таб = СоздатьОбъект("Таблица");
   
   Таб.ВывестиСекцию("Документ<|ДокументВерт<");
   Пока ЗапросКат.Группировка("Ктг") = 1 Цикл
      Таб.ПрисоединитьСекцию("Документ<|Осн2");
   КонецЦикла;
   Таб.ПрисоединитьСекцию("Документ<|ДокументВерт>");
   
   Таб.ВывестиСекцию("КолонТитул|ДокументВерт<");
   Пока ЗапросКат.Группировка("Ктг") = 1 Цикл
      Таб.ПрисоединитьСекцию("КолонТитул|Осн2");
   КонецЦикла;
   Таб.ПрисоединитьСекцию("КолонТитул|ДокументВерт>");
   Продолжать = 1;
   Пока Запрос.Группировка("Пдр") = 1 Цикл
      
      Таб.ВывестиСекцию("Осн1|ДокументВерт<");
      Далее = 1;
      Пока Продолжать = 1 Цикл
         
         СлКат = ЗапросКат.Группировка("Ктг");
         Если Далее = 1 Тогда
            ОК = Запрос.Группировка("Ктг");
         КонецЕсли;
         Если СлКат = 0 Тогда
            Прервать;
         КонецЕсли;
         Если ЗапросКат.Ктг = Запрос.Ктг Тогда
            Таб.ПрисоединитьСекцию("Осн1|Осн2");
            Далее = 1;
         Иначе
            Таб.ПрисоединитьСекцию("Осн1|Пусто");
            Далее = 0;
         КонецЕсли;
      КонецЦикла;
      Таб.ПрисоединитьСекцию("Осн1|ДокументВерт>");
   КонецЦикла;
   
   Таб.ВывестиСекцию("Документ>|ДокументВерт<");
   Пока ЗапросКат.Группировка("Ктг") = 1 Цикл
      Таб.ПрисоединитьСекцию("Документ>|Осн2");
   КонецЦикла;
   Таб.ПрисоединитьСекцию("Документ>|ДокументВерт>");
   
   Таб.Опции(0, 0, 0, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("Результат", );
КонецПроцедуры

Установить режим использования графы отбора в запросе позволяет метод ИспользоватьГрафуОтбора() (англоязычный синоним — UseSelectionColumn()). Если метод не используется — по умолчанию устанавливается автоматический выбор графы отбора. Возвращаемым значением метода является строковое значение — идентификатор использованной реально графы отбора, если метод вызывается после выполнения запроса.

Синтаксис метода:

ИспользоватьГрафуОтбора(<ГрафаОтбора>)

где <ГрафаОтбора> — строковое выражение — идентификатор графы отбора, как он задан в Конфигураторе. Данный параметр устанавливает режим использования определённой графы отбора. Возможными значениями параметра также являются:

  • "*" — автоматический выбор графы отбора;
  • "" (пустая строка) — не использовать графу отбора.

Пример использования:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(ОбработкаДок)
|Период с '01.10.96' по '05.10.96';
|ОбрабатыватьДокументы Все;
|Тов = Документ.РасхНакл.Товар;
|Клиент = Документ.РасхНакл.Клиент;
|Группировка Клиент;
|Группировка Тов;
|Группировка Документ;
|"
;

Запрос.ИспользоватьГрафуОтбора("Клиент");
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Организовать цикла получения данных из выборки, сформированной в результате работы метода Выполнить(), позволяет метод Группировка() (англоязычный синоним — Group()). Метод позиционирует в выборке очередную строку в порядке, определённом параметром <Группировка>. Нельзя использовать метод Группировка(), задавая в качестве параметра младшие группировки, не использовав предварительно этот метод для позиционирования по старшим группировкам. Старшинство группировок определяется порядком их следования в тексте запроса.

Синтаксис метода:

Группировка(<Группировка>, <Направление>)

где

  • <Группировка> — выражение, содержащее порядковый номер или имя группировки;
  • <Направление> — необязательный параметр — числовое выражение, определяющее направление выборки. Возможные значения:
    • 1 — выборка значений группировки по возрастанию (значение по умолчанию);
    • -1 (минус единица) — выборка значений группировки по убыванию.

Возвращаемым значением метода является число 1, если получено следующее значение выборки запроса, или 0, если нет.

Пример использования:

Процедура Сформировать()
   Перем Запрос, ТекстЗапроса;
   Если (Число(ДатаНач) = 0) ИЛИ (Число(ДатаКон) = 0) Тогда
      Предупреждение("Не задан период!");
      Возврат;
   КонецЕсли;
   
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса =
   "//{{ЗАПРОС(Сформировать)
   |с ДатаНач по ДатаКон;
   |Рез = ЖурналРасчетов.Зарплата.Результат;
   |Сотр = ЖурналРасчетов.Зарплата.Объект;
   |Группировка Сотр без групп;
   |Группировка ПериодЖурнала;
   |Функция Сум = Сумма(Рез);
   |"
   ;
   Если Сотрудник.Выбран() = 1 Тогда
      ТекстЗапроса = ТекстЗапроса + "Условие(Сотр = Сотрудник);";
   КонецЕсли;
   
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   
   Таб = СоздатьОбъект("Таблица");
   
   Пока Запрос.Группировка("Сотр") = 1 Цикл
      
      Таб.ВывестиСекцию("Сотр<");
      Пока Запрос.Группировка("ПериодЖурнала") = 1 Цикл
         
         Таб.ВывестиСекцию("Мес");
      КонецЦикла;
      Таб.ВывестиСекцию("Сотр>");
   КонецЦикла;
   
   Таб.Опции(0, 0, 0, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("Результат", );
КонецПроцедуры

Выделить строки временного набора данных, которые являются группой справочника, позволяет метод ЭтоГруппа() (англоязычный синоним — IsItAGroup()). Возвращаемым значением метода является число 1, если текущая строка выборки (временного набора данных, сформированного в результате выполнения запроса) является группой справочника, или 0, если это обычный элемент справочника.

Синтаксис метода:

ЭтоГруппа(<ИмяГруппировки>)

где <ИмяГруппировки> — выражение, содержащее порядковый номер или имя группировки.

Пример использования:

Пока (Запр.Группировка("Товар") = 1) И (Запр.ЭтоГруппа("Товар") = 0) Цикл
    . . .
КонецЦикла;

Получить дату начала периода запроса позволяет метод НачалоПериода() (англоязычный синоним — BeginOfPeriod()). Если в тексте запроса указана одна из предопределённых группировок типа период ("Год", "Месяц", "День" и т.д.), то при обработке этой и вложенных в неё группировок метод НачалоПериода() будет возвращать начало периодов текущих значений этих группировок. Параметры у метода отсутствуют.

Пример использования:

ДатаНачала = Запрос.НачалоПериода();

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

Пример использования:

ДатаКонца = Запрос.КонецПериода();

Осуществить прямое позиционирование на запись в выборке по конкретным значениям группировок позволяет метод Получить() (англоязычный синоним — Get()). Количество параметров метода зависит от количества группировок в запросе. Можно пропускать значения одной или нескольких последних группировок, в этом случае метод позиционируется на запись, которая будет содержать итоговые значения для указанных группировок. Пропускаемые при вызове метода последние значения группировок должны заменяться запятыми. Если при вызове метода опущены все параметры, то выборка позиционируется на самое начало временного набора данных, на строку итогов. Возвращаемым значением метода является число 1, если запись найдена, или 0 – если нет.

После выполнения метода Получить() может осуществляться дальнейший обход выборки вызовами метода Группировка().

Синтаксис метода:

Получить(<ЗначениеГруппировки1>, ..., <ЗначениеГруппировкиN>)

где <ЗначениеГруппировки1>,, <ЗначениеГруппировкиN> — выражения, содержащие значения группировок запроса.

Пример использования:

Текст3апроса = "
| ...
|Группировка Должность;
|Группировка Категория;
| ...
|";

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;
Если Запрос.Получить(ВыбДолжн, ВыбКатег) = 0 Тогда
   Если Запрос.Получить(ВыбДолжн, ) = 0 Тогда
       . . .
   КонецЕсли;
КонецЕсли;

Осуществить прямое позиционирование на начало выборки позволяет метод ВНачалоВыборки() (англоязычный синоним — ToSelectionBegin()). Например, если необходимо перейти на верхний уровень группировок, чтобы затем организовать проход группировки первого уровня (в любом направлении), следует использовать метод ВНачалоВыборки(). Возвращаемым значением метода является число 1, если операция выполнена успешно, или 0 – если нет. Параметры у метода отсутствуют.

Пример использования:

Текст3апроса = "
| ...
|Группировка Должность;
|Группировка Категория;
| ...
|";

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;
Если Запрос.Получить(ВыбДолжн, ВыбКатег) = 0 Тогда
   Если Запрос.Получить(ВыбДолжн, ) = 0 Тогда
       . . .
   КонецЕсли;
КонецЕсли;
Запрос.ВНачалоВыборки();
Пока Запрос.Группировка(1, -1) Цикл
    . . .
КонецЦикла;

Получить значение поля упорядочивания из временной выборки запроса, не обращаясь к базе данных, позволяет метод ЗначениеУпорядочивания() (англоязычный синоним — OrderValue()).

Примечание: Если в тексте запроса для данной группировки не используется конструкция "Упорядочить по", то в этом случае действует упорядочивание по умолчанию:

  • для справочников — зависит от основного представления при описании справочника в Конфигураторе (код или наименование);
  • для документов — дата и время создания документа.

Синтаксис метода:

ЗначениеУпорядочивания(<Группировка>, <Упорядочив>)

где

  • <Группировка> — выражение, содержащее значение номера или имени группировки (номер работает быстрее);
  • <Упорядочив> — необязательный параметр. Порядковый номер параметра упорядочивания указанной группировки. Значение по умолчанию — 1.

Пример использования:

Текст3апроса = "
|ВидРаб = Документ.Наряд.ВидРаботы;
|Сотр = Документ.Наряд.Сотрудник;
|Группировка ВидРаб
|Упорядочить По ВидРаб.Код, ВидРаб.Стоимость;
|Группировка Сотр;
|";
 . . .

Запрос.ЗначениеУпорядочивания("ВидРаб", 2);

Запрос.ЗначениеУпорядочивания(2, 1);

Получить значение атрибута запроса по его имени позволяет метод ПолучитьАтрибут() (англоязычный синоним — SetAttrib()).

Синтаксис метода:

ПолучитьАтрибут(<ИмяАтрибута>)

где <ИмяАтрибута> — строковое выражение, содержащее имя любого атрибута запроса.

Пример использования:

Текст3апроса = "
|ВидРаб = Документ.Наряд.ВидРаботы;
|Сотр = Документ.Наряд.Сотрудник;
|Группировка ВидРаб
|Упорядочить По ВидРаб.Код, ВидРаб.Стоимость;
|Группировка Сотр;
|";
 . . .

Запрос.ПолучитьАтрибут("ВидРаб");

Запрос.ПолучитьАтрибут("Сотр");

Выгрузить результаты запроса в указанную таблицу значений позволяет метод Выгрузить() (англоязычный синоним — Unload()). Возвращаемым значением метода является число 1, если выгрузка произошла успешно, иначе – 0.

Синтаксис метода:

Выгрузить(<ТаблЗнач>, <Флаг>, <Итоги>)

где

  • <ТаблЗнач> — таблица значений, куда выгружаются результаты запроса;
  • <Флаг> — необязательный параметр. Число:
    • 0 — значения групп и функций (значение по умолчанию);
    • 1 — значения групп и функций, дополнительных переменных;
    • 2 — значения упорядочиваний групп и функций;
    • 3 — значения упорядочиваний групп и функций, дополнительных переменных;

    или строка типа "Товар(1), Товар(2), Товар, Склад, Приход, Расход", где Товар(1) — значение первого упорядочивания группировки "Товар" и т.д.

  • <Итоги> — необязательный параметр. Число:
    • 0 — итоги по группировкам не выводить;
    • 1 — итоги по группировкам выводить сверху (значение по умолчанию);
    • 2 — итоги по группировкам выводить снизу;
    • 3 — итоги по группировкам выводить сверху и снизу.

Пример использования:

Текст3апроса = "
| ...
|Группировка Должность;
|Группировка Категория;
| ...
|";

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;
ТаблЗнач = Создать("ТаблицаЗначений");
Запрос.Выгрузить(ТаблЗнач, 0, 0);

Введение в язык запросов

Язык запросов предназначен для описания запросов к документам, справочникам, регистрам, журналам расчётов, планам счетов, бухгалтерским операциям и проводкам. Текст описания запроса передается методу Выполнить() в качестве параметра. В результате выполнения этого метода генерируется временный выходной набор данных, который в дальнейшем используется для заполнения формы отчёта.

Формат текста описания запроса

Текст описания запроса на языке запросов состоит из последовательности операторов. Концом оператора является символ «;» (точка с запятой). Операторы могут записываться в любом порядке, однако, следует помнить, что интерпретатор языка запросов однопроходный, следовательно, сначала следует описать переменную, и только потом её использовать в операторах Группировка, Функция или Условие.

Пример:

Текст3апроса =
"//({ЗАПРОС(РасчЛистки)
|  // Задаем интервал запроса
|Период с ДатаНач по ДатаКон;
|  // Определяем внутренние переменные
|Рез = ЖурналРасчетов.Зарплата.Результат;
|Расч = ЖурналРасчетов.Зарплата.ВидРасч;
|Дни = ЖурналРасчетов.Зарплата.Дни;
|Сотр = ЖурналРасчетов.Зарплата.Объект;
|  // Назначаем группировки
|Группировка Сотр без групп;
|Группировка Расч;
|  // Назначаем функции
|Функция Сум = Сумма(Рез);
|Функция Дней = Сумма(Дни);
|  // Назначаем условие
|Условие(Рез <> 0);
|"
;
 . . .

Как видно из вышеприведённого примера, в тексте запроса, также как и в остальном программном коде, допускается использование комментариев. Комментарий в тексте описания запроса начинается парой символов слэша (//) и заканчивается концом строки.

Соглашения и обозначения, используемые при описании языка

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

  • [] — в квадратные скобки заключаются необязательные синтаксические элементы;
  • []+ — в квадратные скобки со знаком «+» заключаются обязательные синтаксические элементы, которые могут использоваться один или более раз;
  • []* — в квадратные скобки со знаком «*» заключаются необязательные синтаксические элементы, которые могут использоваться один или более раз;
  • () — круглые скобки заключают в себе список параметров;
  • | — вертикальной линией разделяются синтаксические элементы, среди которых нужно выбирать один и только один.

Зарезервированные слова языка запросов

Ключевые слова — это слова, которые используются в языке запросов для обозначения встроенных операторов. Приведённые далее ключевые слова являются зарезервированными и не могут использоваться в качестве имён внутренних переменных описания запросов. Каждое ключевое слово имеет два представления — русское и английское. Английское представление является традиционным для языков программирования. Ключевые слова в русском и английском представлении могут свободно смешиваться в одном исходном тексте. Регистр букв ключевых слов не имеет значения, то есть они могут быть набраны в любом регистре, например: Функция, ФУНКЦИЯ, фУНКЦИЯ.

Ниже приведен полный список зарезервированных слов языка запросов в обоих представлениях:

  • Без (Without)
  • Год (Year)
  • Групп (Groups)
  • Группировка (Group)
  • День (Day)
  • Документ (Document)
  • И (And)
  • ИЛИ (Or)
  • Квартал (Quarter)
  • Когда (When)
  • Месяц (Month)
  • Неделя (Week)
  • НомерСтроки (LineNum)
  • Обрабатывать (Process)
  • ОбрабатыватьДокументы (ProcessDocuments)
  • ОбрабатыватьОперации (PrосessOperations)
  • Период (Period)
  • ПериодЖурнала (JournalPeriod)
  • По (By)
  • По (Till)
  • С (From)
  • СтрокаДокумента (DocumentLine)
  • Упорядочить (Order)
  • Условие (Condition)
  • Функция (Function)

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

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

Числовая константа описывается следующей синтаксической диаграммой:

[+|-][0-9]+ | [0-9]*.[0-9]+

Пример числовых констант:

-17
43.712
.43842

Строковая константа — это строка, заключенная в двойные кавычки. Она не может быть многострочной.

Пример строковой константы:

"Это текстовая константа"

Константа типа "Дата" задаётся в виде строки, заключённой в одинарные кавычки, в формате 'ДД.ММ.ГГ' или 'ДД.ММ.ГГГГ'.

Примеры констант типа "Дата":

'21.05.96'
'25.09.1964'

Внутренние переменные

Внутренние переменные — это переменные, объявленные в тексте описания запроса. Именем переменной может быть любая последовательность букв, цифр и символов подчёркивания (_), начинающаяся с буквы или знака подчёркивания. Имена внутренних переменных не должны совпадать с зарезервированными словами языка запросов. Распознавание имён переменных, названий операторов, процедур и функций ведётся без учёта регистра букв.

Примеры имён переменных:

_43842
НачПериода

Примеры использования переменных:

Сотр = НовЗапрос.Сотр;
Кат = НовЗапрос.Кат;
ИТОГ = НовЗапрос.Итого;

Конкретизация переменной

Конкретизация переменной — это уточнение описания внутренней переменной, если это возможно в текущем контексте. Конкретизации переменной могут использоваться в языке запросов в операторах Группировка ... Упорядочить По и в качестве аргумента оператора Функция.

Синтаксис:

<ВнутренняяПеременная>[.<Путь>]+

где

  • <ВнутренняяПеременная> — идентификатор объявленной ранее внутренней переменной;
  • <Путь> — доступный атрибут внутренней переменной или конкретизации переменной (см. ниже «Атрибуты, доступные при описании внутренних переменных»).

Пример использования:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
" //{{ЗАПРОС(ОбработкаДок)
|Период с '01.10.96' по '05.10.96';
|ОбрабатыватьДокументы Все;
|Тов = Справочник.Товары.ТекущийЭлемент, Документ.РасхНакл.Товар;
|  // используем конкретизацию внутренней переменной Тов
|Группировка Тов Упорядочить По Тов.Наименование;
|Группировка Документ;
|Группировка СтрокаДокумента;
|"
;

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Внимание! Запрос не манипулирует величинами типа "Строка неограниченной длины".

Внешние переменные

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

Пример использования:

Перем ДатаНач, ДатаКон;

Процедура Сформировать()
   Если (Число(ДатаНач) = 0) ИЛИ (Число(ДатаКон) = 0) Тогда
      Предупреждение("Не задан период!");
      Возврат;
   КонецЕсли;
   
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса =
   "//{{ЗАПРОС(Сформировать)
   |  // используем внешние переменные ДатаНач и ДатаКон
   |с ДатаНач по ДатаКон;
   |Рез = ЖурналРасчетов.Зарплата.Результат;
   |Сотр = ЖурналРасчетов.Зарплата.Объект;
   |Группировка Сотр без групп;
   |Группировка ПериодЖурнала;
   |Функция Сум = Сумма(Рез);
   |"
   ;
   
   Если ВыбСотр.Выбран() = 1 Тогда
      ТекстЗапроса = ТекстЗапроса + "Условие(Сотр = ВыбСотр);";
   КонецЕсли;
   
   Если Запрос.Выполнить(ТекстЗапр) = 0 Тогда
      Возврат;
   КонецЕсли;
    . . .
КонецПроцедуры

Атрибуты, доступные при описании внутренних переменных

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

  • Документ (Document) — данные документов;
  • Справочник (Reference) — данные справочников;
  • Регистр (Register) — данные регистров;
  • ЖурналРасчетов (CalcJournal) — данные журналов расчёта;
  • Счет (Account) — данные счетов;
  • Операция (Operation) — данные бухгалтерских операций и проводок.

Эти названия являются первыми в пути описания переменных. В качестве атрибутов допускается использовать любые реквизиты, которые заданы для них в Конфигураторе в дереве метаданных (реквизиты для справочников, документов и журналов расчётов; измерения и ресурсы для регистров). Кроме этих атрибутов, разрешён так же доступ к следующим предопределённым атрибутам:

  • Доступные атрибуты объектов типа "Документ":
    • ВремяДок (DocTime) — время документа;
    • ДатаДок (DocDate) — дата документа;
    • НомерДок (DocNum) — номер документа;
    • НомерСтроки (LineNum) — номер строки документа;
    • ТекущийДокумент (CurDocument) — значение текущего документа.
  • Доступные атрибуты объектов типа "Справочник":
    • Родитель (Parent) — родитель элемента многоуровневого справочника;
    • Владелец (Owner) — владелец подчиненного справочника;
    • Код (Code) — код элемента справочника;
    • Наименование (Description) — наименование элемента справочника;
    • ТекущийЭлемент (CurItem) — значение текущего элемента справочника.
  • Доступные атрибуты объектов типа "Регистр":
    • НомерСтроки (LineNum) — номер строки документа, выполнившего движение регистра (в случае, когда в Модулях документов в конфигурации перед движением регистра использовали метод ПривязыватьСтроку);
    • ТекущийДокумент (CurDocument) — значение документа, выполнившего движение регистра.
  • Доступные атрибуты объектов типа "ПланСчетов":
    • БезКорреспонденций (IsSingle) — флаг того, что элемент плана счетов — забалансовый;
    • Валютный (IsCurrency) — флаг валютного учёта элемента плана счетов;
    • Код (Code) — код элемента плана счетов;
    • Количественный (IsAmount) — флаг количественного учёта элемента плана счетов;
    • Наименование (Description) — наименование элемента плана счетов;
    • ТекущийСчет (CurAccount) — значение текущего счета плана счетов.
  • Доступные атрибуты объектов типа "Операция":
    • ВремяОперации (OperTime) — время операции;
    • ДатаОперации (OperDate) — дата операции;
    • Содержание (Description) — содержание операции;
    • СуммаОперации (OperSum) — сумма операции;
    • ТекущийДокумент (CurDocument — значение документа создавшего операцию.
  • Доступные атрибуты объектов типа "Проводка":
    • ВалСумма (CurSum) — валютная сумма проводки (для счетов с валютным учётом);
    • Валюта (Currency) — валюта проводки;
    • Количество (Amount) — количество проводки (для счетов с количественным учётом);
    • КорСчет (CorAccount) — корреспондирующий счёт. Корреспондирующим счетом, для которого является Счет;
    • Сумма (Sum) — сумма проводки;
    • Счет (Account) — счет, для обработки корреспонденции. Корреспондирующим счётом, для которого является КорСчет.

Примеры использования атрибутов:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
" //{{ЗАПРОС(Сформировать)
|Период с НачДата по КонДата;
|ДОКУМ = Документ.РасходнаяБН.ТекущийДокумент,
|   Документ.РасходнаяКредит.ТекущийДокумент,
|   Документ.РасходнаяНал.ТекущийДокумент,
|   Документ.РасходнаяРеализ.ТекущийДокумент,
|   Документ.Счет.ТекущийДокумент;
|Группировка ДОКУМ; //по документам
|"
;
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Печать)
|Товар = Справочник.Товары.ТекущийЭлемент;
|Группировка Товар Упорядочить по Товар.МинЗапас;
|"
;
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Период с НачДата по КонДата;
|ВидТоплива = Регистр.ПокупателиКолво.ВидыТоплива;
|Вес = Регистр.ПокупателиКолво.Кг;
|Покуп = Регистр.ПокупателиКолво.Покупатели;
|Док = Регистр.ПокупателиКолво.ТекущийДокумент;
|Ном = Регистр.ПокупателиКолво.НомерСтроки;
|Группировка ВидТоплива; //по измерению Регистра
|Группировка Док; // по документам, двигавшим Регистр
|Группировка Ном; // по номерам строк документов
|Функция ВсегоКолво = КонОст(Вес);
|Функция ПриходКолво = Приход(Вес);
|Условие(Покуп = ВыбПокупатель);
|"
;

Правила объявления внутренних переменных

Внутренние переменные используются в тексте запроса для образования ссылок на объекты конфигурации, чтобы использовать их при построении таких операторов запроса, как Группировка, Функция, Условие.

Синтаксис объявления внутренней переменной:

<ИмяПеременной> = <ОписаниеПеременной> [, <ОписаниеПеременной>]+;

где

  • <ИмяПеременной> — имя объявляемой внутренней переменной описания запроса;
  • <ОписаниеПеременной> — ссылка, указывающая на доступный в языке запросов атрибут документа, справочника, регистра или журнала расчётов (см. выше «Атрибуты, доступные при описании внутренних переменных»).

В объявлении внутренней переменной можно указывать несколько вариантов описания переменной. Все описания должны указывать на один и тот же тип данных (число, строку, справочник или документ). Переменной, указывающей на разные справочники или документы, присваивается тип данных "Справочник неопределённого вида" или "Документ неопределённого вида" соответственно.

Например, можно определить внутреннюю переменную:

Товар = Документ.Перемещение.Товар, Документ.Расходная.Товар;

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

Еще пример. Допустим, у нас есть регистр Взаиморасчеты и регистр Кредиты, и в том и в другом есть измерение Клиент. Определяем внутреннюю переменную:

Должник = Регистр.Взаиморасчеты.Клиент, Регистр.Кредиты.Клиент;

Если использовать такую внутреннюю переменную для образования группировки, то она будет означать следующее: пройти по регистру Взаиморасчеты и по регистру Кредиты, вычислить заданные в запросе функции и выбрать значения клиентов, для которых значения хотя бы одной функции будет ненулевой. Здесь мы видим, что формирование запроса по регистрам имеет некоторые особенности (обязательно наличие функций, причём их вычисленные значения должны быть отличны от нуля, только в этом случае найденные объекты включаются во временный набор данных формируемый запросом).

Внимание! Если при описании внутренней переменной указать на разные типы данных, например, на "Справочник" и на "Документ", то это просто вызовет сообщение об ошибке. Например, следующее определение внутренней переменной будет ошибочным:

ААА = Справочник.Товары.ТекущийЭлемент, Документ.Счет.ТекущийДокумент;   

Однако допускается в описании внутренней переменной указание на разные справочники либо на разные документы. Переменной, указывающей на разные справочники или документы, присваивается тип данных "Справочник неопределённого вида" или "Документ неопределённого вида" соответственно. Например, правомерно задать такую внутреннюю переменную:

Парам = Документ.Счет.Клиент, Документ.Счет.Фирма;

(Здесь предполагается, что в контексте конфигурации, реквизиты Клиент и Фирма — это элементы справочников). Если использовать такую внутреннюю переменную для построения группировки, то она будет означать следующее: пройти по документам Счет и выбрать значения клиентов и фирм, встречающихся в них (и, например, упорядочить эти элементы по наименованию). Как интерпретировать результаты полученной выборки при таком запросе — будет зависеть от контекста поставленной задачи.

Особенности описания внутренних переменных для типов "Операция" и "Проводка"

В языке запросов описание внутренних переменных для агрегатных типов данных типа "Операция" и "Проводка" начинается со слова «Операция» вне зависимости от того, будет ли обращение к бухгалтерским операциям или к проводкам. Описание переменной определяется следующим образом:

Операция.(
   <Реквизиты0перации>
   |  <ПредРеквОпераций>
   |  <РеквизитыПроводок>
   |  <ПредРеквПроводок>
   |  Дебет. ( Счет | <Субконто> )
   |  Кредит. ( Счет | <Су6конто> )
   |  Субконто.<ВидСубконто>
   |  КорСубконто.<ВидСубконто>
)

где

  • <Реквизиты0перации> — реквизиты операции, объявленные в метаданных;
  • <ПредРеквОпераций> — предопределённые реквизиты операций;
  • <РеквизитыПроводок> — реквизиты проводок, объявленные в метаданных;
  • <ПредРеквПроводок> — предопределённые реквизиты проводок;
  • <ВидСубконто> — идентификатор вида субконто.

Применение слов «Дебет», «Кредит» в описании переменных позволяют оперировать дебетовой и кредитовой частями проводки, такими как счёт и вид субконто. Применение слов «Субконто» и «КорСубконто» в описании переменных позволяют оперировать как субконто, так и корреспондирующим субконто.

Пример:

Сум = Операция.Сумма;
Сч = Операция.Дебет.Счет, Операция.Кредит.Счет;

О дополнительных именах доступа

Несколько слов о дополнительных именах доступа к стандартной информации, которые определены в языке запросов. Речь идёт о конструкции ТекущийЭлемент для справочников и ТекущийДокумент для документов и регистров (не надо путать эти конструкции языка запросов с одноимёнными методами встроенного языка, хотя их смысл во многом совпадает).

Для справочников использование конструкции ТекущийЭлемент в описании внутренней переменной означает выборку элемента справочника как такового (целиком всей записи справочника).

Аналогично при работе с документами, использование конструкции ТекущийДокумент в описании внутренней переменной, означает выборку документа как такового (целиком всего документа как объекта конфигурации). Сравните два примера, приведённых ниже.

Пример 1. Здесь нас интересуют товары, встречающиеся в документах:

ТОВАР = Документ.РасходнаяБН.Товар, 
   Документ.РасходнаяКредит.Товар,
   Документ.РасходнаяНал.Товар,
   Документ.РасходнаяРеализ.Товар,
   Документ.Счет.Товар;

Пример 2. Здесь нас интересуют сами документы указанных видов как таковые:

ДОКУМ = Документ.РасходнаяБН.ТекущийДокумент, 
   Документ.РасходнаяКредит.ТекущийДокумент,
   Документ.РасходнаяНал.ТекущийДокумент,
   Документ.РасходнаяРеализ.ТекущийДокумент,
   Документ.Счет.ТекущийДокумект;

Использование для документов конструкции НомерСтроки в описании внутренней переменной, означает выборку номеров строк документов (не самих строк, а чисел, обозначающих номера строк в документе):

СТРОКА = Документ.РасходнаяБН.НомерСтроки;

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

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

Пример:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Период с НачДата по КонДата;
|ВидТоплива = Регистр.ПокупателиКолво.ВидыТоплива;
|Покуп = Регистр.ПокупателиКопво.Покупатели;
|Док = Регистр.ПокупателиКолво.ТекущийДокумент;
|Ном = Регистр.ПокупателиКолво.НомерСтроки;
|Вес = Регистр.ПокупателиКолво.Кг;
|Группировка ВидТоплива; // по измерению Регистра
|Группировка Док; //по документам, двигавшим Регистр
|Группировка Ном; // по номерам строк документов
|Функция ВсегоКолво = КонОст(Вес);
|Функция ПриходКолво = Приход(Вес);
|Условие(Покуп = Покупат);
|"
;

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

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

Операторы языка запросов

Установить интервал дат формирования запроса позволяет оператор Период С ... По (англоязычный синоним — Period From ... Till). Если в описании запроса оператор Период С ... По опущен, то интервал дат формирования запроса устанавливается в точку актуальности итогов (ТА) (или на рабочую дату, если не установлена компонента «Оперативный учет»), запрос формируется только на этот момент времени.

Использование данного оператора актуально только в том случае, если запрос строится для выборки данных по регистрам, журналам расчётов и/или документам. Здесь указывается, в каком интервале выбирать движения регистров и/или подборку документов. При выполнении запроса только по справочникам эта секция не играет никакой роли.

Синтаксис оператора:

[[Период] С <Дата>|<ВнешПеременная> [По <Дата>|<ВнешПеременная>];]

где

  • <Дата> — константа типа "Дата", "Документ" или позиция документа;
  • <ВнешПеременная> — внешняя переменная типа "Дата", "Документ" или позиция документа. Если указан документ, то за момент времени принимается дата и время документа;
  • По — добавочное ключевое слово для связки первой части команды со второй, необязательной частью.

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

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
 . . .
|Счет = Регистр.Cash.Счет;
|Статья = Регистр.Cash.Статья;
|СуммаЭквивалента2 = Регистр.Cash.СуммаЭквивалента2;
|СуммаЭквивалента1 = Регистр.Cash.СуммаЭквивалента1;
 . . .

Если ДатаКонца >= ПолучитьДатуТА() Тогда
   ТекстЗапроса = ТекстЗапроса + "Период с ДатаНачала;";
Иначе
   ТекстЗапроса = ТекстЗапроса + "Период с ДатаНачала по ДатаКонца;";
КонецЕсли;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

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

Применение конструкции С ... По ... приводит к тому, что выборка записей из журнала расчётов проводится по времени действия записей журнала расчётов, определяемых реквизитами журнала расчётов ДатаНачала и ДатаОкончания, а не временем их ввода в журнал.

Примечание: Работа запроса с журналами расчётов, с использованием конструкции Период С ... По ..., аналогична выборке записей в журнале расчётов, организуемой при помощи метода журнала расчётов ВыбратьПериод(). С другой стороны, запрос, использующий конструкцию С ... По ..., аналогичен выборке, организуемой при помощи метода журнала расчётов ВыбратьЗаписи().

Пример 1:

Процедура РасчЛистки()
   Перем Запрос, Флаг;
   Перем ДатаНач, ДатаКон;
   ЖР = СоздатьОбъект("ЖурналРасчетов.Зарплата");
   ДатаНач = ЖР.НачалоТекущегоПериода();
   ДатаКон = ЖР.КонецТекущегоПериода();
   
   Запрос = СоздатьОбъект("Запрос");
   Флаг = Запрос.Выполнить(
   "//{{ЗАПРОС(РасчЛистки)
   |Период С ДатаНач По ДатаКон; // выборка по расчетным периодам!
   |Рез = ЖурналРасчетов.Зарплата.Результат;
   |Расч = ЖурналРасчетов.Зарплата.ВидРасч;
   |Дни = ЖурналРасчетов.Зарплата.Дни;
   |Сотр = ЖурналРасчетов.Зарплата.Объект;
   |Группировка Сотр без групп;
   |Группировка Расч;
   |функция Сум = Сумма(Рез);
   |функция Дней = Сумма(Дни);
   |Условие(Рез о 0);
   |"
   );
    . . .
КонецПроцедуры;

Пример 2:

Запрос = СоздатьОбъект("Запрос");

ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|С ДатаНач По ДатаКон;
|Рез = ЖурналРасчетов.Зарплата.Результат;
|Сотр = ЖурналРасчетов.Зарплата.Объект;
|ПЖ = ЖурналРасчетов.Зарплата.ПериодРегистрации;
|Группировка Сотр без групп;
|Группировка ПЖ;
|Функция Сум = Сумма(Рез);
|"
;
Флаг = Запрос.Выполнить(ТекстЗапроса);
 . . .

Назначить режим обработки документов в запросе позволяет оператор ОбрабатыватьДокументы (англоязычный синоним — ProcessDocuments). В операторе указывается, какими документами должен оперировать запрос: непроведёнными (NonTransacted), проведёнными (Transacted) или теми и другими (All). По умолчанию в запросе обрабатываются только проведённые документы.

Синтаксис оператора:

ОбрабатыватьДокументы [Непроведенные|Проведенные|Все];

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

Пример:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(ОбработкаДок)
|Период с '01.10.96' по '05.10.96';
|ОбрабатыватьДокументы Все;
|Тов = Справочник.Товары.ТекущийЭлемент, Документ.РасхНакл.Товар;
|Группировка Тов упорядочить по Тов.Наименование;
|Группировка Документ;
|Группировка СтрокаДокумента;
|"
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Назначить режим обработки бухгалтерских операций в запросе позволяет оператор ОбрабатыватьОперации (англоязычный синоним — ProcessOperations). В операторе указывается, какими операциями должен оперировать запрос: с включенными проводками (On), с выключенными проводками (Off) или теми и другими (All). По умолчанию в запросе обрабатываются только операции с включенными проводками.

Синтаксис оператора:

ОбрабатыватьОперации [Включенные|Выключенные|Все];

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

Пример:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(ОбработкаОпер)
|Период с '01.10.96' по '05.10.96';
|ОбрабатыватьОперации Все;
|Опер = Операция.ТекущийДокумент;
|Группировка Опер;
|"
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Назначить режим обработки помеченных на удаление объектов в запросе позволяет оператор Обрабатывать (англоязычный синоним — Process). В операторе указывается, какими объектами должен оперировать запрос: не помеченными на удаление (NonMarkedOnRemoving), помеченными на удаление (MarkedOnRemoving) или теми и другими (All). По умолчанию в запросе обрабатываются все объекты.

Синтаксис оператора:

Обрабатывать [ПомеченныеНаУдаление|НеПомеченныеНаУдаление|Все];

где ПомеченныеНаУдаление, НеПомеченныеНаУдаление, Все — указание, какие объекты следует обрабатывать.

Пример:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Обработка)
|Период с '01.10.96' по '05.10.96';
|Обрабатывать НеПомеченныеНаУдаление;
|Товар = Справочник.Товар.ТекущийЭлемент;
|Группировка Товар упорядочить по Товар.Наименование;
|"
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Вычислить указанный тип функции и присваивает её значение внутренней переменной позволяет оператор Функция (англоязычный синоним — Function).

Синтаксис оператора:

Функция <ИмяФункции> = <ТипФункции> (<Параметр>|<УточненныйПараметр>) [Когда (<Условие>)];

где

  • <ИмяФункции> — имя, которое присваивается функции. По этому имени можно в дальнейшем обращаться к значению вычисленной функции из вызывающего программного модуля как к атрибуту запроса. Данную внутреннюю переменную заранее объявлять не нужно. Она фактически неявно объявляется в операторе Функция;
  • <ТипФункции> — ключевое слово одной из встроенных функций языка (см. список типов ниже);
  • <Параметр> — имя объявленной ранее внутренней переменной, значение которой используется как параметр встроенной функции. В функциях Сумма, Среднее, Максимум, Минимум в качестве данного параметра возможно использование арифметического выражения в терминах встроенного языка «1С:Предприятие»;
  • <УточненныйПараметр> — конкретизация объявленной ранее внутренней переменной, значение которой используется как аргумент встроенной функции;
  • Когда (англ. When) — необязательное добавочное ключевое слово, использование которого в команде означает, что вычисление функции следует производить только при условии, когда заданное логическое выражение <Условие> истинно;
  • <Условие> — логическое выражение встроенного языка «1С:Предприятие». В логическом выражении могут участвовать как внутренние, так и внешние переменные запроса. Используется только после ключевого слова Когда.

Типы применяемых функций предопределены и могут быть следующими:

  • Сумма (Sum) — вычисляет сумму выбранных по запросу значений параметра*;
  • Среднее (Avg) — вычисляет среднее из выбранных по запросу значений параметра;
  • Минимум (Min) — вычисляет минимум из выбранных по запросу значений параметра;
  • Максимум (Мах) — вычисляет максимум из выбранных по запросу значений параметра;
  • Счётчик (Count) — подсчитывает количество записей, вошедших в выборку;
  • НачОст (BegRest) — вычисляет начальный остаток для выбранных по запросу значений параметра**;
  • КонОст (EndRest) — вычисляет конечный остаток для выбранных по запросу значений параметра**;
  • Приход (Debit) — вычисляет приход для выбранных но запросу значений параметра**;
  • Расход (Credit) — вычисляет расход для выбранных по запросу значений параметра**;
  • СНД (IDB) — вычисляет сальдо начальное дебетовое для выбранных по запросу значений параметра***;
  • СКД (FDB) — вычисляет сальдо конечное дебетовое для выбранных по запросу
    значений параметра***;
  • СНК (ICD) — вычисляет сальдо начальное кредитовое для выбранных по запросу значений параметра***;
  • СКК (FCD) — вычисляет сальдо конечное кредитовое для выбранных по запросу значений параметра***;
  • ДО (TD) — вычисляет дебетовые обороты для выбранных по запросу значений параметра***;
  • КО (TC) — вычисляет кредитовые обороты для выбран
    ных по запросу значений параметра***;
  • КорДО (CorTD) — вычисляет дебетовые обороты между корреспондирующим счетам или субконто для выбранных по запросу значений параметра****;
  • КорКО (CorTC) — вычисляет кредитовые обороты между корреспондирующим счетам или субконто для выбранных по запросу значений параметра****;

Примечания:

* Для ресурсов оборотных регистров допускается вызывать только тип функции "Сумма".

** Типы функций "НачОст", "КонОст", "Приход", "Расход" можно использовать только с параметрами, указывающими на ресурсы регистров остатков. Для ресурсов регистров остатков другие типы функций вызывать нельзя.

*** Функции "СНД", "СНК", "СКД", "СКК", "ДО", "КО" можно использовать только с реквизитами проводки: Сумма, Количество или ВалСумма.

**** Функции "КорДО" и "КорКО" можно использовать только с реквизитами проводки: Сумма, Количество или ВалСумма. Функции накапливают значения только тогда, когда в запросе есть обращение к реквизитам проводок Счет, КорСчет, Субконто или КорСубконто.

Примечание 5: В программном модуле, где используется запрос, <ИмяФункции> будет являться атрибутом запроса. При помощи данного атрибута можно обращаться к значению вычисленной в запросе функции.

Примечание 6: В функциях "Сумма", "Среднее", "Максимум", "Минимум" в качестве аргумента возможно использование арифметического выражения в терминах встроенного языка.

Пример:

 . . .
|КолВо = Документ.ВидДокумента.Количество;
|Цена = Документ.ВидДокумента.Цена;
|Функция Сум = Сумма(КолВо * Цена);
|Функция Макс = Максимум(Окр(КолВо) * Окр(Цена));
|Функция Средн = Среднее(ФункцияОпределеннаяВМодуле(КолВо, Цена));
 . . .

Другой пример:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//ЗАПРОС(Функции)
|Период с ДатаНач по ДатаКон;
|Оклад = Справочник.Сотрудники.Оклад;
|Подр = Справочник.Сотрудники.Подразделение;
|Ктг = Справочник.Сотрудники.Категория;
|Группировка Подр без групп;
|Группировка Ктг без групп;
|Функция Всего = Сумма(Оклад);
|Условие((Ктг.Выбран() = 1) И (Подр.Выбран() = 1));
|"
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;
 . . .
Итог = Запрос.Всего;
 . . .

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

Операторы функций в запросе можно опускать, тогда запрос просто не будет ничего вычислять, а просто во временный набор данных заносятся записи со значениями группировок. Однако это справедливо только для работы запросов по справочникам и по документам. При работе запроса по регистрам следует помнить, что в этом случае обязательно наличие функций, причём только в том случае, когда их вычисленные значения отличны от нуля (хотя бы одной из заданных функций), найденные объекты включаются во временный набор данных, формируемый запросом. Если при работе запроса по регистрам в тексте запроса операторы функций опущены, то программа не выдаст никакого сообщения об ошибке, добросовестно пройдет по всем группировкам, не вычислит никаких значений функций и, значит, ничего не запишет во временном файле.

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

В тексте запроса, при описании оператора Функция можно использовать необязательное ключевое слово Когда, использование которого в операторе означает, что вычисление функции следует производить только при условии, что значение логического выражения, заданного в параметре ключевого слова является "Истина". Синтаксис применяемого логического выражения полностью аналогичен синтаксису разрешённому к применению в операторах Условие.

Следует понимать, что не все функции внутри конкретной группировки запроса могут иметь чётко интерпретируемый смысл. Например, для группировки по документу движения регистра следующие функции

|Функция ПрихКол = Приход(Количество);
|Функция РасхКол = Расход(Количество);

имеют четкий смысл — приращения, сделанные документом при движении регистра. С другой стороны, в той же группировке следующие функции

|Функция НачКол = НачОст(Количество);
|Функция КонКол = КонОст(Количество);

явно не имеют смысла (в запросах по регистрам, обычно задают период запроса при помощи оператора Период C. Функция "НачКол" в данном примере должна по смыслу показывать остаток ресурса Количество на начальную дату запроса. Внутри группировки по документу вопрос: «Какой начальный остаток ресурса на дату 10.01.97?» по документу, проведённому, например, 13.01.97, не имеет смысла). Поэтому в таких ситуациях функция будет иметь нулевое значение.

Пример:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//ЗАПРОС(Функции)
|Период с ДатаОтчета;
|Товар = Регистр.КвотыТоваров.Товар;
|Отдел = Регистр.КвотыТоваров.Отдел;
|Сотрудник = Регистр.КвотыТоваров.Сотрудник;
|Партнер = Регистр.КвотыТоваров.Партнер;
|Док = Регистр.КвотыТоваров.ТекущийДокумент;
|Количество = Регистр.КвотыТоваров.КвотаТовара;
|Группировка Товар;
|Группировка Отдел;
|Группировка Сотрудник;
|Группировка Партнер;
|Группировка Док;
|Функция НачКол = НачОст(Количество);
|Функция ПрихКол = Приход(Количество);
|Функция РасхКол = Расход(Количество);
|Функция КонКол = КонОст(Количество);
|// Следующие Функции вычисляем только при определенных
|// условиях, чтобы получить отфильтрованные итоги
|Функция ПрихКолТов = Приход(Количество) Когда (Док.ФлагТовара = 1);
|Функция РасхКолТов = Расход(Количество) Когда (Док.ФлагТовара = 1);
|Функция ПрихКолОтд = Приход(Количество) Когда (Док.ФлагОтдела = 1);
|Функция РасхКолОтд = Расход(Количество) Когда (Док.ФлагОтдела = 1);
|Функция ПрихКолСотр = Приход(Количество) Когда (Док.ФлагСотрудника = 1);
|Функция РасхКолСотр = Расход(Количество) Когда (Док.ФлагСотрудника = 1);
|"
;

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Задать способ группировки информации и порядок её упорядочивания в запросе позволяет оператор Группировка (англоязычный синоним — Group). От способа группировки информации и порядка её упорядочивания в запросе зависит последующий порядок её выборки.

Синтаксис оператора:

Группировка <ИмяГруппировки>|<ПредопредГруппировка> [Упорядочить по <Порядок>[, <Порядок&#gt;]*]
            [Без Упорядочивания][Без Групп][Все [ВошедшиеВЗапрос]];

где

  • <ИмяГруппировки> — имя объявленной ранее внутренней переменной, по значению которой устанавливается порядок выборки. По этому имени можно в дальнейшем обращаться к значению группировки из вызывающего программного модуля как к атрибуту запроса;
  • <ПредопредГруппировка> — ключевое слово одной из встроенных предопределенных группировок языка запросов (см. список ниже). По этому имени можно будет обращаться к значению группировки из вызывающего программного модуля;
  • Упорядочить по (англ. Order By) — необязательное добавочное ключевое слово. Параметры, следующие за данным ключевым словом, определяют упорядочивание строк в группировке. По умолчанию документы упорядочиваются по дате и времени документов, справочники — по коду или наименованию, в зависимости от основного представления, заданного при описании справочника в Конфигураторе;
  • <Порядок> — используется только после ключевого слова Упорядочить по. Конкретизация внутренней переменной <ИмяГруппировки>, значение которой является параметром упорядочивания строк в группировке. Кроме того, в данном параметре можно использовать имя функции, объявленной в этом же запросе в операторе Функция;
  • Без Упорядочивания (англ. Without Order) — необязательное добавочное ключевое слово, которое преследует цель уменьшения времени формирования запроса, при условии, что ни упорядочивание, ни значения упорядочивания при использовании данного запроса не нужны;
  • Без Групп (англ. Without Groups) — необязательное добавочное ключевое слово, использование которого назначает вывод в запрос только простых элементов справочников (исключая группы). Используется только для группировок, построенных на основе внутренней переменной типа "Справочник";
  • Все (англ. All) — необязательное добавочное ключевое слово, действие которого зависит от типа внутренней переменной, на основе которой построена группировка. Используется только для группировок, построенных на основе внутренней переменной типа "Справочник", или для предопределённых группировок, задающих временной интервал (Год, Месяц, Квартал, Неделя, День). Для предопределённых временных группировок подразумевается, что в запрос будут включены любые значения данных (в том числе нулевые) в каждый заданный момент времени с даты начала запроса по дату конца запроса (интервал задаётся оператором Период С...). Для группировок по справочникам подразумевается, что в запрос будут включены любые значения данных (в том числе нулевые) для каждого допустимого элемента справочника;
  • ВошедшиеВЗапрос (англ. IncludedInQuery) — необязательное добавочное ключевое слово действие которого уточняет предыдущее ключевое слово Все. Использование данного слова подразумевает, что в каждую строку запроса будут включены значения данных (в том числе нулевые), для которых есть ненулевое значение хотя бы в одной строке запроса.

Предопределённые группировки могут быть следующими:

  • Документ (Document) — позволяет детализацию до каждого документа;
  • СтрокаДокумента (DocumentLine) — позволяет детализацию до каждой строки табличной части каждого документа;
  • День (Day), Неделя (Week), Месяц (Month), Квартал (Quarter), Год (Year) — группировки по дате, дают возможность накапливать значения по документам за конкретный период (на каждый день, неделю, месяц и т.д.). В запросе может присутствовать несколько группировок такого типа.

Замечание: В программном модуле, где используется запрос, имя <ИмяГруппировки> (или <ПредопредГруппировка>) будет являться атрибутом запроса. Кроме того, это имя используется в качестве параметра метода запросов Группировка().

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

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

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

По умолчанию, документы упорядочиваются в группировке по дате и времени документов, элементы справочников — в зависимости от основного представления, заданного при описании справочника в Конфигураторе (код или наименование). Однако критерий упорядочивания в группировке можно установить при помощи необязательного ключевого слова Упорядочить по. Параметры, следующие за данным ключевым словом, определяют упорядочивание строк в группировке.

С параметром упорядочивания связан специальный метод для доступа к значениям объекта "Запрос". Речь идет об использовании метода ЗначениеУпорядочивания(). В программном модуле, после того как запрос уже сформирован, мы можем при помощи этого метода получить значение поля упорядочивания из временного набора данных, не обращаясь к базе данных. Например, если у нас в запросе была группировка "Товар", а нам для формирования некоторого отчёта нужны значения наименований товаров, то эти наименования товаров можно получить двумя способами:

Наим = Запрос.Товар.Наименование;



Наим = Запрос.ЗначениеУпорядочивания("Товар", 1);

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

Пример:

Процедура Группировки()
   Перем Запрос, ТекстЗапроса;
   Перем ДатаНач, ДатаКон;
   ЖР = СоздатьОбъект("ЖурналРасчетов.Зарплата");
   ДатаНач = ЖР.НачалоТекущегоПериода();
   ДатаКон = ЖР.КонецТекущегоПериода();
   
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса =
   "//{{ЗАПРОС(Группировки)
   |Период с ДатаНач по ДатаКон;
   |Рез = ЖурналРасчетов.Зарплата.Результат;
   |Расч = ЖурналРасчетов.Зарплата.ВидРасч;
   |Дни = ЖурналРасчетов.Зарплата.Дни;
   |Сотр = ЖурналРасчетов.Зарплата.Объект;
   |Группировка Сотр без групп;
   |Группировка Расч;
   |Функция Сум = Сумма(Рез);
   |Функция Дней = Сумма(Дни);
   |Условие(Рез о 0);
   |"
   ;
   
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   
   Таб = СоздатьОбъект("Таблица");
   Пока Запрос.Группировка("Сотр") = 1 Цикл
      
      Таб.ВывестиСекцию("Сотр");
      Пока Запрос.Группировка("Расч") = 1 Цикл
         
         Таб.ВывестиСекцию("Расч");
      КонецЦикла;
   КонецЦикла;
   Таб.Опции(0, 0, 0, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("Результат", );
КонецПроцедуры

Увеличить скорости выполнения запроса, если итоговые записи при использовании запроса не нужны, позволяет оператор Без итогов (англоязычный синоним — Without Totals). Данный оператор языка запросов, даёт возможность не накапливать итоги по группировкам. Использовать данный оператор в тексте запроса имеет смысл, когда запрос строится не для формирования сложного отчёта, а например, для простой выборки значений из информационной базы для последующей их обработки.

В случае применения данного оператора в тексте запроса, при обходе результатов запроса применяется только один цикл обхода, используя метод объекта "Запрос" Группировка() без параметра.

Пример:

Запрос = СоздатьОбъект("Запрос");
Текст3апроса = "
 . . .
|Группировка Товар;
|Группировка Склад;
|Без Итогов;
|"
;
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
   Возврат;
КонецЕсли;

Пока Запрос.Группировка() = 1 Цикл
    . . .
КонецЦикла;

Примечание: Если в тексте запроса используется группировка по многоуровневому справочнику и не указано "Без Групп", то итоги по группам справочника будут накапливаться. Другими словами, если в запросе не нужны итоги по группам справочника, то в тексте запроса кроме использования оператора Без Итогов дополнительно следует в операторах Группировка ... использовать ключевое слово Без Групп.

Задать условие включения информации в запрос позволяет оператор Условие (англоязычный синоним — Condition). Если указанное в качестве параметра логическое выражение истинно, то информация включается в запрос, иначе нет.

Синтаксис оператора:

Условие(<ЛогическоеВыражение>);

где <ЛогическоеВыражение> — логическое выражение встроенного языка «1С:Предприятие». В логическом выражении могут участвовать как внутренние, так и внешние переменные запроса, то есть переменные программного модуля, доступные в процедуре, использующей запрос.

Пример:

ТекстЗапроса =
"//{{ЗАПРОС(Одинарный)
|Период с ДатаНачала по ДатаКонец;
|Оклад = Справочник.Сотрудники.Оклад;
|Ктг = Справочник.Сотрудники.Категория;
|Группировка Ктг без групп;
|Функция Всего = Сумма(Оклад);
|Условие(Ктг.Выбран() = 1);   // только для тех сотрудников
| // у кого заполнен реквизит Категория
|"
;

Далее в нижеприведённом примере показан отрывок текста процедуры, в которой формируется некоторый отчёт, причём переменные ВыбТовар, ВыбОтдел, ВыбСотрудник являются реквизитами диалога отчёта, значит, они доступны в программном модуле, поэтому могут быть использованы в логическом выражении оператора Условие(). В данном примере операторы Условие() использованы для фильтрации в запросе только выбранных значений параметров отчёта:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Квоты)
|Товар = Регистр.КвотыТоваров.Товар;
|Отдел = Регистр.КвотыТоваров.Отдел;
|Сотрудник = Регистр.КвотыТоваров.Сотрудник;
|Партнер = Регистр.КвотыТоваров.Партнер;
|Количество = Регистр.КвотыТоваров.КвотаТовара;
|Группировка Товар;
|Группировка Отдел;
|Группировка Сотрудник;
|Группировка Партнер;
|Функция Кол_во = КонОст(Количество);
|Условие(Товар.ПринадлежитГруппе(ВыбТовар) = 1);
|Условие(Отдел = ВыбОтдел);
|Условие(Сотрудник = ВыбСотрудник.Сотрудник);
|"
;

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

В параметре оператора Условие(), в принципе, можно записывать логические выражения любой сложности (по правилам встроенного языка «1С:Предприятие»), используя любые логические операторы (>, <, =, >=, <>, И, ИЛИ, НЕ и др.), при этом в качестве операндов могут участвовать как внутренние, так и внешние переменные запроса (если существуют внутренняя и внешняя переменные с одинаковым именем, то использоваться по данному имени будет внутренняя переменная).

Пример:

Условие(Цена > 23.5);
Условие((Товар.ПринадлежитГруппе(ВыбТовар) = 1) И (Товар.Розн_Цена = 100));

Использование двух операторов

Условие(Товар.Наименование <> "Стол");
Условие(Товар.Наименование <> "Шкаф");

аналогично одному оператору

Условие((Товар.Наименование <> "Стол") И (Товар.Наименование <> "Шкаф"));

Кроме обычных логических операторов в операторе Условие() языка запросов можно использовать дополнительный оператор — логический оператор принадлежности В (англоязычный синоним — In). Тогда, например, оператор языка запросов Условие (А в Б); будет говорить о том, что условие истинно, когда значение А является подмножеством значения Б. Причём, следует особо отметить, что если значение Б будет пустое (объект не выбран), то условие будет является истинным, в отличии от оператора = (равно).

Если на принадлежность проверяется значение типа "элемент справочника", то проверка выполняется с учётом его возможного вхождения в группу справочника. Аналогично, проверка на принадлежность субсчёта осуществляется с учётом его возможного вхождения в группу счетов.

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

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

Текст3апроса = "
 . . .
|Товар = Документ.ВидДокумента.Товар;";
 . . .
|"
;

Если ВыбТовар.Выбран() = 1 Тогда
   Если ВыбТовар.ЭтоГруппа() = 1 Тогда
      ТекстЗапроса = ТекстЗапроса + "Условие(Товар.ПринадлежитГруппе(ВыбТовар) = 1);";
   Иначе
      ТекстЗапроса = ТекстЗапроса + "Условие(Товар = ВыбТовар);";
   КонецЕсли
КонецЕсли;

А теперь тот же пример, но с использованием логического оператора принадлежности:

Текст3апроса = "
 . . .
|Товар = Документ.ВидДокумента.Товар;";
 . . .
|Условие(Товар В ВыбТовар);
 . . .
|"
;

Примеры использования запросов

Печать каталога товаров

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

Процедура ПечатьСправочника()
   
   Перем Запрос, ТекстЗапроса, Таб;
   
   Запрос = СоздатьОбъект("Запрос");
   Текст3апроса = "//{{ЗАПРОС(Печать)
   |Товар = Справочник.Товары.ТекущийЭлемент;
   |Группировка Товар Упорядочить по Товар.МинЗапас;
   |"
   ;
   
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   
   Таб = СоздатьОбъект("Таблица");
   Таб.ВывестиСекцию("Отчет");
   Пока Запрос.Группировка("Товар") = 1 Цикл
      
      Если Запрос.Товар.ЭтоГруппа() = 1 Тогда
         Таб.ВывестиСекцию("Группа");
      Иначе
         Таб.ВывестиСекцию("Товар");
      КонецЕсли;
   КонецЦикла;
   
   Таб.Опции(0, 0, 4, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("Список товаров по каталогу", "");
КонецПроцедуры

Отчёт по неходовым товарам

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

Процедура Сформировать()
   Перем Запрос, ТекстЗапроса, Таб;
   Рег = СоздатьОбъект("Регистр.ОстаткиТовара");
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(Сформировать)
   |Период С ДатаНачала По ДатаКонца;
   |ТОВАР = Документ.РасходнаяБН.Товар, 
   |   Документ.РасходнаяКредит.Товар, Документ.РасходнаяНал.Товар,
   |   Документ.РасходнаяРеализ.Товар, Документ.Счет.Товар;
   |Группировка ТОВАР упорядочить по ТОВАР.Наименование без групп;
   |"
   ;
   Если ДатаКонца >= ПолучитьДатуТА() Тогда
      ТекстЗапроса = ТекстЗапроса + "Период С ДатаНачала;";
   Иначе
      ТекстЗапроса = ТекстЗапроса + "Период С ДатаНачала По ДатаКонца;";
      Peг.ВременныйРасчет();
      РассчитатьРегистрыНа(ДатаКонца);
   КонецЕсли;
   
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   Тов = СоздатьОбъект("Справочник.Товары");
   
   Тов.ВключатьПодчиненные(1);
   
   Тов.ПорядокНаименований();
   ИтогоОстаток = 0;
   ИтогоСумма = 0;
   Таб = СоздатьОбъект("Таблица");
   Таб.ВывестиСекцию("Отчет");
   
   Тов.ВыбратьЭлементы();
   Пока Тов.ПолучитьЭлемент() > 0 Цикл
      Флаг = 0;
      Товар = Тов.ТекущийЭлемент();
      Если Товар.ЭтоГруппа() = 1 Тогда
         Продолжить;
      КонецЕсли;
      
      Если Запрос.Получить(Товар) = 1 Тогда
         Продолжить;
      КонецЕсли;
      
      Рег.СводныеОстатки(Товар, );
      ТекОстаток = Рег.ОстатокТовара;
      ТекСумма = Рег.БазоваяСтоимость;
      Если ТекОстаток = 0 Тогда
         Продолжить;
      КонецЕсли;
      Таб.ВывестиСекцию("Товар");
      ИтогоОстаток = ИтогоОстаток + ТекОстаток;
      ИтогоСумма = ИтогоСумма + ТекСумма;
   КонецЦикла;
   Таб.ВывестиСекцию("Итоги");
   Таб.ТолькоПросмотр(1);
   Таб.Опции(0, 0, 3, 0);
   Таб.Показать("Отчет о неходовых товарах", "");
КонецПроцедуры



ДатаКонца = РабочаяДата();
ДатаНачала = ДатаКонца — Константа.ПериодАнализа;

Отчёт по регистру с точностью до строки документа

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

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

Процедура Сформировать()
   Перем Запрос, ТекстЗапроса, Таб;
   
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(Сформировать)
   |Период с НачДата по КонДата;
   |ВидТоплива = Регистр.ПокупателиКолво.ВидыТоплива;
   |Вес = Регистр.ПокупателиКолво.Кг;
   |Покуп = Регистр.ПокупателиКолво.Покупатели;
   |Док = Регистр.ПокупателиКолво.ТекущийДокумент;
   |Ном = Регистр.ПокупателиКолво.НомерСтроки;
   |Группировка ВидТоплива;      // по измерению Регистра
   |Группировка Док;             // по документам, двигавшим Регистр
   |Группировка Ном;             // по номерам строк документов
   |Функция ВсегоКолво = КонОст(Вес);
   |Функция ПриходКолво = Приход(Вес);
   |Условие(Покуп = ВыбПокупатель);
   |"
   ;
   
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   
   Таб = СоздатьОбъект("Таблица");
   Таб.ИсходнаяТаблица("Таблица1");
   Таб.ВывестиСекцию("Шапка");
   Пока Запрос.Группировка(1) = 1 Цикл
      
      Таб.ВывестиСекцию("ВидТоплива");
      
      Пока Запрос.Группировка(2) = 1 Цикл
         Док1 = Запрос.Док;
         
         Если НЕ(Док1.Вид() = "Продажа") Тогда
            Продолжить;
         КонецЕсли;
         
         Пока Запрос.Группировка(3) = 1 Цикл
            
            Док1.ПолучитьСтрокуПоНомеру(Запрос.Ном);
            Таб.ВывестиСекцию("Строка");
         КонецЦикла;
      КонецЦикла;
   КонецЦикла;
   
   Таб.Опции(0, 0, 0, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("", "");
КонецПроцедуры

Анализ счёта

Ниже приведён пример использования запроса для работы с бухгалтерскими операциями и проводками. Запрос обрабатывает корреспонденции счёта Сч со счетами КорСч за расчётный период. Значение счёта для анализа задаётся в диалоге установкой ВыбСч.

Процедура АнализСчета()
   Перем Запрос, ТекстЗапроса, Таб;
   
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(Сформировать)
   |Период с ДатаС по ДатаПо;
   |Сч = Операция.Счет;
   |КорСч = Операция.КорСчет;
   |Сумма = Операция.Сумма;
   |Группировка Сч упорядочить по Сч.Код;
   |Группировка КорСч упорядочить по КорСч.Код;
   |Функция КорДо = КорДО(Сумма);
   |Функция КорКо = КорКО(Сумма);
   |Условие(Сч = ВыбСч);
   |"
   ;
   
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   
   Таб = СоздатьОбъект("Таблица");
   Таб.ИсходнаяТаблица("Сформировать");
   
   Таб.ВывестиСекцию("Заголовок");
   Состояние("Заполнение выходной таблицы...");
   Пока Запрос.Группировка("Сч") = 1 Цикл
      
      Таб.ВывестиСекцию("Сч");
      Пока Запрос.Группировка("КорСч") = 1 Цикл
         
         Таб.ВывестиСекцию("КорСч");
      КонецЦикла;
   КонецЦикла;
   
   Таб.ВывестиСекцию("Итого");
   
   Таб.Опции(1, 0, 1, 0);
   Таб.Показать("Сформировать", "");
КонецПроцедуры

Разработка вложенных отчётов

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

Поскольку каждая ячейка таблицы может содержать значение, записанное в неё, то в программном модуле формы отчёта возможно обрабатывать это значение. Обработка значения ячейки таблицы вызывается системой по клавише Enter или по двойному щелчку мышью на какой-либо ячейке (если режим «только просмотр»). Стандартными действиями системы на обработку такого события являются: для документа — открытие документа, для элемента справочника — открытие формы редактирования элемента справочника. Другими словами, стандартные действия системы зависят от типа данных содержащегося в ячейке значения. Однако, это событие возможно перехватить и обработать нестандартным способом. Для этого предназначена предопределённая процедура встроенного языка ОбработкаЯчейкиТаблицы().

Примером нестандартной обработки значения ячейки таблицы может быть, например, вызов на формирование другого отчёта. Таким образом, мы можем создавать как бы вложенные отчёты, которые вызываются один из другого, выдавая с каждым разом более детальную информацию. Допустим отчёт «Взаиморасчеты» при формировании всегда выводится в кратком виде, когда виден только сводный баланс по контрагенту. Для того, чтобы получить детальный отчёт по данному контрагенту, достаточно встать курсором в готовой форме отчёта на этого контрагента и нажать клавишу Enter. Тогда сработает процедура ОбработкаЯчейкиТаблицы(), в которой можно записать вызов формирования детального отчёта. А если, кроме того, завести флаг режима отображения, то можно вместо этого показывать карточку этого контрагента из справочника.

Рассмотрим построение вложенных отчётов на примере. Допустим, у вас есть отчёт «ПродажиТоваров», в котором отображается перечень товаров, количество и сумма проданных за некоторый период товаров. Программный модуль формирования такого отчёта приведён ниже.

Процедура ПродВсего()
   Перем Запрос, ТекстЗапроса, Таб;
   ДатаКон = ДатаКонца;
   Если ДатаКон >= ПолучитьДатуТА() Тогда
      ДатаКон = Дата(0);
   КонецЕсли;
   
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(ПродВсего)
   |Период с ДатаНачала по ДатаКон;
   |ТОВАР = Документ.РасхНакл.Товар;
   |Сумма_Прод = Документ.РасхНакл.СуммаРуб;
   |КОЛВО_Прод = Документ.РасхНакл.Количество;
   |Группировка ТОВАР;
   |Функция Продано = Сумма(КОЛВО_Прод);
   |Функция СуммаПродано = Сумма(Сумма_Прод);
   |"
   ;
   
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   
   Таб = СоздатьОбъект("Таблица");
   Таб.ИсходнаяТаблица("ТабВсего");
   Таб.ВывестиСекцию("Отчет");
   Пока Запрос.Группировка("Товар") = 1 Цикл
      ПродСумма = Запрос.СуммаПродано;
      Если Запрос.Товар.ЭтоГруппа() = 1 Тогда
         Таб.ВывестиСекцию("Группа");
      Иначе
         Таб.ВывестиСекцию("Товар");
      КонецЕсли;
   КонецЦикла;
   
   Таб.ТолькоПросмотр(1);
   Таб.Опции(0, 0, 4, 0);
   Таб.Показать("Продажа товаров", "");
КонецПроцедуры

В режиме исполнения у нас получится такой отчёт:

Отчёт

Далее, допустим, мы хотим получить более подробный отчёт по конкретному товару, так, чтобы указав на товар в отчёте, и дважды нажав кнопку мыши, мы получали отчёт по продажам именно этого товара с точностью до каждого клиента. Для этого откроем в Конфигураторе редактор таблицы нашего отчёта и в свойствах ячейки (Свойства ячейки -> Текст -> поле «Значение»), отображающей наименование товара, проставим значение ячейки — «Запрос.Товар».

Далее, в программном модуле напишем процедуру формирования дополнительного отчёта:

Процедура ПродТовар(ВТовар)
   Перем Запрос, ТекстЗапроса, Таб;
   ДатаКон = ДатаКонца;
   Если ДатаКон >= ПолучитьДатуТА() Тогда
      ДатаКон = Дата(0);
   КонецЕсли;
   
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(ПродТовар)
   |Период с ДатаНачала по ДатаКон;
   |КЛИЕНТ = Документ.РасхНакл.Клиент;
   |ТОВАР = Документ.РасхНакл.Товар;
   |СУММ = Документ.РасхНакл.СуммаВал;
   |КОЛВО = Документ.РасхНакл.Количество;
   |Группировка КЛИЕНТ Упорядочить По КЛИЕНТ.Наименование;
   |Группировка ТОВАР Упорядочить По ТОВАР.Наименование;
   |Функция Продано = Сумма(КОЛВО);
   |Функция ПродСум = Сумма(СУММ);
   |"
   ;
   Если ВТовар.Выбран() = 1 Тогда
      Если ВТовар.ЭтоГруппа() = 1 Тогда
         ТекстЗапроса = ТекстЗапроса + "Условие(Товар.ПринадлежитГруппе(ВТовар) = 1);";
      Иначе
         ТекстЗапроса = ТекстЗапроса + "Условие (Товар = ВТовар);";
         ФОдинТовар = 1;
      КонецЕсли;
   КонецЕсли;
   
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   
   Таб = СоздатьОбъект("Таблица");
   Таб.ВывестиСекцию("Отчет");
   Пока Запрос.Группировка("Клиент") = 1 Цикл
      Таб.ВывестиСекцию("Клиент");
      Пока Запрос.Группировка("Товар") = 1 Цикл
         Если ФОдинТовар = 0 Тогда
            Таб.ВывестиСекцию("Товар");
         КонецЕсли;
      КонецЦикла;
   КонецЦикла;
   
   Таб.ТолькоПросмотр(1);
   Таб.Опции(0, 4, 0, 0);
   Таб.Показать("Продажа товара", "");
КонецПроцедуры

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

Процедура ОбработкаЯчейкиТаблицы(ЗначЯч, ФлагСтандартнойОбработки)   
   Если ТипЗначения(ЗначЯч) = 2 Тогда
      ФлагСтандартнойОбработки = 1;
      Возврат;
   КонецЕсли;
   ПродТовар(ЗначЯч);
КонецПроцедуры

Теперь, в режиме исполнения, если в отчёте «Продажи товаров» мы укажем курсором на товар, например, «Сапоги женские» и дважды щёлкнем на нём мышью, то сформируется дополнительный подробный отчёт «Продажа товара».

Способы оптимизации формирования отчётов

Процесс получения отчётов с использованием запросов можно условно разделить на две фазы: сначала формируется запрос, затем полученные данные выводятся в таблицу. В данном разделе речь пойдёт о второй фазе получения отчёта — выводе данных в таблицу.

Рассмотрим следующий пример. Допустим, требуется вывести в отчёт полный перечень товаров со всеми их реквизитами. Для этого сначала формируется запрос с одной группировкой — "Товар", затем полученные данные выводятся в таблицу. Ниже приведены три варианта вывода данных в таблицу.

Вариант 1:

В программном модуле текст вывода данных в таблицу следующий:

Пока Запрос.Группировка("Товар") = 1 Цикл
   Таб.ВывестиСекцию("Товар");
КонецЦикла;

Секция "Товар" в таблице имеет следующий формат:

Секция'Товар'

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

Вариант 2:

В программном модуле текст вывода данных в таблицу следующий:

Пока Запрос.Группировка("Товар") = 1 Цикл
   ПечНаим = Запрос.Товар.Наименование;
   ПечАртикул = Запрос.Товар.Артикул;
   ПечЦена = Запрос.Товар.Цена;
   ПечВалюта = Запрос.Товар.Валюта;
   Таб.ВывестиСекцию("Товар1");
КонецЦикла;

Секция "Товар1" в таблице имеет следующий формат:

Секция'Товар1'

Во этом варианте отображаемые реквизиты товара вычисляются в программном модуле, а в ячейках таблицы размещены простые выражения — ссылки на идентификаторы программного модуля. Доступ к каждому реквизиту товара, как и в первом варианте, происходит по полному пути: Запрос-Товар-Реквизит. Но в данном варианте фаза вывода данных в таблицу работает быстрее первого варианта (выигрыш примерно 20%), так как в программном модуле выражения вычисляются существенно быстрее, чем выражения, помещённые в ячейках таблицы (программный модуль при загрузке компилируется, а выражения в ячейках таблицы интерпретируются каждый раз при выводе секций).

Вариант 3:

В программном модуле текст вывода данных в таблицу следующий:

Пока Запрос.Группировка("Товар") = 1 Цикл
   Тов = Запрос.Товар;
   ПечНаим = Тов.Наименование;
   ПечАртикул = Тов.Артикул;
   ПечЦена = Тов.Цена;
   ПечВалюта = Тов.Валюта;
   Таб.ВывестиСекцию("Товар1");
КонецЦикла;

Секция «Товар1» в таблице имеет следующий формат:

Секция'Товар1'

В этом варианте отображаемые реквизиты товара также вычисляются в программном модуле, а в ячейках таблицы размещены простые выражения — ссылки на идентификаторы программного модуля. Однако доступ к каждому реквизиту товара происходит по сокращённому пути — через промежуточную переменную: Товар—Реквизит. Поэтому в данном варианте фаза вывода данных в таблицу работает быстрее, чем во втором варианте (выигрыш примерно 20%) и существенно быстрее, чем в первом варианте (выигрыш примерно 40%), так как вычисление значений реквизитов объектов через «одну точку» выполняется быстрее, чем через «две (и более) точки».

Отсюда вывод: при реализации больших отчётов, которые рассчитаны на отображение более сотни строк:

  • не следует размещать сложные выражения в ячейках таблицы. Лучше вычислить необходимые значения непосредственно в программном модуле;
  • если необходимо получить несколько реквизитов одного объекта, который сам является составной частью другого объекта, то следует воспользоваться промежуточной переменной, в которую сначала можно записать значение всего объекта «целиком», а затем уже от неё получать требуемые данные.

Другие статьи по схожей тематике

  • Работы с табличными формами
  • Работа со справочниками в 1С
  • Работа с объектами типа "Документ"
  • Работа с типом данных "Счет"
  • Работа с операциями и проводками
  • Работа с бухгалтерскими итогами
  • Работа с регистрами оперативного учёта

Like this post? Please share to your friends:
  • Запрос о сданной отчетности код ошибки 0600100004
  • Запрос на открытие tcp ip сокета ошибка меркурий
  • Запрещено делать ставки фонбет ошибка
  • Запретить вывод ошибок php
  • Запрет опции безлимитный интернет код ошибки o191