Условие в виртуальной таблице 1с. Упорядочивание данных по ссылочному полю

Условие в виртуальной таблице 1с. Упорядочивание данных по ссылочному полю
Условие в виртуальной таблице 1с. Упорядочивание данных по ссылочному полю

Статья описывает физическую реализацию виртуальной таблицы остатков конфигурации, работающей в клиент-серверном режиме работы на примере использования СУБД MS SQL Server.

Применимость

В статье рассматривается платформа «1С:Предприятие» редакции 8.3.5.1383. В актуальной версии платформы возможны некоторые изменения в тексте, описанного в материале, запроса T-SQL, выполняемого на стороне сервера СУБД.

Устройство виртуальной таблицы остатков

Рассмотрим, в какой запрос к СУБД трансформируется запрос с использованием виртуальной таблицы остатков регистра накопления. Для примера будет рассматриваться следующий текст запроса:

ВЫБРАТЬ
ТоварныеЗапасыОстатки.Товар ,
ТоварныеЗапасыОстатки.Склад ,
ТоварныеЗапасыОстатки.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварныеЗапасы.Остатки (&Дата , Склад = &Склад ) КАК
ТоварныеЗапасыОстатки

Сначала при помощи метода глобального контекста ПолучитьСтруктуруХраненияБазыДанных() получим список таблиц базы данных, в которых хранятся данные регистра накопления «ТоварныеЗапасы»:

Состав полей основной таблицы регистра накопления и таблицы итогов приведен ниже:

Хранение итогов для данного регистра настроено в режиме «1С:Предприятие 8» следующим образом:

Параметры в рассматриваемом запросе заполним следующим образом:


Платформа преобразует текст запроса в следующий запрос, который и будет выполнен на сервере СУБД:

SELECT
Q_000_T_001.Fld82 ,
Q_000_T_001.Fld83 ,
Q_000_T_001.Fld84Balance
FROM
(SELECT Fld82 ,
Fld83 ,

FROM
(SELECT Fld82 ,
Fld83 ,
SUM (Fld84 ) AS Fld84Balance
FROM AccumRgT85
WHERE Period = DATETIME (3999 , 11 , 1 )
AND ((Fld83 = ))
AND (Fld84 <> 0 ) AND (Fld84 <> 0 )
GROUP BY Fld82 , Fld83
HAVING Fld84Balance <> 0
UNION ALL
SELECT Fld82 ,
Fld83 ,
SUM (CASE WHEN RecordKind = 0 THEN – Fld84 ELSE Fld84 END ) AS Fld84Balance
FROM AccumRg81
WHERE Period >= DATETIME (2012 , 9 , 1 )
AND Period < DATETIME (3999 , 11 , 1 )
AND Active
AND ((Fld83 = 9:))
GROUP BY Fld82 , Fld83
HAVING Fld84Balance <> 0 ) T
GROUP BY Fld82 , Fld83
HAVING Fld84Balance <> 0 ) Q_000_T_001

Разберем подробнее полученный запрос.

Сначала при помощи первого запроса, входящего в объединение, выбираются данные из итоговой таблицы AccumRgT85. Итоги получаются на дату хранения текущих итогов (01.11.3999), дополнительно накладывается условие на поле Склад (поскольку такое условие использовалось в параметрах виртуальной таблицы). Дополнительно выполняется проверка на отсутствие в результате строк с нулевыми остатками.

Обратите внимание, что производится группировка по выбранным в тексте запроса измерениям. Именно поэтому не требуется в тексте на языке запросов «1С:Предприятие» дополнительно выполнять группировку по измерениям.

Во втором запросе объединения используется таблица движений регистра AccumRg81. В зависимости от вида движения (если RecordKind равно 0, то это Приход, в противном случае – Расход) проставляется знак в выражении. Платформа выбирает данные за период с даты, указанной в качестве параметра виртуальной таблицы, по дату хранения текущих итогов (01.11.3999).

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

Если используется СУБД MS SQL Server и для базы данных установлено смещение дат 2000, то все даты будут храниться с указанным смещением, т.е. вместо 01.11.3999 Вы увидите 01.11.5999.

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

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

SELECT
Q_000_T_001.Fld82 ,
Q_000_T_001.Fld83 ,
Q_000_T_001.Fld84Balance
FROM
(SELECT Fld82 ,
Fld83 ,
SUM (Fld84Balance ) AS Fld84Balance
FROM
(SELECT Fld82 ,
Fld83 ,
SUM (Fld84 ) AS Fld84Balance
FROM AccumRgT85
WHERE Period = DATETIME (2012 , 4 , 1 )
AND ((Fld83 = 9:))
AND (Fld84 <> 0 )
AND (Fld84 <> 0 )
GROUP BY Fld82 , Fld83
HAVING Fld84Balance <> 0
UNION ALL
SELECT Fld82 ,
Fld83 ,
SUM (CASE WHEN RecordKind = 0 THEN Fld84 ELSE – Fld84 END ) AS Fld84Balance
FROM AccumRg81
WHERE Period >= DATETIME (2012 , 4 , 1 )
AND Period < DATETIME (2012 , 9 , 1 )
AND Active
AND ((Fld83 = 9:))
GROUP BY Fld82 , Fld83
HAVING Fld84Balance <> 0 ) T
GROUP BY Fld82 , Fld83
HAVING Fld84Balance <> 0 ) Q_000_T_001

Обратите внимание на следующее условие в тексте запроса.

Язык запросов в 1С 8 — это упрощенный аналог широко известного «структурированного языка программирования» (как чаще его называют, SQL). Но в 1С он используется только для чтения данных, для изменения данных применяется объектная модель данных.

Еще одно интересное отличие – русский синтаксис. Хотя на самом деле Вы можете использовать и англоязычные конструкции.

Пример запроса:

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

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

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

Описание конструкций языка запросов

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

Для получения данных достаточно использовать конструкции «ВЫБРАТЬ» (select) и «ИЗ» (from). Простейший запрос выглядит следующим образом:

ВЫБРАТЬ * ИЗ Справочники.Номенклатура

Где «*» означает выбор всех полей таблицы, а Справочники.Номенклатура – имя таблицы в базе данных.

Рассмотрим более сложный и общий пример:

ВЫБРАТЬ
<ИмяПоля1> КАК <ПредставлениеПоля1>,
Сумма(<ИмяПоля2>) КАК <ПредставлениеПоля2>
ИЗ
<ИмяТаблицы1> КАК <ПредставлениеТаблицы1>
<ТипСоединения> СОЕДИНЕНИЕ <ИмяТаблицы2> КАК <ПредставлениеТаблицы2>
ПО <УсловиеСоединениеТаблиц>

ГДЕ
<УсловиеОтбораДанных>

СГРУППИРОВАТЬ ПО
<ИмяПоля1>

УПОРЯДОЧИТЬ ПО
<ИмяПоля1>

ИТОГИ
<ИмяПоля2>
ПО
<ИмяПоля1>

В данном запросе мы выбираем данные полей «ИмяПоля1» и «ИмяПоля1» из таблиц «ИмяТаблицы1» и «ИмяТаблицы», присваиваем полям синонимы с помощью оператора «КАК», соединяем их по некому условию «УсловиеСоединениеТаблиц».

Из полученных данных мы отбираем только данные, соответствующие условию из «ГДЕ» «УсловиеОтбораДанных».Далее мы группируем запрос по полю «ИмяПоля1», при этом суммируя «ИмяПоля2».Создаём итоги по полю «ИмяПоля1» и итоговым полем «ИмяПоля2».

Последним действием мы сортируем запрос с помощью конструкции «УПОРЯДОЧИТЬ ПО».

Общие конструкции

Рассмотрим общие конструкции языка запросов 1С 8.2.

ПЕРВЫЕ n

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

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

Запросом будет получено первых 100 записей справочника «Банки», упорядоченных по алфавиту.

РАЗРЕШЕННЫЕ

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

Если пользователь пытается с помощью запроса прочитать записи недоступные ему, он получит сообщение об ошибке. Чтобы этого избежать, следует использовать конструкцию «РАЗРЕШЕННЫЕ», т.е запрос будет читать только разрешенные ему записи.

ВЫБРАТЬ РАЗРЕШЕННЫЕ
ХранилищеДополнительнойИнформации.Ссылка
ИЗ
Справочник.ХранилищеДополнительнойИнформации

РАЗЛИЧНЫЕ

Использование «РАЗЛИЧНЫЕ» позволит исключить попадание строк-дублей в результат запроса 1С. Дублирование означает совпадение всех полей запроса.

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

ПустаяТаблица

Данная конструкция используется очень редко для объединения запросов. При объединении может возникнуть необходимость указать в одной из таблиц пустую вложенную таблицу. Для этого как раз подойдет оператор «ПустаяТаблица»

Пример из справки 1С 8:

ВЫБРАТЬ Ссылка.Номер, ПУСТАЯТАБЛИЦА.(Ном, Тов, Кол) КАК Состав
ИЗ Документ.РасхНакл
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Ссылка.Номер, Состав.(НомерСтроки, Товар, Количество)
ИЗ Документ.РасхНакл Документ.РасходнаяНакладная.Состав.*

ЕСТЬNULL

Очень полезная функция, которая позволяет избежать многих ошибок. ЕстьNULL() позволяет заменить значение NULL на нужное. Очень часто используется в проверках на наличие значения в присоединенных таблицах, например:

ВЫБРАТЬ
НоменклатураСпр.Ссылка,
ЕстьNULL(ОстаткиТовара.КоличествоОстаток,0) КАК КоличествоОстаток
ИЗ


Можно использовать и по-другому. Например, если для каждой строки не известно, в какой таблице существует значение:

ЕСТЬNULL(СчетФактураПолученный.Дата, СчетФактураВыданный.Дата)

КАК – оператор, который позволяет нам присвоить имя (синоним) таблицы или полю. Пример использования мы видели выше.

Данные конструкции очень похожи – они позволяют получить строковое представление нужного значения. Единственное отличие в том, что ПРЕДСТАВЛЕНИЕ преобразует любые значения в строковый тип, а ПРЕДСТАВЛЕНИЕССЫЛКИ — только ссылочные. ПРЕДСТАВЛЕНИЕССЫЛКИ рекомендуется применять в запросах системы компоновки данных для оптимизации, если, конечно, поле ссылочных данных не планируется использовать в отборах .

ВЫБРАТЬ
Представление(Ссылка), //строка, например «Авансовый отчет №123 от 10.10.2015
Представление(ПометкаУдаления) КАК ПометкаУдаленияТекст, //строка, «Да» или «Нет»
ПредставлениеСсылки(ПометкаУдаления) КАК ПометкаУдаленияБулево //булево, Истина или Ложь
ИЗ
Документ.АвансовыйОтчет

ВЫРАЗИТЬ

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

Выразить для ссылочного типа используется для ограничения запрашиваемых типов данных в полях составного типа, часто используется для оптимизации работы системы. Пример:

ВЫРАЗИТЬ(ТаблицаЗатрат.Субконто1 КАК Справочник.СтатьиЗатрат).ВидДеятельностиДляНалоговогоУчетаЗатрат

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

ВЫРАЗИТЬ(Комментарий КАК Строка(150))

РАЗНОСТЬДАТ

Получите 267 видеоуроков по 1С бесплатно:

Пример использования ЕСТЬ NULL в запросе 1С:

ВЫБРАТЬ * ИЗ
Спр
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ОстаткиТовара
ПО НоменклатураСпр.Ссылка = РеализованныеТоварыКомитентовОстатки.Номенклатура
ГДЕ НЕ ОстаткиТовара.КоличествоОстаток ЕСТЬ NULL

Тип данных в запросе можно определить следующим образом: с помощью функций ТИП() и ТИПЗНАЧЕНИЯ() или с помощью логического оператора ССЫЛКА. Эти две функции аналогичны.

Предопределенные значения

Помимо использования в запросах переданных параметров в языке запросов 1С можно использовать предопределенные значения или . Например, перечисления, предопределенные справочники, планы счетов и так далее.Для этого используется конструкция «Значение()».

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

ГДЕ Номенклатура.ВидНоменклатуры = Значение(Справочник.ВидыНоменклатуры.Товар)

ГДЕ Контрагенты.ВидКонтактнойИнформации = Значение(Перечисление.ВидыКонтактнойИнформации.Телефон)

ГДЕ ОстаткиПоСчетам.СчетУчета = Значение(ПланСчетов.Хозрасчетный.ПрибылиУбытки)

Соединения

Соединения бывают 4 типов: ЛЕВОЕ , ПРАВОЕ , ПОЛНОЕ, ВНУТРЕННЕЕ .

ЛЕВОЕ и ПРАВОЕ СОЕДИНЕНИЕ

Соединения используются для связи двух таблиц по определенному условию. Особенность при ЛЕВОМ СОЕДИНЕНИИ в том, что мы берём первую указанную таблицу полностью и привязываем по условию вторую таблицу. Поля второй таблицы, которые не удалось привязать по условию, заполняются значением NULL .

Например:

Вернет всю таблицу Контрагентов и заполнит поле “Банк” лишь в тех местах, где будет соблюдаться условие “Контрагенты.Наименование = Банки.Наименование”. Если условие не соблюдается, в поле Банк будет установлено NULL .

ПРАВОЕ СОЕДИНЕНИЕ в языке 1С абсолютно аналогично ЛЕВОМУ соединению , за исключением одного отличия – в ПРАВОМ СОЕДИНЕНИИ “главная” таблица – вторая, а не первая.

ПОЛНОЕ СОЕДИНЕНИЕ

ПОЛНОЕ СОЕДИНЕНИЕ отличается от левого и правого тем, что выводит все записи из двух таблиц, соединяет лишь те, которые может соединить по условию.

Например:

ИЗ

ПОЛНОЕ СОЕДИНЕНИЕ
Справочник.Банки КАК Банки

ПО

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

ВНУТРЕННЕЕ СОЕДИНЕНИЕ

ВНУТРЕННЕЕ СОЕДИНЕНИЕ отличается от полного тем, что выводит только те записи, которые смогли соединить по заданному условию.

Например:

ИЗ
Справочник.Контрагенты КАК Клиенты

ВНУТРЕННЕЕ СОЕДИНЕНИЕ
Справочник.Банки КАК Банки

ПО
Клиенты.Наименование = Банки.Наименование

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

Объединения

Конструкция ОБЪЕДИНИТЬ и ОБЪЕДИНИТЬ ВСЕ объединяет два результата в один. Т.е. результат выполнения двух будет «слит» в один, общий.

Т.е система работает точно так же, как и обычные , только для временной таблицы.

Как использовать ИНДЕКСИРОВАТЬ ПО

Однако следует учесть один момент. Построение индекса временной таблицы также требует времени на выполнение. Поэтому целесообразно использовать конструкцию ” ”, только если точно известно, что во временной таблице будет не 1-2 записи. В противном случае эффект может быть обратным – быстродействие от индексированных полей не компенсирует времени построения индекса.

ВЫБРАТЬ
КурсыВалютСрезПоследних.Валюта КАК Валюта,
КурсыВалютСрезПоследних.Курс
ПОМЕСТИТЬ КурсыВалют
ИЗ
РегистрСведений.КурсыВалют.СрезПоследних(&Период,) КАК КурсыВалютСрезПоследних
ИНДЕКСИРОВАТЬ ПО
Валюта
;
ВЫБРАТЬ
ЦеныНоменклатуры.Номенклатура,
ЦеныНоменклатуры.Цена,
ЦеныНоменклатуры.Валюта,
КурсыВалют.Курс
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период,
Номенклатура В (&Номенклатура) И ТипЦен = &ТипЦен) КАК ЦеныНоменклатуры
ЛЕВОЕ СОЕДИНЕНИЕ КурсыВалют КАК КурсыВалют
ПО ЦеныНоменклатуры.Валюта = КурсыВалют.Валюта

Группировка

Язык запросов 1С позволяет использовать специальные агрегатные функции при группировке результатов запросов. Группировку можно также использовать без агрегатных функций, для «устранения» дублей.

Существуют следующие функции:

Сумма, Количество, Количество разных, Максимум, Минимум, Среднее.

Пример №1:

ВЫБРАТЬ
РеализацияТоваровУслугТовары.Номенклатура,
СУММА(РеализацияТоваровУслугТовары.Количество) КАК Количество,
СУММА(РеализацияТоваровУслугТовары.Сумма) КАК Сумма
ИЗ

СГРУППИРОВАТЬ ПО
РеализацияТоваровУслугТовары.Номенклатура

Запрос получает все строки с товарами и суммирует их по количеству и суммам в разрезе номенклатуры.

Пример №2

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

Данный пример отобразит список БИКов справочника «Банки» и покажет, сколько дублей существует по каждому из них.

Итоги

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

Один из самых популярных способов использования итогов в практике – партионное списание товаров.

ВЫБРАТЬ




ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
УПОРЯДОЧИТЬ ПО

ИТОГИ
СУММА(Количество),
СУММА(Сумма)
ПО
Номенклатура

В результате запроса получится следующее иерархическое :

Общие итоги

Если необходимо получить итоги по всем «итогам», используйте оператор «ОБЩИЕ».

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

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

В котором 1 уровень группировки – агрегирование всех нужных полей.

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

Оператор УПОРЯДОЧИТЬ ПО используется для сортировки результата запроса.

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

ВЫБРАТЬ

ИЗ
Справочник.Номенклатура КАК Номенклатура
УПОРЯДОЧИТЬ ПО
Наименование

Запрос выведет список наименований справочника номенклатуры, отсортированного по алфавиту.

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

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

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

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

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

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

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

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

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

ВЫБРАТЬ
ТоварыНаСкладахОстаткиИОбороты.Номенклатура,
ТоварыНаСкладахОстаткиИОбороты.КоличествоНачальныйОстаток,
ТоварыНаСкладахОстаткиИОбороты.КоличествоОборот,
ТоварыНаСкладахОстаткиИОбороты.КоличествоПриход,
ТоварыНаСкладахОстаткиИОбороты.КоличествоРасход,
ТоварыНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты КАК ТоварыНаСкладахОстаткиИОбороты

Такой запрос позволяет быстро получить большое количество данных.

Параметры виртуальных таблиц

Очень важный аспект работы с виртуальными таблицами – использование параметров. Параметры виртуальных таблиц – специализированные параметры для отбора и настройки.

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

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

РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Месяц, ДвиженияИГраницыПериода, Номенклатура = &НужнаяНоменклатура)

Алгоритм работы виртуальных таблиц

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

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

  1. Получаем ближайшее по дате и измерениям рассчитанное значение в таблице итогов.
  2. «Прибавляем» сумму из таблицы движения к сумме из таблицы итогов.


Такие простые действия могут существенно повысить производительность системы в целом.

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

Конструктор запросов – инструмент, встроенный в систему 1С предприятие, существенно облегчающий разработку запросов к базе данных.

Конструктор запроса имеет достаточно простой, интуитивно понятный интерфейс. Тем не менее рассмотрим применение конструктора запроса подробнее.

Запуск конструктора текста запроса производится контекстным меню (правой кнопкой мыши) в нужном месте программного кода.

Описание конструктора запроса 1С

Рассмотрим каждую вкладку конструктора подробнее. Исключение – вкладка Построитель, это тема для отдельного разговора.

Вкладка Таблицы и поля

На этой вкладке указывается источник данных и поля, которые необходимо выводить в отчет. По сути тут описываются конструкции ВЫБРАТЬ.. ИЗ.

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

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

Вкладка Связи

Вкладка служит для описания соединений нескольких таблиц, создает конструкции со словом СОЕДИНЕНИЕ.

Вкладка Группировка

На данной вкладке система позволяет группировать и суммировать нужные поля результата таблицы. Описывается использование конструкций СГРУППИРОВАТЬ ПО, СУММА, МИНИМУМ, СРЕДНЕЕ, МАКСИМУМ, КОЛИЧЕСТВО, КОЛИЧЕСТВО РАЗЛИЧНЫХ.

Вкладка Условия

Отвечает за всё, что идёт в тексте запроса после конструкции ГДЕ, т.е за все условия, накладываемые на получаемые данные.

Вкладка Дополнительно

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

Группировка Выборка записей :

  • Первые N – параметр, возвращающий в запрос только N записей (оператор ПЕРВЫЕ)
  • Без повторяющихся – обеспечивает уникальность полученных записей (оператор РАЗЛИЧНЫЕ)
  • Разрешенные – позволяет выбирать только те записи, которые позволяет выбрать система с учетом (конструкция РАЗРЕШЕННЫЕ)

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

Ниже существует флаг Блокировать полученные данные для последующего изменения . Он позволяет включить возможность установки блокировки данных, которая обеспечивает сохранность данных от момента их чтения до изменения (актуально только для Автоматического режима блокировок, конструкция ДЛЯ ИЗМЕНЕНИЯ).

Вкладка Объединения/Псевдонимы

На этой вкладке конструктора запросов устанавливается возможность объединения разных таблиц и псевдонимов(конструкция КАК). В левой части указываются таблицы. Если установить флаги напротив таблицы, будет использоваться конструкция ОБЪЕДИНИТЬ, иначе – ОБЪЕДИНИТЬ ВСЕ (отличия двух способов ). В правой части указываются соответствия полей в разных таблицах, если соответствие не указано, запрос будет возвращать NULL.

Вкладка Порядок

Здесь указывается порядок сортировки значений (УПОРЯДОЧИТЬ ПО) – по убыванию (УБЫВ) или возрастанию(ВОЗР).

Также есть интересный флаг – Автоупорядочивание (в запросе – АВТОУПОРЯДОЧИВАНИЕ). По умолчанию система 1С выводит данные в “хаотичном” порядке. Если установить этот флаг, система будет сортировать данные по внутренним данным.

Вкладка Пакет запросов

На вкладке конструктора запросов можно создавать новые , а также использовать её в роли навигации. В тексте запроса пакеты разделяются символом “;”(точка запятая).

Кнопка “Запрос” в конструкторе запросов

В левом нижнем углу конструктора запроса есть кнопка Запрос, с помощью которого можно в любой момент просмотреть текст запроса:

В данном окне можно внести коррективы в запрос и выполнить его.


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

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

Рассмотрим этот инструмент подробнее.

Скачать консоль запросов 1С

Первым делом, чтобы начать работу с консолью запросов, её нужно откуда-то скачать. Обработки обычно делятся на два вида – на управляемых формах и обычных (или, иногда, их называют на 8.1 и на 8.2/8.3).

Я постарался объединить эти два вида в одной обработке – в нужном режиме работы открывается нужная форма (в управляемом режиме консоль работает только в толстом режиме).

Описание консоли запросов 1С

Начнем рассмотрение консоли запросов с описания главной панели обработки:

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

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

Слева, в поле “Запрос”, можно создавать новые запросы и сохранять их в древовидной структуре. Вторая группа кнопок как раз отвечает за управление списком запросов. С помощью неё можно создать, скопировать, удалить, переместить запрос.

  • Выполнить запрос – простое выполнение и получение результата
  • Выполнить пакет – позволяет просмотреть все промежуточные запросы в пакете запросов
  • Просмотр временных таблиц – позволяет увидеть результаты, которые возвращают временные запросы в таблице

Параметры запроса:

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

В окне параметров запроса интересно следующее:

  • Кнопка Получить из запроса автоматически находит все параметры в запросе для удобства разработчика.
  • Флаг Единые параметры для всех запросов – при установке его обработка не очищает параметры при переходе от запроса к запросу в общем списке запросов.

Задать параметр списком значений очень просто, достаточно при выборе значения параметра нажать на кнопку очистки значения (крестик), система предложит выбрать тип данных, где надо выбрать “Список значения”:

Также в верхней панели очень есть кнопка вызова настроек консоли запросов:

Здесь можно указать параметры автосохранения запросов и параметры выполнения запроса.

В поле запроса консоли заносится текст запроса. Сделать это можно простым набором теста запроса или же вызовом специального инструмента – конструктора запросов.

Конструктор запроса 1С 8 вызывается из контекстного меню (правая кнопка мыши) при нажатии на поле ввода:

Также в этом меню есть такие полезные функции, как очистка или добавление в запрос символов переноса строки (“|”) или же получения кода запроса вот в таком удобном виде:

Запрос = Новый Запрос;
Запрос.Текст = ”
|ВЫБРАТЬ
| Валюты.Ссылка
|ИЗ
| Справочник.Валюты КАК Валюты”;
РезультатЗапроса = Запрос.Выполнить();

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



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

Оптимизация запросов

Одним из важнейших пунктов в повышении производительности работы 1С предприятия 8.3 является оптимизация запросов . Этот пункт также очень важен при сдаче аттестации . Ниже пойдет речь о типичных причинах не оптимальной работы запросов и способах из оптимизации.

Отборы в виртуальной таблице с помощью конструкции ГДЕ

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

ПРАВИЛЬНО :

ВЫБРАТЬ

ИЗ
РегистрНакопления.ВзаиморасчетыСДепонентамиОрганизаций.Остатки(
,
Организация = &Организация
И Физлицо = &Физлицо) КАК ВзаиморасчетыСДепонентамиОрганизацийОстатки

НЕПРАВИЛЬНО :

ВЫБРАТЬ
ВзаиморасчетыСДепонентамиОрганизацийОстатки.СуммаОстаток
ИЗ
РегистрНакопления.ВзаиморасчетыСДепонентамиОрганизаций.Остатки(,) КАК ВзаиморасчетыСДепонентамиОрганизацийОстатки
ГДЕ
ВзаиморасчетыСДепонентамиОрганизацийОстатки.Организация = &Организация
И ВзаиморасчетыСДепонентамиОрганизацийОстатки.Физлицо = &Физлицо

Получение значения поля составного типа через точку

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

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

НЕПРАВИЛЬНО:

ВЫБРАТЬ
НаборЗаписей.Регистратор.Дата,
НаборЗаписей.Количество
ИЗ
РегистрНакопления.ТоварыОрганизации КАК НаборЗаписей

Т.е по факту вот такой запрос будет обращаться не к одной таблице, а к 22 таблицам базы данных (у этого регистра 21 тип регистратора).

ПРАВИЛЬНО:

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

Либо второй вариант – добавление такой информации в реквизит, например, в нашем случае – добавление даты.

ПРАВИЛЬНО:

ВЫБРАТЬ
ТоварыОрганизаций.Дата,
ТоварыОрганизаций.Количество
ИЗ
РегистрНакопления.ТоварыОрганизаций КАК ТоварыОрганизаций

Подзапросы в условии соединения

Для оптимизации недопустимо использовать подзапросы в условиях соединения, это существенно замедляет работу запроса. Желательно в таких случаях использовать ВТ. Для соединения нужно использовать только объекты метаданных и ВТ, предварительно проиндексировав их по полям соединения.

НЕПРАВИЛЬНО:

ВЫБРАТЬ …

ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ ИЗ РегистрСведений.Лимиты
ГДЕ …
СГРУППИРОВАТЬ ПО …
) ПО …

ПРАВИЛЬНО:

ВЫБРАТЬ …
ПОМЕСТИТЬ Лимиты
ИЗ РегистрСведений.Лимиты
ГДЕ …
СГРУППИРОВАТЬ ПО …
ИНДЕКСИРОВАТЬ ПО …;

ВЫБРАТЬ …
ИЗ Документ.РеализацияТоваровУслуг
ЛЕВОЕ СОЕДИНЕНИЕ Лимиты
ПО …;

Соединение записей с виртуальными таблицами

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

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

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

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

  1. Индекс содержит все поля, перечисленные в условии.
  2. Эти поля находятся в самом начале индекса.
  3. Эти отборы идут подряд, то есть между ними не «вклиниваются» значения, не участвующие в условии запроса.

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

Использование логического ИЛИ в условиях

Вот и всё, в данной статье были освещены основы аспекты оптимизации запросов, которые должен знать каждый эксперт 1С.

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

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

1. Конструкция "ИЗ".

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

ВЫБРАТЬ Справочник.Банки.*

Выбирает все поля из справочника Банки. И является аналогичным запросу:

ВЫБРАТЬ Банки.* ИЗ Справочник.Банки КАК Банки

2. Упорядочивание данных по ссылочному полю

Когда нам необходимо упорядочить данные запроса по примитивным типам: "Строка", "Число", "Дата" и т.д., то все решается использованием конструкции "УПОРЯДОЧИТЬ ПО", если вам необходимо упорядочить данные по ссылочному полю? Ссылочное поле представляет из себя ссылку, уникальный идентификатор, т.е. грубо говоря некий произвольный набор символов и обычное упорядочивание может выдать не совсем ожидаемый результат. Для упорядочивания ссылочным полей используется конструкция "АВТОУПОРЯДОЧИВАНИЕ". Для этого необходимо сначала упорядочить данные непосредственно по ссылочному типу конструкцией "УПОРЯДОЧИТЬ ПО", а затем конструкция "АВТОУПОРЯДОЧИВАНИЕ".

В этом случае для документов упорядочивание будет происходить в порядке "Дата->Номер" , для справочников по "Основному представлению". Если упорядочивание происходит не по ссылочным полям, то использовать конструкцию "АВТОУПОРЯДОЧИВАНИЕ" не рекомендуется.

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

3.Получение текстового представления ссылочного типа. Конструкция "ПРЕДСТАВЛЕНИЕ".

Когда вам необходимо вывести для показа поле ссылочного типа, например поле "Банк", которое является ссылкой на элемент справочника "Банки", то необходимо понимать, что при выводе этого поля автоматически выполнится подзапрос к справочнику "Банки", чтобы получить представление справочника. Это будет замедлять вывод данных. Для Того, чтобы этого избежать необходимо использовать конструкцию "ПРЕДСТАВЛЕНИЕ" в запросе, чтобы сразу получить представление объекта и уже его выводить для просмотра.

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

4. Условие на выборку данных по шаблону.

Например, вам необходимо получить мобильные телефоны сотрудников вида (8 -123- 456-78-912). Для этого необходимо поставить такое условие в запросе:

ВЫБРАТЬ Сорудник.Наименование, Сорудник.Телефон КАК Телефон ИЗ Справочник.Сотрудники КАК Сотрудники ГДЕ Телефон ПОДОБНО "_-___-___-__-__"

Символ "_" является служебным и заменяет любой символ.

5. Одновременное использование итогов и группировок.


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

ВЫБРАТЬ ОказаниеУслуг.Организация КАК Организация, ОказаниеУслуг.Номенклатура КАК Номенклатура, СУММА(ОказаниеУслуг.СуммаДокумента) КАК СуммаДокумента ИЗ Документ.ОказаниеУслуг КАК ОказаниеУслуг СГРУППИРОВАТЬ ПО ОказаниеУслуг.Организация, ОказаниеУслуг.Номенклатура ИТОГИ ПО ОБЩИЕ, Организация, Номенклатура

В этом случае запрос вернет практически тоже самое что и такой запрос:

ВЫБРАТЬ ОказаниеУслуг.Организация КАК Организация, ОказаниеУслуг.Номенклатура КАК Номенклатура, ОказаниеУслуг.СуммаДокумента КАК СуммаДокумента ИЗ Документ.ОказаниеУслуг КАК ОказаниеУслуг ИТОГИ СУММА(СуммаДокумента) ПО ОБЩИЕ, Организация, Номенклатура

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

6. Разыменование полей.

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

Запрос:

Можно представить в виде:

ВЫБРАТЬ Оплата.Ссылка, Оплата.Организация, Оплата.Организация, Организации. АдминистративнаяЕдиница ИЗ Документ.Оплата КАК Оплата ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Организации КАК Организации ПО Оплата.Организация = Организации.Ссылка

При разыменовании ссылочных полей составного типа платформа пытается создать неявные соединения со всеми таблицами, которые входят в тип этого поля. В этом случае запрос будет неоптимален.Если четко известно, какого типа поле, необходимо ограничивать такие поля по типу конструкцией ВЫРАЗИТЬ() .

Например имеется регистр накопления "Нераспределенные оплаты", где регистратором могут выступать несколько документов. В этом случае неверно получать значения реквизитов регистратора таким образом:

ВЫБРАТЬ НераспределенныеОплаты.Регистратор.Дата, ..... ИЗ РегистрНакопления.НераспределеныеОплаты КАК НераспределенныеОплаты

следует ограничить тип составного поля регистратор:

ВЫБРАТЬ ВЫРАЗИТЬ(НераспределенныеОплаты.Регистратор КАК Документ.Оплата).Дата, ..... ИЗ РегистрНакопления.НераспределеныеОплаты КАК НераспределенныеОплаты

7. Конструкция "ГДЕ"

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

Пример. Необходимо выбрать всех Клиентов из Справочника клиенты и для тех клиентов, у которых имеется документ оплата со значением реквизита "Организация" = &Организация вывести документ "Оплата", для тех у кого нет, не выводить.

Результат запроса вернет записи только для тех клиентов, у которых была оплата по организации в параметре, а других клиентов отсеет. Поэтому необходимо сначала получить все оплаты по "такой-то" организации во временной таблице, а потом уже соединять со справочником "Клиенты" левым соединением.

ВЫБРАТЬ Оплата.Ссылка КАК Оплата, Оплата.Пайщик КАК Клиент ПОМЕСТИТЬ тОплаты ИЗ Документ.Оплата КАК Оплата ГДЕ Оплата.Отделение = &Отделение; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ Клиенты.Ссылка КАК Клиент, ЕСТЬNULL(тОплаты.Оплата, "") КАК Оплата ИЗ Справочник.Клиенты КАК Клиенты ЛЕВОЕ СОЕДИНЕНИЕ тОплаты КАК тОплаты ПО Клиенты.Ссылка = тОплаты.Клиент

Можно обойти это условие и другим способом. необходимо наложить условие "ГДЕ" непосредственно в связи двух таблиц. Пример:

ВЫБРАТЬ Клиенты.Ссылка, Оплата.Ссылка ИЗ Справочник.УС_Абоненты КАК УС_Абоненты ЛЕВОЕ СОЕДИНЕНИЕ Документ.Оплата КАК Оплата ПО (Клиенты.Ссылка = Оплата.Клиент И Оплата.Клиент.Наименование ПОДОБНО "Сахарный Пакет") СГРУППИРОВАТЬ ПО Клиенты.Ссылка, Оплата.Ссылка

8. Соединения с Вложенными и Виртуальными таблицами

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

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

ВЫБРАТЬ НераспределенныеОплатыОстатки.Клиент, НераспределенныеОплатыОстатки.СуммаОстаток ИЗ (ВЫБРАТЬ Клиенты.Ссылка КАК Ссылка ИЗ Справочник.Клиенты КАК Клиенты ГДЕ Клиенты.Ссылка В(&Клиенты)) КАК ВложенныйЗапрос ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.НераспределенныеОплаты.Остатки КАК НераспределенныеОплаты ПО ВложенныйЗапрос.Ссылка = НераспределенныеОплатыОстатки.Клиент

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

ВЫБРАТЬ Клиенты.Ссылка КАК Ссылка ПОМЕСТИТЬ тКлиенты ИЗ Справочник.Клиенты КАК Клиенты ГДЕ
Клиенты.Ссылка В (&Клиенты) ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ тКлиенты.Ссылка, НераспределенныеОплатыОстатки.СуммаОстаток, ИЗ тКлиенты КАК тКлиенты ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.НераспределенныеОплаты.Остатки(, Клиент В (ВЫБРАТЬ тКлиенты.Ссылка ИЗ тКлиенты)) КАК НераспределенныеОплатыОстатки ПО тКлиенты.Ссылка = НераспределенныеОплатыОстатки.Клиенты

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

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

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

ВЫБРАТЬ Клиенты.Ссылка КАК Ссылка ПОМЕСТИТЬ тКлиенты ИЗ Справочник.Клиенты КАК Клиенты ИНДЕКСИРОВАТЬ ПО Ссылка ГДЕ
Клиенты.Ссылка В (&Клиенты) ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ НераспределенныеОплаты.СуммаОстаток, НераспределенныеОплаты.Клиент КАК Клиент ПОМЕСТИТЬ тОстатки ИЗ РегистрНакопления.НераспределенныеОплаты.Остатки(, Клиент В (ВЫБРАТЬ тКлиенты.Ссылка ИЗ тКлиенты)) КАК НераспределенныеОплатыОстатки; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ тКлиенты.Ссылка, тОстатки.СуммаОстаток КАК СуммаОстаток ИЗ тКлиенты КАК тКлиенты ЛЕВОЕ СОЕДИНЕНИЕ тОстатки КАК тОстатки ПО тКлиенты.Ссылка = тОстатки.Клиент

9.Проверка результата выполнения запроса.

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

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

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

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

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

Это избавит систему от синтаксической проверки запроса в цикле.

11. Конструкция "ИМЕЮЩИЕ".

Конструкция, довольно редко встречающаяся в запросах. Позволяет накладывать условия на значения агрегатные функций (СУММА, МИНИМУМ, СРЕДНЕЕ и т.д.). Например, вам необходимо выбрать только тех клиентов, у которых сумма оплат в сентябре была больше 13 000 рублей. Если использовать условие "ГДЕ", то придется сначала создавать временную таблицу или вложенный запрос, там группировать записи по сумме оплаты и потом накладывать условие. Конструкция "ИМЕЮЩИЕ" поможет этого избежать.

ВЫБРАТЬ Оплата.Клиент, СУММА(Оплата.Сумма) КАК Сумма ИЗ Документ.Оплата КАК Оплата ГДЕ МЕСЯЦ(Оплата.Дата) = 9 СГРУППИРОВАТЬ ПО Оплата.Клиент ИМЕЮЩИЕ СУММА(Оплата.Сумма) > 13000

В конструкторе для этого достаточно перейти на вкладку "Условия", добавить новое условие и поставить галочку на "Произвольное". Далее просто написать Сумма(Оплата.Сумма) > 13000


12. Значение NULL

Я не буду описывать здесь принципы трехзначной логики в БД, есть множество статей на эту тему. Просто вкратце о том как NULL может повлиять на результат запроса. Значение NULL на самом деле не значение, а факт того, что значение не определено, неизвестно. Поэтому любые операции с NULL возвращают NULL, будь то сложение, вычитание, деление или сравнение. Значение NULL не может быть сравнимо со значением NULL, потому как мы не знаем, что именно сравнивать. Т.е. оба этих сравнения: NULL = NULL, NULL<>NULL - это не Истина или не Ложь, это неизвестно.

Давайте рассмотрим пример.

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

ВЫБРАТЬ "Нет оплат" КАК Признак, NULL КАК Документ ПОМЕСТИТЬ тОплаты; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ Клиенты.Ссылка КАК Клиент, Оплата.Ссылка КАК Оплата ПОМЕСТИТЬ тКлиентОплата ИЗ Справочник.Клиенты КАК Клиенты ЛЕВОЕ СОЕДИНЕНИЕ Документ.Оплата КАК Оплата ПО Клиенты.Ссылка = Оплата.Пайщик; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ тКлиентОплата.Клиент ИЗ тКлиентОплата КАК тКлиентОплата ВНУТРЕННЕЕ СОЕДИНЕНИЕ тОплаты КАК тОплаты ПО тКлиентОплата.Оплата = тОплаты.Документ

Обратите внимание на вторую временную таблицу тКлиентОплата. Левым соединением я выбираю всех клиентов и все оплаты по этим клиентам. Для тех же клиентов у которых нет оплат в поле "Оплата" будет NULL . Следуя логике, в первой временной таблице "тОплаты" я обозначил 2 поля, одно из них NULL, второе строка "Не имеет оплат". В третьей таблице я соединяю внутренним соединением таблицы "тКлиентОплата" и "тОплаты" по полям "Оплата" и "Документ". Мы знаем, что в первой таблице поле "Документ" это NULL, и во второй таблице у тех, у кого нет оплат в поле "Оплата" тоже NULL. Что же вернет нам такое соединение? А ничего не вернет. Потому как сравнение NULL = NULL не принимает значение Истина.

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

ВЫБРАТЬ "Нет оплат" КАК Признак, ЗНАЧЕНИЕ(Документ.Оплата.ПустаяСсылка) КАК Документ ПОМЕСТИТЬ тОплаты; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ Клиенты.Ссылка КАК Клиент, ЕСТЬNULL(Оплата.Ссылка, ЗНАЧЕНИЕ(Документ.Оплата.ПустаяСсылка)) КАК Оплата ПОМЕСТИТЬ тКлиентОплата ИЗ Справочник.Клиенты КАК Клиенты ЛЕВОЕ СОЕДИНЕНИЕ Документ.Оплата КАК Оплата ПО Клиенты.Ссылка = Оплата.Пайщик; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ тКлиентОплата.Клиент ИЗ тКлиентОплата КАК тКлиентОплата ВНУТРЕННЕЕ СОЕДИНЕНИЕ тОплаты КАК тОплаты ПО тКлиентОплата.Оплата = тОплаты.Документ

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

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

13. Недокументированная особенность конструкции "ВЫБОР КОГДА...ТОГДА....КОНЕЦ".

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

ВЫБРАТЬ ВЫБОР КОГДА Пользователи.Наименование = "Вася Пупкин" ТОГДА "Наш любимый сотрудник" ИНАЧЕ "Не знаем такого" КОНЕЦ КАК Поле1 ИЗ Справочник.Пользователи КАК Пользователи

А что делать, если, к примеру, нам надо получить название месяца в запросе? Писать огромную конструкцию в запросе некрасиво и долго, поэтому нас может выручить такая форма записи выше:

ВЫБОР МЕСЯЦ(УС_РасчетПотребления_ГрафикОбороты.ПериодРасчета) КОГДА 1 ТОГДА "Январь" КОГДА 2 ТОГДА "Февраль" КОГДА 3 ТОГДА "Март" КОГДА 4 ТОГДА "Апрель" КОГДА 5 ТОГДА "Май" КОГДА 6 ТОГДА "Июнь" КОГДА 7 ТОГДА "Июль" КОГДА 8 ТОГДА "Август" КОГДА 9 ТОГДА "Сентябрь" КОГДА 10 ТОГДА "Октябрь" КОГДА 11 ТОГДА "Ноябрь" КОГДА 12 ТОГДА "Декабрь" КОНЕЦ КАК Месяц

Теперь конструкция выглядит не такой громоздкой и легко воспринимается.

14. Пакетное выполнение запроса.


Для того, чтобы не плодить запросы, можно создать один большой запрос, разбить его на пакеты и работать уже с ним.
Например, мне нужно получить из справочника "Пользователи" поля: "ДатаРождения" и доступные роли для каждого пользователя. в выгрузить это в разные табличные части на форме. Конечно можно сделать это в одном запросе, тогда придется перебирать записи или сворачивать, а можно так:

ВЫБРАТЬ Пользователи.Ссылка КАК ФИО, Пользователи.ДатаРождения, Пользователи.Роль ПОМЕСТИТЬ втПользователи ИЗ Справочник.Пользователи КАК Пользователи; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ втПользователи.ФИО, втПользователи.ДатаРождения ИЗ втПользователи КАК втПользователи СГРУППИРОВАТЬ ПО втПользователи.ФИО, втПользователи.ДатаРождения; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ втПользователи.ФИО, втПользователи.Роль ИЗ втПользователи КАК втПользователи СГРУППИРОВАТЬ ПО втПользователи.ФИО, втПользователи.ДатаРождения

тПакет = Запрос.ВыполнитьПакет();

ТП_ДатыРождения = тПакет.Выгрузить();
ТП_Роли = тПакет.Выгрузить();

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

15. Условия в пакетном запросе

Например, у нас есть пакетный запрос, где сначало мы получаем поля: "Наименование, ДатаРождения, Код" из справочника "Пользователи" и хотим из справочника "ФизЛица" получить записи с условием по этим полям.

ВЫБРАТЬ Пользователи.ФизЛицо.Наименование КАК Наименование, Пользователи.ФизЛицо.ДатаРождения КАК ДатаРождения, Пользователи.ФизЛицо.Код КАК Код ПОМЕСТИТЬ втПользователи ИЗ Справочник.Пользователи КАК Пользователи; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ФизическиеЛица.Ссылка КАК ФизЛицо ИЗ Справочник.ФизическиеЛица КАК ФизическиеЛица

Можно накложить условия таким образом:

ГДЕ ФизическиеЛица.Код В (ВЫБРАТЬ втПользователи.Код ИЗ втПользователи) И ФизическиеЛица.Наименование В (ВЫБРАТЬ втПользователи.Код ИЗ втПользователи) И ФизическиеЛица.ДатаРождения В (ВЫБРАТЬ втПользователи.ДатаРождения ИЗ втПользователи)

А Можно и так:

ГДЕ (ФизическиеЛица.Код, ФизическиеЛица.Наименование, ФизическиеЛица.ДатаРождения) В (ВЫБРАТЬ втПользователи.Код, втПользователи.Наименование, втПользователи.ДатаРождения ИЗ втПользователи)

Причем обязателено соблюдать порядок.

16. Вызов конструктора запросов для "условия" в пакетном запросе

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

Необходимо после Конструкции "В" поставить скобки и между скобками оставить пустое место(пробел), выделить это место и вызвать контруктор запросов. Контруктору будут доступны все таблицы пакетного запроса. Прием работает как на виртуальных таблицах регистров, так и для вкладки "Условия". В последнем случае необходимо поставить галочку "П(произволное условие)" и войти в режим редактирования "F4".

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

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

upd1. Пункты 11,12
upd2. Пункты 13,14,15,16

Используемая литература:
Язык запросов "1С:Предприятия 8" - Е.Ю. Хрусталева
Профессиональная разработка в системе 1С:Предприятие 8".

Если моя публикация Вам полезна, не забудьте поставить плюсик:-)

Здесь рубрикатор по всем задачам сборника (страничка, где собраны ссылки на ветки форума по каждой задаче)
http://chistov.spb.ru/forum/16-969-1

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

Итак, приступим:


В случае удаленной сдачи у вас должно быть в конце экзамена на рабочем столе два объекта:

1. Итоговая выгрузка информационной базы (файл dt)
2. Пояснительная записка

Ничего другого быть не должно, никаких промежуточных копий и т.д.

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

Но об этом Вам и так будет сказано в инструкции, которую дадут прочесть перед началом экзамена.
Просто лучше знать заранее)


Использование знака амперсанда в запросах.

Иногда быстрее набрать с дополнительной клавиатуры, чем переключать туда-сюда раскладку, экономится время
& = Alt+38

*************************************************************************************************
Использование МоментВремени() в запросах

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

Момент = ?(РежимПроведения = РежимПроведенияДокумента.Оперативный, Неопределено, МоментВремени());

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

Код такой:

Движения.НазваниеРегистра.Записывать = Истина; Движения.НазваниеРегистра.Очистить();

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

Движения.НазваниеРегистра.Записать();

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

Но я везде просто указывал сразу конструкцию из этих трех строчек:

Движения.НазваниеРегистра.Записывать = Истина; Движения.НазваниеРегистра.Очистить(); Движения.НазваниеРегистра.Записать();

*************************************************************************************************
Есть два способа блокировки данных, выбор между ними зависит от методики проведения - старой или новой:

1) Обычная управляемая блокировка, старая методика проведения документа (объект БлокировкаДанных)

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


Пример:

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


1. Устанавливаем блокировку с помощью объекта БлокировкаДанных
2. Читаем остатки
3. Проверяем возможность списания
4. Формируем движения, к примеру списываем товар
5. После проведения документа блокировка автоматически снимается (блокировка действует в рамках транзакции проведения и снимается автоматически системой). То есть как-то специально разблокировать объект не надо.

2) Новая методика проведения документов (использование свойства БлокироватьДляИзменения = Истина)

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

Пример:
Рассмотрим операцию реализации товара.
В документе - количество, в регистре - только количество
Так вот, количество товара мы знаем из документа.
Мы формируем движения с указанным в документе количеством и записываем их. Далее читаем регистр, смотрим остатки, анализируем - есть ли отрицательные. Если есть выводим ошибку и ставим Отказ = Истина.

То есть последовательность такая:
1. Для движения по регистру устанавливаем свойство БлокироватьДляИзменения = Истина
2. Формируем движения - списываем товар
3. Записываем движения
4. Читаем регистр, смотрим, чтобы не было отрицательных остатков. Если есть - то списали лишнее, если нет - то все нормально.

Так вот, в этом случае нет необходимости указывать по каким измерениям нам надо блокировать регистр.
Мы просто устанавливаем свойство БлокироватьДляИзменения = Истина до записи наших движений, формируем движения и записываем.
Система сама заблокирует регистр в момент записи по тем измерениям, которые надо, проанализировав то, что мы записали.
После проведения блокировка снимется.

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

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

*************************************************************************************************
Блокировка данных (способ блокировки №1 из приведенного выше описания)

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

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

Блокировка = Новый БлокировкаДанных; ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах"); ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный; ЭлементБлокировки.ИсточникДанных = ТЧ; ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура"); Блокировка.Заблокировать();

*************************************************************************************************
Табличную часть документов лучше называть просто "ТЧ"

Табличная часть в 99% документов - одна. Такое унифицированное название табличных частей очень поможет сэкономить время, так как:
1) Очень короткое - быстро писать
2) Одинаковое для всех документов, не придется вспоминать при написании кода как она называется

*************************************************************************************************
Результат запроса проверять на пустоту перед выборкой или выгрузкой в ТЗ.

Вообще во всех задачах использовал выборку.

Выборка более оптимальна для системы с точки зрения производительности, так как "заточена" только для чтения данных (в отличие от ТЗ).

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

Результат = Запрос.Выполнить(); Если Не Результат.Пустой() Тогда Выборка = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); ... КонецЕсли;

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

Результат = Запрос.Выполнить(); Если Не Результат.Пустой() Тогда Выборка = Результат.Выбрать(); Выборка.Следующий(); МетодСписанияСебестоимости = Выборка.МетодСписанияСебестоимости; КонецЕсли;

*************************************************************************************************
Документ "Операция" для задачи по БУ

Обязательно нужно создавать документ Операция для задач по БУ.

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

*************************************************************************************************
Оперативное проведение документов:

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

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

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

*************************************************************************************************
Условие в запросе вида "Или указанная номенклатура или любая, если не указана"

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

Номенклатура = &Номенклатура ИЛИ &Номенклатура = Значение(Справочник.Номенклатура.ПустаяСсылка)

Но более оптимально и правильнее это условие будет преобразовать (спасибо yukon):


Запрос.Текст = Запрос.Текст + " ГДЕ Номенклатура = &Номенклатура";

КонецЕсли;

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

Если ЗначениеЗаполнено(Номенклатура) Тогда
Запрос1.Отбор.Добавить("Номенклатура = &Номенклатура");
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
КонецЕсли;

*************************************************************************************************
Присоединение таблиц в запросах:

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

Если требуется присоединить таблицу без всяких условий, то на закладке с условиями просто писать условие "ИСТИНА".
В этом случае таблица присоединится точно.

*************************************************************************************************
Использование плана видов характеристик (ПВХ):

1. Использование в качестве механизма описания характеристик объектов.

1.1. Создаем ПВХ. Это будут ВидыХарактеристик (например, цвет, размер, макс. скорость и т.д.). В настройках выбираем все возможные типы значений характеристик и если нужно создаем объект из пункта 1.2 и указываем его также в настройках.

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

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

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

2. Использование ПВХ для создания механизма субконто регистра бухгалтерии .

2.1. Создаем ПВХ ВидыСубконто.

2.2. Создаем подчиненный справочник ЗначенияСубконто (как с характеристиками, в нем будут значения субконто, если нет таких в других справочниках).

2.3. Связь производится с помощью плана счетов.

*************************************************************************************************
Ресурсы регистра бухгалтерии:

Сумма - балансовый,
Количество - небалансовый и связан с признаком учета Количественный

*************************************************************************************************
Виртуальные таблицы регистра бухгалтерии:

Обороты: обороты какого-то одного счета
ОборотыДтКт: обороты между какими-то двумя счетами, то есть все одинаковые проводки за период.

*************************************************************************************************
Валютный учет на регистрах бухгалтерии - как реализовать:

Создаем признак учета "валютный" в плане счетов.
В регистре бухгалтерии создаем дополнительно:
- измерение Валюта (запрет незаполненных значений, небалансовый, признак учета - валютный)
- ресурс ВалютнаяСумма (небалансовый, признак учета - валютный, в нем будет хранится сумма в валюте, то есть 100$ например)
Все.

Таким образом структура регистра:

Измерения:
- Валюта
Ресурсы
- Количество
- Сумма (сумма в рублях)
- ВалютнаяСумма (сумма в валюте)

Таким образом валютный учет - это лишь доработка обычного учета на РБ, он не изменяет сути к примеру ресурса Сумма
(там как и обычно сумма в рублях, независимо от того, валютный ли счет или нет).
И если признак учета Валютный для счета выключен, то это обычная структура РБ (ресурсы - только количество и сумма).

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

Иначе получим не срез последних, а последнюю запись с указанным значением ресурса - она может быть не последней по набору измерений

*************************************************************************************************
Смысл ресурса и реквизита в регистре расчета

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

А значение реквизита доступно только в реальной таблице регистра расчета, в виртуальных таблицах его нет.

*************************************************************************************************
Галочка "Базовое" в свойствах измерения регистра расчета
Означает, что по этому измерению в дальнейшем будет получаться база и служит для дополнительной индексации значений по этому полю.

*************************************************************************************************
Разбивка периода действия отпуска по месяцам при записи наборов записей регистра,
в случае если отпуск задается в документе одной строкой сразу на несколько месяцев одной строкой:

ДатаНачалаТекМесяца = НачалоМесяца(ТекСтрокаОсновныеНачисления.ПериодДействияНачало); ДатаОкончанияТекМесяца = КонецМесяца(ТекСтрокаОсновныеНачисления.ПериодДействияНачало); ТекМесяц = Дата; Пока ДатаНачалаТекМесяца <= НачалоМесяца(ТекСтрокаОсновныеНачисления.ПериодДействияКонец) Цикл Движение = Движения.ОсновныеНачисления.Добавить(); Движение.Сторно = Ложь; Движение.ВидРасчета = ТекСтрокаОсновныеНачисления.ВидРасчета; Движение.ПериодДействияНачало = Макс(ДатаНачалаТекМесяца, ТекСтрокаОсновныеНачисления.ПериодДействияНачало); Движение.ПериодДействияКонец = КонецДня(Мин(ДатаОкончанияТекМесяца, ТекСтрокаОсновныеНачисления.ПериодДействияКонец)); Движение.ПериодРегистрации = Дата; Движение.Сотрудник = ТекСтрокаОсновныеНачисления.Сотрудник; Движение.Подразделение = ТекСтрокаОсновныеНачисления.Подразделение; Движение.Сумма = 0; Движение.КоличествоДней = 0; Движение.График = ТекСтрокаОсновныеНачисления.График; Движение.Параметр = ТекСтрокаОсновныеНачисления.Параметр; Движение.БазовыйПериодНачало = НачалоМесяца(ДобавитьМесяц(Дата, -3)); Движение.БазовыйПериодКонец = КонецДня(КонецМесяца(ДобавитьМесяц(Дата, -1))); ДатаНачалаТекМесяца = НачалоМесяца(ДобавитьМесяц(ДатаНачалаТекМесяца, 1)); ДатаОкончанияТекМесяца = КонецМесяца(ДатаНачалаТекМесяца); КонецЦикла; КонецЕсли;

*************************************************************************************************
Построение Диаграммы Ганта:

Размещаем на форме элемент типа "ДиаграммаГанта", называем ДГ, далее создаем команду "Сформировать" и в модуле формы пишем следующее:

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

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

*************************************************************************************************
Обработка записей "сторно" в расчетных задачах:

В процедуре обработки проведения (модуль объекта) формируем все движения, а далее если есть записи в других периодах получим их так
(система формирует их автоматически - помогает нам):

ЗаписиДополнения = Движения.ОсновныеНачисления.ПолучитьДополнение(); // Записывать движения для получения дополнения не нужно

Для Каждого ТекСтрока Из ЗаписиДополнения Цикл
Запись = Движения.ОсновныеНачисления.Добавить();
ЗаполнитьЗначенияСвойств(Запись, ТекСтрока);
Запись.ПериодРегистрации = ТекСтрока.ПериодРегистрацииСторно;
Запись.ПериодДействияНачало = ТекСтрока.ПериодДействияНачалоСторно;
Запись.ПериодДействияКонец = ТекСтрока.ПериодДействияКонецСторно;
КонецЦикла

А при расчете записей вставлять проверки:

Если ТекДвижение.Сторно Тогда
ТекДвижение.Сумма = - ТекДвижение.Сумма;
КонецЕсли;

*************************************************************************************************
Как определить что относить в основным начислениям, а что - к дополнительным в расчетных задачах.

Но не всегда это на 100% ясно, бывают и случаи посложней, хотя их довольно мало
(например премия, которая зависит от количества рабочих в месяце дней - это ОН).

Основные начисления:
Если по виду расчета есть зависимость от графика (имеется в виду регистр сведений с датами календаря), то он относится к основным начислениям.

Пример ОН:
- Оклад
- Что-то, что считается от количества рабочих дней (а для этого нужно использовать график): либо в периоде действия (как оклад), либо в базовом периоде

Дополнительные начисления:
То, что считается либо от начисленной суммы, либо ОТРАБОТАННОГО (а не нормы!) времени, либо вообще не зависит - это доп. начисления.

То есть: начисления для расчета которых используется норма времени (может еще и факт) - это ОН, а для которых фактические данные или вообще ничего не нужно - это ДН.

Или другими словами:

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

*************************************************************************************************
Добавить возможность в форме списка справочника "Номенклатура" возможность открытия раздела встроенной справки "Работа со справочниками".

Сделать на форме команду:

&НаКлиенте
Процедура Справка(Команда)
ОткрытьСправку("v8help://1cv8/EnterprWorkingWithCatalogs");
КонецПроцедуры

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

*************************************************************************************************
Осуществление взаимодействия между формами, например, подбор:

1. Из текущей формы открываем нужную методом "ОткрытьФорму()", вторым параметром передаем структуру с параметрами (если надо). Третьим параметром можем передать ссылку на эту форму - ЭтаФорма.

2. В открываемой форме в обработчике "ПриСозданииНаСервере()" мы можем поймать переданные в п.1 параметры через "Параметры.[ИмяПараметра]". Форма, которая инициализировала открытие этой формы, будет доступна через идентификатор "Владелец" (если она конечно была указана в п.1).

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

*************************************************************************************************
Жизненный цикл параметров формы

Все параметры, переданные в форму в момент ее открытия видны только в процедуре «ПриСозданииНаСервере».
После создания все параметры уничтожаются и более не доступны в форме.
Исключение составляют параметры, которые в редакторе формы объявлены с признаком «Ключевой параметр».
Они определяют уникальность формы.
Такой параметр будет существовать до тех пор, пока существует сама форма.

*************************************************************************************************
Использование интерфейса "Такси"

При разработке можно установить в свойствах конфигурации обычный управляемый интерфейс 8.2 - так все заметно компактнее и привычнее.
Особенно это актуально, если сдаете удаленно - разрешение экрана очень маленькое, с интерфейсом "такси" невозможно ничего сделать.
Только не забудьте когда все сделаете поставить снова "Такси"! Иначе экзаменатор снимет балы!

*************************************************************************************************

PS: Есть отдельные типовые подзадачи, которые используются во всех задачах, именно их и нужно уметь решать (например, списание по партиям, использование ПВХ (ну это правда редко) и другие). И во всех задачах они просто повторяются (где-то одни подзадачи есть, где-то другие, просто в разных комбинациях). Тем более, что сборник же уже давно обещали новый выпустить (если еще не выпустили), в котором вроде задач должно быть намного больше, то есть нет смысла запоминать решения отдельных задач, есть смысл научиться решать отдельные типовые подзадачи, тогда решишь любую задачу.

PSS: Коллеги, если у кого-нибудь есть еще какая-либо полезная информация по подготовке к экзамену и сдаче, просьба писать в комментариях, дополним статью.