При работе с документами в 1С очень часто возникает необходимость просматривать их движения по регистрам. И при работе с обычными формами в режиме толстого клиента никаких проблем не возникало. Кнопка Перейти и далее можно выбрать по какому регистру будем смотреть движения или сформировать отчет о движениях документа по всем регистрам.
Но когда в первый раз сталкиваешься с такой необходимостью в управляемом приложении, то оказывается, что не все так просто. И на первый взгляд кажется, что это вообще невозможно, т.к. в меню никаких подходящих команд обнаружить не удается. Конечно же сразу приходит в голову вариант воспользоваться консолью запросов. И этот вариант вполне рабочий. Правда постоянно писать запросы для выборки движений по каждому конкретному документу не очень удобно.
И тем не менее с помощью определенных настроек мы можем добиться нашей цели и переходить к движениям регистров непосредственно из документа. Рассмотрим это на примере демо версии конфигурации ЗУП 3.1.
Итак, откроем любой документ Начисление зарплаты и взносов. В Шапке документа нет кнопки ПЕРЕЙТИ и нет ссылок на регистры движений, добавим их: выберем пункт меню Вид – Настройка панели навигации формы
В открывшемся окне выберем регистры, движения которых нам надо видеть и перенесем их в правую панель
В результате этих манипуляций шапка документа будет отображать названия регистров движений документа
И теперь, щелкнув по этим ссылкам, можно просматривать движения документа.
Разберем, как изменялся (скорее дополнялся) синтаксис текстов запросов на простом примере: Проводится документ Расходная содержащая в табличной части Товары список продаваемых товаров и количество. При проведении такого документа необходимо обеспечить контроль отрицательных остатков хранящихся в регистре накопления остатков ОстаткиТоваров.
Структура конфигурации представлена на рисунке справа:
Сформируем запрос к табличной части документа и виртуальной таблице Остатки регистра накопления. Учтем возможные дубли строк в документе, для этого произведем группирование записей.
Естественно приведенный запрос абсолютно не оптимален. С помощью вложенных запросов оптимизируем его: Произведем группирование табличной части документа до соединения с таблицей остатков, в параметры виртуальной таблицы передадим список товаров как значение условия для расчета остатков. В итоге наш запрос примет следующий вид:
Если бы в запросе необходимо было бы получить данные из остатков разных регистров то значение фильтра, а следовательно и наш второй вложенный запрос, повторялся бы во всех параметрах виртуальных таблиц, естественно что система при каждом вложенном запросе заново обращается к базе данных для получения данных.
Временные таблицы
Не помню уже с какого релиза в запросах стало можно использовать временные таблицы. Для этого используется объект «Менеджер временных таблиц». Фактически менеджер временных таблиц описывает пространство имен временных таблиц и отвечает за их создание и уничтожение в базе данных.
Сами временные таблицы действительно физически создаются в базе, соответственно следует относиться к ним осторожно, так как дисковая подсистема на сегодняшний момент самая медленная часть техники, а скорость создания и уничтожения таблиц напрямую от нее зависит.
Перепишем запрос для использования временных таблиц. Во временные таблицы поместим сгруппированную табличную часть документа и список товаров для фильтра виртуальных таблиц:
При использовании временных таблиц в тексте запроса применяют инструкцию Поместить для создания новой временной таблицы, в этом случае в результат запроса система передает не содержимое этой таблицы (см прим 1 и прим 2 в тексте выше), а количество записей помещенных во временную таблицу, по желанию можно не принимать это значение.
Также допускается использование инструкции Уничтожить в этом случае временная таблица уничтожается, в противном случае временные таблицы уничтожаются вместе с объектом менеджер временных таблиц.
В основном нашем запросе я использовал названия временных таблиц как указание на источник получения данных (им обязательно надо назначать синоним, что мы и видим в тексте). Использовать временные таблицы как источник можно не единожды, что при умелом их применении позволит и сократить текст запроса (улучшиться читабельность сложных запросов) и увеличить скорость (при использовании данных временной таблицы в нескольких местах запроса).
Пакетные запросы
Пакетные запросы логично дополняют функционал временных таблиц и дают больше возможностей при работе с запросами.
В пакетном запросе фактически можно описать несколько запросов, как связанных между собой использованием временных таблиц, так и не связанных (можно, но не понятно зачем?). В итоге можно выполнить последовательно все запросы и принять в результате либо массив с результатами исполнения каждого запроса, либо результат последнего. Для получения массива с результатами запроса применяют метод ВыполнитьПакет() объекта запрос, а для получения результата последнего запроса ВыполнитьЗапрос().
В тексте запроса, запросы пакета разделяются символом «;» (точка с запятой). Область имен виртуальных таблиц у одного пакетного запроса одна. Использование менеджера временных таблиц не требуется, но возможно если вы хотите передать временные таблицы из одного пакетного запроса в другой.
Перепишем процедуру для использования пакетных запросов:
Фактически я убрал определение объекта запрос и использование менеджера временных таблиц, объединил тексты запросов (обратите внимание на разделитель «;» между текстами). В результате текст запроса стал читабельнее (а при использовании конструктора запросов намного увеличивается удобство чтения запроса).
После выполнения запроса в переменную МассивРезультатов у нас попадет 3 элемента. Первые два будут содержать число характеризующее количество записей помещенных во временные таблицы ДокТЧ и СписокТоваров, а третий будет содержать выборку с полями Номенклатура, Док_Количество и Рег_Количество.
В переменную РезультатЗапроса попадет только выборка.
Ну вот и все что касается пакетных запросов. Очень удобный механизм и с точки зрения написания запросов и с точки зрения чтения сложных запросов.
Если в запросе используется конструкция вида регистратор.дата или получение еще какого-либо реквизита через регистратор и это поле не отображается в полях отчета СКД, то:
Допустим Вы сделали запрос по регистру накоплений и через регистратор обратились к дате или сумме документа и при формировании отчета СКД, эти поля недоступны !? как же быть?
Проблема в том - что у регистратором может выступать несколько документов и видимо права чтение/просмотр есть не на все - поэтому через скд эта таблица целиком недоступна, решение:
Что при разработке отчетов требуется чтобы у пользователя с ограниченными правами, отчет формировался полностью без проверки прав!
Особенно если настроен RLS
Есть несколько способов как это сделать:
1. Установить привилегированный режим в модуле отчета
Форма отчета должна быть Управляемой, далее в модуле отчета процедура обработчика «При компоновке результата»:
2. Формирование в привилегированном режиме через Общий модуль с галкой Привелигерованный
Создаем общий модуль
так же как в пункте 1 в обработчике «При компоновке результата» пишем:
В общем модуле МЕ_ДляОтчетаСКД_ПривелРежим код:
3. Если включен режим Использовать ограничение на уровне прав доступа - RLS
Часто используется в типовых. Тут в модуле для текущего пользователя можно на время формирования отчету установить параметр сеанса ИспользоватьОграниченияПравДоступаНаУровнеЗаписей в Ложь и RLS не сработает.
После завершения формирования, не забудьте включить rls обратно установив = Истина
4. Если в запросе используется конструкция вида регистратор.дата и это поле не отображается в полях отчета СКД
Допустим Вы сделали запрос по регистру накоплений и через регистратор обратились к дате или сумме документа и при формировании отчета СКД, эти поля недоступны !? как же быть?
Проблема в том - что у регистратором может выступать несколько документов и видимо права чтение/просмотр есть не на все - поэтому через скд эта таблица целиком недоступна, решение:
1. открыть доступ на все регистраторы регистра
2. в запросе четко обозначить тип
В дополнении у пункту 1, код процедуры сформировать отчет(). Для вывода отчета я использую шаблон All4CF.ru_Template_SKD_v4.1 в нем уже реализованы почти все необходимые функции и работает в Обычных и УП формах:
Связка сервера 1С:Предприятие и PostgreSQL вторая по популярности среди установок 1С и самое используемое решение на платформе Linux. В отличии внедрений на базе Windows и MSSQL, где трудно сделать так, чтобы не заработало, внедрения на базе Linux таят множество подводных камней для неопытного администратора. Часто бывает так, что вроде бы все сделано правильно, но ошибка следует за ошибкой. Сегодня мы рассмотрим самые типовые из них.
Общая информация
Перед тем, как начинать искать ошибки установки и, вообще, приступать к внедрению серверной версии 1С:Предприятия было бы неплохо освежить представление как это работает:
Сервер 1С Предприятия. Часть 1 - Общие вопросы.
В небольших внедрениях сервер 1С и сервер СУБД обычно совмещают на одном физическом сервере, что немного сужает круг возможных ошибок. В нашем случае будет рассматриваться ситуация, когда сервера разнесены по разным машинам. В нашей тестовой лаборатории мы развернули следующую схему:
В нашем распоряжении имеются два сервера под управлением Ubuntu 12.04 x64, на одном из них установлен сервер 1С:Предприятие версии 8.3, на другом PostgreSQL 9.04 от Ethersoft, а также клиент под управлением Windows. Напоминаем, что клиент работает только с сервером 1С, который, в свою очередь, формирует необходимые запросы к серверу СУДБ. Никаких запросов от клиента к серверу управления базами данных не происходит.
Сервер баз данных не обнаруженВАЖНО: пользователь "postgres" не прошёл проверку подлинности (Ident)
Данная ошибка возникает при разнесении серверов по разным ПК из-за неправильно настроеной проверки подлинности в локальной сети. Для устранения откройте /var/lib/pgsql/data/pg_hba.conf, найдите строку:
host all all 192.168.31.0/24 ident[/pre]
и приведите ее к виду:
host all all 192.168.31.0/24 md5[/pre]
где 192.168.31.0/24 - диапазон вашей локальной сети. Если такой строки нет, ее следует создать в секции IPv4 local connections.
Сервер баз данных не обнаруженcould not translate host name "NAME" to address: Temporary failure in name resolution
На первый взгляд ошибка понятна: клиент не может разрешить имя сервера СУБД, типичная ошибка для небольших сетей, где отсутствует локальный DNS-сервер. В качестве решения добавляют запись в файлhosts на клиенте, что не дает никакого результата...
А теперь вспоминаем, о чем было сказано несколько раньше. Клиентом сервера СУБД является сервер 1С, но никак не клиентский ПК, следовательно запись нужно добавлять на сервере 1С:Предприятие в файл/etc/hosts на платформе Linux или в C:\Windows\System32\drivers\etc\hosts на платформе Windows.
Аналогичная ошибка будет возникать, если вы забыли добавить запись типа A для сервера СУБД на локальном DNS-сервере.
Ошибка при выполнении операции с информационной базойserver_addr=NAME descr=11001(0x00002AF9): Этот хост неизвестен.
Как и прошлая, эта ошибка связана с неправильным разрешением клиентом имени сервера. На этот раз именно клиентским ПК. В качестве решения добавляем в файл /etc/hosts на платформе Linux или в C:\Windows\System32\drivers\etc\hosts на платформе Windows запись вида:
192.168.31.83SRV-1C-1204[/pre]
где указываете адрес и имя вашего сервера 1С:Предприятия. В случае использования локального DNS следует добавить A-запись для сервера 1С.
Ошибка СУБД: DATABASE не пригоден для использования
Гораздо более серьезная ошибка, которая говорит о том, что вы установили несовместимую с 1С:Предприятие версию PostgreSQL или допустили грубые ошибки при установке, например не установили все необходимые зависимости, в частности библиотеку libICU.
Если вы имеете достаточный опыт администрирования Linux систем, то можете попробовать доустановить необходимые библиотеки и заново инициализировать кластер СУБД. В противном случае PostgreSQL лучше переустановить, не забыв удалить содержимое папки /var/lib/pgsql.
Также данная ошибка может возникать при использовании сборок 9.1.x и 9.2.x Postgre@Etersoft, подробности смотрите ниже.
Ошибка СУБД: ERROR: could not load library "/usr/lib/x86_64-linux-gnu/postgresql/fasttrun.so"
Довольно специфичная ошибка, характерная для сборок 9.1.x и 9.2.x Postgre@Etersoft, также может приводить предыдущей ошибке. Причина кроется в неисправленной ошибке в библиотеке fasttrun.so. Решение - откатиться на сборку 9.0.x Postgre@Etersoft.
Ошибка СУБДERROR: type "mvarchar" does not exist at character 31
Возникает если база данных была создана без помощи системы 1С:Предприятия. Помните, для работы с 1С базы данных следует создавать только с использованием инструментов платформы 1С: через консоль Администрирование серверов 1С Предприятия
или через средство запуска 1С.
Сервер баз данных не обнаруженВАЖНО: пользователь "postgres" не прошёл проверку подлинности (по паролю)
Очень простая ошибка. Неправильно указан пароль суперпользователя СУБД postgres. Вариантов решения два: вспомнить пароль или изменить его. Во втором случае вам нужно будет изменить пароль в свойствах всех существующих информационных баз через оснастку Администрирование серверов 1С Предприятия.
Сервер баз данных не обнаруженFATAL: database "NAME" does not exist
Еще одна очень простая ошибка. Смысл ее сводится к тому, что указанная БД не существует. Чаще всего возникает из-за ошибки в указании имени базы. Следует помнить, что информационная база 1С в кластере и база данных СУБД - две разные сущности и могут иметь различные имена. Также следует помнить, что Linux системы чувствительны к регистру и для них unf83 и UNF83 два разных имени.
В некоторых типовых конфигурациях фирмы 1С существует возможность ручной корректировки движений документа по регистрам. В конфигурации 1С: Бухгалтерия 8 для этого, при наличии соответствующих прав, нужно открыть движения документа и установить флаг “Ручная корректировка”. Однако, иногда возникает необходимость выполнить корректировку движений большого количества документов. В этом случае нам понадобится обработка, которая изменит движения документов без перепроведения.
Рассмотрим как изменить движения документа на примере конфигурации 1С: Бухгалтерия 8. Менять будем движения по регистру бухгалтерии “Хозрасчетный”. Пусть перед нами стоит задача заполнить суммы налогового учета по данным бухгалтерского. Предположим, что у нас уже есть обработка, которая выбирает необходимые нам документы и последовательно обрабатывает их с помощью описанной нами процедуры “ИзменитьДвиженияДокумента”. Посмотрим как должна выглядеть эта процедура.
Хотелось бы отметить, что без проверки ведения налогового учета на счёте, при попытке записать набор, содержащий проводку с ненулевой суммой по счёту на котором не ведется налоговый учет, возникнет ошибка следующего содержания:
Запись не верна! Поле “Сумма (налоговый учет)” должно быть пустым! (Регистр бухгалтерии: Журнал проводок (бухгалтерский и налоговый учет); Номер строки: 1)
Режим обмена данными устанавливается следующими строками:
Это необходимо для того, чтобы не выполнялся программный код, находящийся в обработчиках событий “ПередЗаписью” модуля набора записей регистра бухгалтерии “Хозрасчетный” и модуля корректируемого документа. В каждом из них (для типовых конфигураций) есть проверка следующего вида:
Признак ручной корректировки документа (ДокументОбъект.РучнаяКорректировка = Истина) необходимо устанавливать для того, чтобы изменения сохранились при повторном проведении документа. При проведении такого документа в конфигурации 1С:Бухаглерия 8 выдается следующее сообщение:
Движения документа отредактированы вручную и не могут быть автоматически актуализированы.
gvk2009 подробно и доходчиво описал разницу методов, за что ему огромное спасибо:
В Синтаксис-Помощнике очень скупо написано о процедуре ДанныеФормыВЗначение(), чуть побольше - о РеквизитФормыВЗначение(). И совсем нет примеров использования. Попробуем с этим разобраться.
РеквизитФормыВЗначение()
Является методом управляемой формы, компилируется только &НаСервере, контекст формы является для него необходимым, поэтому компиляция &НаСервереБезКонтекста недоступна. На клиенте не работает, поскольку в результате получаем прикладной объект.
Где и когда его нужно использовать?
Метод РеквизитФормыВЗначение() необходим, если требуется из модуля формы вызвать стандартный метод объекта или метод (процедуру, функцию) из модуля объекта, из общего модуля.
Этот метод будет отрабатывать с данными, взятыми из формы, т.е. еще не записанными в базу.
Для того, чтобы измененные данные вернуть на форму, используется метод ЗначениеВРеквизитФормы().
Вторым параметром метода РеквизитФормыВЗначение является тип значения. Это необязательный параметр. Если обрабатываемый реквизит не является составным типом, то тип будет автоматически получен из реквизита формы. Иначе генерируется исключение времени выполнения.
Примеры:
В указанных выше случаях метод РеквизитФормыВЗначение() похож на метод ПолучитьОбъект(). Разница в том, что первый получает объект, заполненный данными формы, а второй - объект с данными из базы.
ДанныеФормыВзначение()
В отличие от метода управляемой формы РеквизитФормыВЗначение(), процедура глобального контекста ДанныеФормыВЗначение() может работать без контекста формы, но именно поэтому, в частности, ей необходимо указывать тип конвертируемых данных.
Обратной процедурой является ЗначениеВДанныеФормы().
Примеры:
В этом примере на форме отображен набор записей регистра бухгалтерии. При отработке процедуры, активность набора меняется только на форме, в базе при этом ничего не происходит. Активность у набора записей регистра в базе поменяется только после выполнения операции Записать.
В этом примере на клиент возвращается ОснРеквизит, содержащий измененные данные. Но его еще нужно "запихать" в отображаемую форму. Для этого используем процедуру глобального контекста КопироватьДанныеФормы().
В большинстве случаев процедуры ДанныеФормыВзначение() и РеквизитФормыВЗначение() взаимозаменяемы. При этом РеквизитФормыВЗначение проще в использовании. Но если требуется использование &НаСервереБезКонтекста - тогда только ДанныеФормыВЗначение.
В качестве иллюстрации взаимозаменяемости Пример 2 еще в двух вариантах:
Бывают ситуации, когда в запросе требуется получить остатки не на фиксированную дату (параметр - один на весь отчет), а на произвольную, (когда дата остатков в каждой строке своя).
Существует несколько способов получить нужные данные.
1.Непосредственно в запросе (через реальную таблицу регистра)
Способ подходит практически для любой ситуации, и поэтому наиболее универсален. Единственный, пожалуй, минус этого способа - если в отчете пользователю не требуется курс, то запрос быдет выбирать избыточные данные.
Вызов СрезПоследних() можно использовать только с передачей в него заранее готового значения даты, на которую требуется получить значения. Поэтому сабж делается через стыковку нескольких запросов - основной, к нему стыкуется запрос по регистру сведений с условием по дате и поиском записи с максимальной датой (периодом).
Для общего развития: Что есть срез последних в платформе?
В зависимости от периодичности регистра (по времени, по позизии регистратора) ВТ разворачивается в следующий запрос:
1. По времени (год, месяц, ... секунда)
2. По позиции регистратора
В данном случае нужно еще раз обернуть выборку
Все это можно увидеть посмотрев технологический журнал с включенным режимом протоколирования запросов
2.Система компоновки данных (передача набора значений одной таблицы в параметр виртуальной таблицы)
Данный способ подходит для отчетов. Из очевидных плюсов - если курс (или другие данные) не нужны для построения отчета, то СКД не будет их получать. Однако быстродействие такого отчета может оказаться и несколько ниже, чем в первом способе.
Для примера сделаем отчет - список заказов покупателей.
Для этого создадим набор данных "Документы" - запрос:
Для того, чтобы потом успешно свзать наборы данных, в запрос необходимо включить поля "Дата" и "ВалютаДокумента". Чтобы они не появлялись в списке доступных полей, если это необходимо, их можно убрать, установив флажки ограничений в таблице "Поля" схемы компоновки. В остальном запрос вряд ли требует комментариев.
Для того, чтобы получить информацию о курсах валют, добавим второй набор данных-запрос, "Курсы валют":
В этом запросе имеются 2 параметра: "Дата" и "Валюта". Эти параметры будут установлены СКД при соединении наборов. Кроме того, параметр "Дата" указан в выбранных полях - это нужно для соединения таблиц.
Для ненужный полей "Дата" и "Валюта" также устанавливаем флажки ограничений, чтобы они не появлялись в доступных полях.
Перейдем к соединению наборов. На странице "Связи наборов данных" добавим 2 связи:
1. Источник связи - набор "Документы", приемник - набор "Курсы валют". Выражение источник - "Дата", выражение приемник - "Дата", Параметр - "Дата"
2. Источник связи - набор "Документы", приемник - набор "Курсы валют". Выражение источник - "ВалютаДокумента", выражение приемник - "Валюта", Параметр - "Валюта"
Главное здесь - параметры связи. При соединении наборов данных, если указан параметр, СКД передает в подчиненный набор (в нашем случае - запрос "Курсы валют") параметры, указанные в соединении. Значениями параметров будут значения соответствующих полей набора-источника.
Перейдем к вычисляемым полям. Добавим вычисляемое поле "СуммаВВалютеУпрУчета". Выражение поля - "СуммаДокумента * Курс / Кратность".
Также укажем поля "СуммаДокумента" и "СуммаВВалютеУпрУчета" как ресурсы
Настроим отчет.
Добавим одну группировку "Детальные записи", в выбранных полях укажем "ЗаказПолкупателя", "Курс" и "Кратность". Добавим ресурсы "СуммаДокумента" и "СуммаВВалютеУпрУчета"
Собственно процесс расчета записей каждого поднабора состоит в получении всех необходимых данных для расчета каждой записи и вычислении значений ресурсов этой записи по формуле, определяемой способом расчета данной записи. Например, для расчета записи об окладе нужно будет получить данные графика этой записи, для расчета премии необходимо будет рассчитать базу и так далее.
Ниже приведен пример процедуры, осуществляющей расчет набора записей одного приоритета. Для каждой записи при помощи функции ПолучитьДанныеДляРасчета() возвращается структура данных, которая передается в процедуру РассчитатьЗапись().
Расчет набора записей одного приоритета
В функции ПолучитьДанныеДляРасчета() должны быть прописаны алгоритмы, при помощи которых можно получить данные для расчета записи с любым способом расчета, существующим в конфигурации. Ниже приведен пример функции, которая получает данные для трех способов расчета:
Получение данных для трех видов расчета
В данном случае для расчета записей со способом ПоМесячнойСтавке система получит данные графика за период действия и фактический период действия, для способа ПроцентомОтБазы будет получена расчетная база записи, а для способа ПоСдельнойВыработке будут рассчитаны обороты по соответствующему регистру накопления за интервал периода действия записи. Способ расчета ФиксированнойСуммой не требует получения данных.
Функция ПолучитьДанныеДляРасчета() возвращает структуру, содер- жащую различные поля в зависимости от способа расчета, применяемого в данной записи
Расчет значений ресурсов записи
После того как данные для расчета получены, необходимо прописать в модуле формулу для заполнения реквизитов каждой записи в соответствии со способом расчета. В данном случае эту функцию выполняет процедура РассчитатьЗапись(). В процедуре РассчитатьЗапись() для каждого возмож- ного способа расчета описывается формула, позволяющая из реквизитов записи и полученных данных рассчитать значения ресурсов этой записи.
Процедура расчета записей
При расчете записей следует учитывать, что сторно-записи рассчитываются в общем порядке. Поэтому в ресурсы сторно-записи должно попадать отрицательное значение результата расчета. Например, сторно- запись отменяет начисленный оклад за период 5 дней. При расчете такой записи по формуле система получит сумму оклада за 5 дней, например, 1200 руб. В ресурс сторно-записи в этом случае должно быть записано значение -1200.
При работе с регистрами расчета есть возможность получения базовых данных. Это своеобразный способ расчета оборотов регистра, при котором функция расчета оборотов не является простой функцией суммирования ресурсов регистра по измерениям за определенный период, а представляет собой более сложную функцию. Эта функция зависит от состояния плана видов расчета, назначенного регистру расчета и, таким образом, управляется пользователем.
В данном разделе мы рассмотрим два существующих в системе способа получения базовых данных - при помощи языка запросов и при помощи функциональной записи, методом ПолучитьБазу(). При этом будет называть "основным" регистром расчета тот регистр, для которого необходимо получить базовые данные, а "базовыми" регистрами (которых в общем случае может быть несколько) будем называть те регистры, для которых выполняется суммирование ресурсов.
Мы не будем рассматривать эти способы подробно, рассмотрим только их отличия и область применения.
Метод ПолучитьБазу()
Метод ПолучитьБазу() определен для объектов РегистрРасчетаМенеджер.<Имя регистра расчета> и РегистрРасчетаЗапись.<Имя регистра расчета>. Метод позволяет задать ресурсы базовых регистров, по которым необходимо получить обороты, задать поля, в разрезе которых нужно получить обороты и задать правила сопоставления измерений основного и базовых регистров расчета.
Правила сопоставления записей регистров расчета задаются структурой, каждый элемент которой задает для того или иного измерения основного регистра список измерений базовых регистров расчета. Имена элементов структуры должны совпадать с именами измерений основного регистра, а значения элементов структуры - строки, со списком измерений базовых регистров через запятую. Если элемент структуры с именем того или иного измерения не задан, то это значит, что на соответствующее измерение не налагается условие.
Имена измерений и ресурсов базовых регистров задаются в формате <ИмяРегистраРасчета>.<ИмяПоля>.
Пример использования метода:
В приведенном выше примере измерение "Физлицо" основного регистра при получении оборотов будет сопоставляться с измерением "Физлицо" базового регистра "ОсновныеНачисления" и измерением "Работник" базового регистра "ДополнительныеНачисления".
Таблица языка запросов для получения базовых данных
Для получения базовых данных в языке запросов определены виртуальные таблицы "РегистрРасчета.<Имя регистра расчета>.База<Имя базового регистра расчета>". В качестве параметров виртуальной таблицы задаются измерения основного регистра, измерения базового регистра и поля, в разрезе которых нужно получить базовые данные. Измерения и разрезы задаются как массив (или список значений) строк с именами измерений.
Пример написания запроса с использованием виртуальных таблиц базовых данных:
Приведенный пример предполагает ту же структуру данных и ту же решаемую задачу, что и пример для метода ПолучитьБазу(). При этом мы видим заметное увеличение исходного кода и кажущуюся его сложность.
Сравнение
Заметным отличием функционального метода получения базовых данных и получения при помощи запроса является то, что в функциональном методе одним вызовом метода можно получить базовые данные по всем базовым регистрам, а при использовании запросов получение базовых данных делается запросом к нескольким таблицам - по числу базовых регистров. Тем не менее, рекомендуемым способом получения данных является получение данных запросом. Это позволит, например, получить не только данные базовых видов расчета, но и дополнительную информацию, необходимую для расчета.
Отметим, что производительность получения данных при помощи функционального метода и при помощи запроса одинакова несмотря на кажущееся усложнение исполняемого кода в случае с запросами.
Краткая функциональная запись с использованием метода ПолучитьБазу() допустима только в том случае, если нет необходимости в иных данных помимо базовых, и при этом хочется "сэкономить" на строках кода. Совершенно не допустимо из соображений производительности кода, применение метода ПолучитьБазу() в том случае, если после его использование все равно придется при помощи запроса получать дополнительные данные для расчета.
Еще одно соображение касается условий отбора базовых данных. Для метода ПолучитьБазу(), фактически, нет возможности получить базовые данные иначе, чем по одной записи или по конкретному регистратору (с отбором по тем или иным измерениям). В случае же запроса в распоряжении у разработчика все возможности языка запросов по отбору записей.
Для расчета записей необходимо сначала сформировать набор этих записей в регистре расчета. Это позволит использовать расчетные механизмы платформы. Формирование записей при расчете аналогично рассмотренному выше модулю формирования записей при проведении. Однако если при проведении в качестве набора записей выступали движения доку- мента по регистру (Движения.ОсновыеНачисленияРегл), то при расчете без проведения такой набор необходимо создать.
Ниже приведен модуль, позволяющий сформировать набор записей регистра расчета по данным документа. В тексте используется процедура ДобавитьСтрокуОсновныхНачислений(), описанная выше. Этот модуль является начальным этапом процедуры РассчитатьОсновныеНачисления(), которая вызывается при нажатии кнопки Рассчитать в форме документа.
При формировании набора записей значения ресурсов не играют роли, так как они будут в дальнейшем изменены при расчете. В том числе эти значения могут быть пустыми.
В статье приведены полезные приемы при работе с запросами 1С v.8.2, а также сведения, которые не так хорошо известны о языке запросов. Я не стремлюсь дать полное описание языка запросов, а хочу остановиться лишь на некоторых моментах, которые для кого-то могут быть полезны.
Итак, начнем. Запрос - это специальный объект в 1С 8.2, который используется для формирования и выполнения запросов к таблицам базы данных в системе. Для выполнения запроса необходимо составить текст запроса, в котором описывается какие таблицы будут использоваться в качестве источников данных запроса, какие нужно выбрать поля, какие применить сортировки и группировки и т.д. Подробнее о запросах можно прочитать в книге "1С 8.2 Руководстве разработчика". Язык запросов 1С 8.2 очень похож синтаксисом на другие SQL языки запросов баз данных, но есть и отличия. Из основных преимуществ встроенного языка запросов стоит отметить разыменование полей, наличие виртуальных таблиц, удобная работа с итогами и нетипизированные поля в запросах. Из недостатков – в качестве выходного поля нельзя использовать запрос, нельзя использовать хранимые процедуры, нельзя преобразовать строку в число.
Приведу сведения и рекомендации по языку запросов по пунктам:
1.Для повышения читабельности запроса и уменьшения количества параметров запроса можно в запросе применять обращение к предопределенным данным конфигурации с помощью литерала ЗНАЧЕНИЕ (ПРЕДСТАВЛЕНИЕЗНАЧЕНИЯ). В качестве представления значений могут использоваться значение перечислений, предопределенные данные справочников, планов видов расчета, планов видов характеристик, планов счетов, пустые ссылки, значения точек маршрута, значения системных перечислений (например, ВидДвиженияНакопления, ВидСчета).
Примеры: ГДЕ Город = ЗНАЧЕНИЕ(Справочник.Города.Москва) ГДЕ Город = ЗНАЧЕНИЕ(Справочник.Города.ПустаяСсылка) ГДЕ ТипТовара = ЗНАЧЕНИЕ(Перечисление.ВидыТоваров.Услуга) ГДЕ ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход) ГДЕ ТочкаМаршрута = ЗНАЧЕНИЕ(БизнесПроцесс.Согласование.ТочкаМаршрута.Согласие)
Выражение в скобках всегда начинается со слова в единственном числе (Справочник, Перечисление и т.д.), которое соответствует типу предопределенного значения.
2.Автоупорядочивание в запросе может сильно тормозить процесс. Если сортировка не нужна, лучше вообще ее не использовать. Во многих случаях эффективнее записать сортировку через ключевое слово УПОРЯДОЧИТЬ ПО.
3.Нужно следить, чтобы при использовании псевдонимов не появилось неоднозначное поле. Иначе система не поймет к какому объекту надо обращаться.
Пример запроса с неоднозначным полем: ВЫБРАТЬ Номенклатура.Ссылка, ОстаткиТоваровОстатки.КоличествоОстаток ИЗ Справочник.Номенклатура КАК Номенклатура ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК ОстаткиТоваровОстатки ПО ОстаткиТоваровОстатки.Номенклатура = Номенклатура.Ссылка
Нужно исправить псевдоним таблицы, например, так: «Справочник.Номенклатура КАК Номенклатура1», а «Номенклатура.Ссылка» соответственно исправить на «Номенклатура1.Ссылка».
4.Иногда полезно получать представление ссылочных полей с помощью ключевого слова ПРЕДСТАВЛЕНИЕ наряду со ссылкой для того, чтобы не было повторного обращения к базе данных. Это бывает полезно при выводе результата запроса в таблицу.
Пример: ВЫБРАТЬ ПРЕДСТАВЛЕНИЕ(Документ.Контрагент) КАК Получатель, ПРЕДСТАВЛЕНИЕ(Документ.Основание) ИЗ Документ.РасходнаяНакладная КАК Документ
5.Использование в запросе ВЫРАЗИТЬ(Поле КАК Тип) позволяет убрать лишние таблицы из соединения с полем составного типа данных. Тем самым ускорить выполнение запроса.
Пример (регистратор - поле с составным типом для физической таблицы регистранакопления ОстаткиТоваров, в запросе выбираются Дата и Номер документов ПоступлениеТоваров, при этом при обращении к реквизитам документа Дата и Номер через Регистратор не происходит множественного соединения таблицы регистра с таблицами документов, являющихся регистраторами для регистра ОстаткиТоваров): ВЫБРАТЬ РАЗЛИЧНЫЕ [b] ВЫРАЗИТЬ(ОстаткиТоваров.Регистратор КАК Документ.ПоступлениеТоваров).Номер КАК НОМЕРПОСТУПЛЕНИЯ,[/b] [b]ВЫРАЗИТЬ(ОстаткиТоваров.Регистратор КАК Документ.ПоступлениеТоваров).Дата КАК ДАТАПОСТУПЛЕНИЯ[/b] [b]ИЗ РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваровГДЕ (ВЫРАЗИТЬ(ОстаткиТоваров.Регистратор КАК Документ.ПоступлениеТоваров) ЕСТЬ НЕ NULL)[/b]
6.Когда в конфигурации 1С есть пользователи, у которых права ограничены на определенные объекты конфигурации, в запросе к таким объектам необходимо использовать ключевое слово РАЗРЕШЕННЫЕ, чтобы запрос выполнился без ошибки (Выбрать Разрешенные ...)
7.При объединении таблиц, содержащих вложенные таблицы (например, Документ с табличной частью) бывает полезно ключевое слово ПУСТАЯТАБЛИЦА, когда, например, в одном из документов нет табличной части.
Пример: ВЫБРАТЬ Ссылка.Номер, ПУСТАЯТАБЛИЦА.(Ном, Тов, Кол) КАК Состав ИЗ Документ.РасходнаяНакладная ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ Ссылка.Номер, Состав.(НомерСтроки, Номенклатура, Количество) ИЗ Документ.РасходнаяНакладная
8.При работе с соединениями таблиц, содержащих по одной строке, бывает нужно склеить строки таблиц (при этом в обеих таблицах нет такого поля, по которому их можно было соединить). Этого можно добиться, применив конструкцию «ПОЛНОЕ СОЕДИНЕНИЕ Таблица По ИСТИНА». Если в таблицах больше, чем одна строка, то в результате будет количество строк, равное произведению количества строк обеих таблиц. Если в одной таблице О строк, то в результирующей таблице количество строк будет равно количеству строк второй таблицы. Также для соединения таких таблиц можно применять декартово произведение таблиц , при котором в результирующей таблице будут встречаться все комбинации строк из обеих таблиц. Надо помнить, что если в одной из таблиц 0 строк, тогда и декартово произведение будет 0, поэтому полное соединение будет лучше. Вообще вместо полного соединения ПО ИСТИНА можно использовать и любой другой тип соединения, но в таком случае тоже возможна ситуация, когда в результирующей таблице будет 0 строк, даже если в одной из таблиц будет ненулевое количество строк. В случае полного соединения такая ситуация будет только в одном случае, если количество строк в обеих таблицах равно 0. Если знать, что в таблице есть точно хотя бы одна строка, тогда можно использовать и ЛЕВОЕ СОЕДИНЕНИЕ с другой таблицей с условием ПО ИСТИНА.
Пример (правда надуманный, для Полного соединения): ВЫБРАТЬ Первые 1 Пол.Ссылка, К.Контрагент ИЗ Перечисление.Пол КАК Пол ПОЛНОЕ СОЕДИНЕНИЕ (Выбрать Первые 1 Д.Контрагент ИЗ Документ.РеализацияТоваров КАК Д Упорядочить По Д.МоментВремени ) КАК К ПО (ИСТИНА)
9. Для того чтобы получить уникальные записи по какому-то полю, правильней вместо группировки пользоваться ключевым словом РАЗЛИЧНЫЕ в запросе, потому что такая конструкция намного наглядней и ключевое слово СГРУППИРОВАТЬ ПО имеет более широкое применение и часто используется, если дополнительно надо рассчитать агрегатные функции по группировкам. В некоторых случаях необходимо вывести ограниченное количество строк. Для этого в описании запроса в описании запроса следует указать ключевое слово ПЕРВЫЕ и после него – требуемое количество строк.
Пример для ПЕРВЫЕ: Выбрать Первые 5 Справочник.Номенклатура.Наименование, Справочник.Номенклатура.ЗакупочнаяЦена Упорядочить По Справочник.Номенклатура.ЗакупочнаяЦена Убыв
Пример для РАЗЛИЧНЫЕ: Выбрать Различные Документ.Расходная.Контрагент
10.Агрегатные функции в запросе можно использовать без ключевого слова СГРУППИРОВАТЬ. В таком случае все результаты будут сгруппированы в одну строку.
Пример: Выбрать Сумма(Накладная.Сумма) Как Сумма Из Документ.РасходнаяНакладная.Состав Как Накладная
11.В запросах в полях выборки можно свободно обращаться к реквизитам полей выборки. Эта возможность называется разыменованием полей выборки. Если источник данных - вложенная таблица (табличная часть документа), то в полях выборки можно обращаться также к полям основной таблицы (например, через поле Ссылка обратиться к полю основной таблицы Контрагент)
Пример: ВЫБРАТЬ [b] ПоступлениеТоваровИУслугТовары.Номенклатура, ПоступлениеТоваровИУслугТовары.Номенклатура.Код, ПоступлениеТоваровИУслугТовары.Количество КАК Количество, ПоступлениеТоваровИУслугТовары.Ссылка.КонтрагентИЗ Документ.ПоступлениеТоваровИУслуг.Товары КАК ПоступлениеТоваровИУслугТоварыГДЕ ПоступлениеТоваровИУслугТовары.Ссылка = &Ссылка[/b]
Есть одна особенность использования разыменования полей, если в запросе есть группировки. В любых запросах с группировками в списках полей запроса можно свободно обращаться к реквизитам группировочных полей.
Пример: ВЫБРАТЬ ПоступлениеТоваровИУслугТовары.Номенклатура, ПоступлениеТоваровИУслугТовары.Номенклатура.Код, СУММА(ПоступлениеТоваровИУслугТовары.Количество) КАК Количество, ПоступлениеТоваровИУслугТовары.Ссылка.Контрагент, ПоступлениеТоваровИУслугТовары.Ссылка.Дата ИЗ Документ.ПоступлениеТоваровИУслуг.Товары КАК ПоступлениеТоваровИУслугТовары ГДЕ ПоступлениеТоваровИУслугТовары.Ссылка = &Ссылка СГРУППИРОВАТЬ ПО ПоступлениеТоваровИУслугТовары.Номенклатура, ПоступлениеТоваровИУслугТовары.Ссылка
В справке 1С написано, что при наличии группировки, в полях выборки запроса могут участвовать только группировочные поля и агрегатные функции по полям выборки. Есть один исключительный случай, когда агрегатные функции применены к полям вложенной таблицы. В этом случае в списке полей выборки возможны обращения к полям таблицы верхнего уровня, без группировки результатов по этим полям.
Пример: ВЫБРАТЬ ПоступлениеТоваровИУслуг.Товары.(СУММА(Количество),Номенклатура), ПоступлениеТоваровИУслуг.Ссылка, ПоступлениеТоваровИУслуг.Контрагент ИЗ Документ.ПоступлениеТоваровИУслуг КАК ПоступлениеТоваровИУслуг СГРУППИРОВАТЬ ПО ПоступлениеТоваровИУслуг.Товары.(Номенклатура)
12. Иногда вместо указания какого-либо поля в группировке полезно в поля выборки запроса включить параметр: ВЫБРАТЬ ДокТовары.Номенклатура, &Контрагент, &Период, СУММА(ДокТовары.Количество * ДокТовары.К) КАК Количество, СУММА(ДокТовары.Сумма) КАК СуммаИЗ Документ.Приходная.Товары КАК ДокТоварыГДЕ ДокТовары.Ссылка = &Ссылка СГРУППИРОВАТЬ ПО ДокТовары.Номенклатура
А затем установить параметр в тексте запроса: Запрос.УстановитьПараметр(«&Контрагент», ВыбКонтрагент); Запрос.УстановитьПараметр(«&Период», Дата);
13. В универсальных запросах параметры можно использовать в описании источников данных запроса, в условиях ГДЕ, в условиях соединения таблиц и параметрах виртуальных таблиц. Существует два приема для создания универсальных запросов:
А) с помощью механизма конкатенации строк, добавляя в текст запроса переменные;
Пример1: ТипУпорядочивания = ?(НЕКАЯПЕРЕМЕННАЯ,"","УБЫВ"); Запрос.Текст= "Выбрать ... Упорядочить ПО Поле1 " + ТипУпорядочивания + "...";
Пример2: Запрос.Текст = "Выбрать Поле1..."; Если НЕКАЯПЕРЕМЕННАЯ = 1 Тогда Запрос.Текст = Запрос.Текст + ",Поле2 ..."; КонецЕсли;
Б)использовать параметры в различных частях запроса (например, в секции источников данных запроса), а затем метод встроенного языка - СТРЗАМЕНИТЬ(). При проектировании универсальных запросов полезно обращение к свойству объектов МЕТАДАННЫЕ(), с помощью которого можно определить название таблицы для какой-то ссылки (например, для документа будет примерно так - Ссылка.МЕТАДАННЫЕ().ИМЯ), переданной через параметр в некую универсальную процедуру.
Пример: Выбрать ДокТЧ.Номенклатура, ... ИЗ &НекийДокТЧ КАК ДокТЧ
А затем установить параметр в тексте запроса Запрос.Текст = СтрЗаменить(Запрос.Текст, "&НекийДокТЧ", "Документ."+Ссылка.Метаданные().Имя+".Товары");
Параметры можно использовать в условиях запроса, чтобы включить опциональное условие &Параметр ИЛИ НЕ КакоеТоСвойство: Запрос.УстановитьПараметр(“&Параметр”, “Контрагент.Наименование=””Иванов”””);
С помощью литерала ИСТИНА можно убирать определенные фильтры в запросе Запрос.УстановитьПараметр(«&Параметр»,Истина);
14.Очень полезными в конструкторе запросов является команда контекстного меню таблицы - "Переименовать таблицу...", с помощью которого можно придумать некоторое обобщенное имя для источника данных. Для создания запросов к однотипным таблицам, похожим по структуре, бывает полезным для второй таблицы скопировать текст запроса первой таблицы, зайти в окно конструктора запросов и в контекстном меню таблицы выбрать пункт - Заменить таблицу... и выбрать вторую талицу.
15.При работе с созданием вложенных запросов в секциях условий или параметров виртуальных таблиц конструктора запросов используется прием выделения пробела в скобках, тогда появляется в контекстном меню пункт «Конструктор запроса», а при редактировании вложенного запроса в условии выделяют весь запрос в скобках .
Пример вложенного запроса: Товар В ( Выбрать Номенклатура ...)
16. При проектировании отчетов СКД в запросах к регистрам остатков - в качестве параметра Период удобнее и правильнее использовать выражение ДобавитьКДате(КонецПериода(Период,ДЕНЬ),СЕКУДА,1), так как остатки в виртуальных получаются на начало периода, не включая последнюю секунду. Прием +1 секунда не может быть применен с документами: по новой методике проведения документов остатки по регистру надо получать на Период, заданный объектом Граница с моментом времени документа включая (а не на дату документа +1 секунда!), а по старой методике проведения - на момент времени документа (а не на дату документа !). При анализе оборотов или данных за период удобно добавлять параметр с типом СтандартныйПериод (в этом случае не надо приводить последнюю дату интервала на конец дня). У стандартного поля «НачалоПериода» в поле «Выражение» надо прописать «&Период.ДатаНачала». А у стандартного поля «КонецПериода» в поле «Выражение» прописать «&Период.ДатаОкончания». Очень много полезной информации по языку запросов можно найти не в синтакс-помощнике, а в полной справке конфигуратора 1С 8.2 (кнопка F1)
17.Функция запроса ЕстьNull (удобнее писать англоязычный вариант IsNull) обычно используется для избавления от значений типа Null для числовых полей запроса. В ряде случаев, например полного соединения двух таблиц функция IsNull (Параметр1,Параметр2) может с успехом заменить конструкцию ВЫБОР КОГДА ... ТОГДА ..ИНАЧЕ ….КОНЕЦ, когда для какого-либо поля значения NULL могут быть как в первой таблице, так и во второй (такая конструкция позволяет получать не Null значение для поля). Но надо помнить, что в отличие от условного оператора ВЫБОР функция ЕстьNull приводит тип второго аргумента к типу первого аргумента, что нужно учитывать, если типы аргументов отличаются!
Пример: IsNull(Рег.Остаток,0) IsNull(Док.Товар,Док1.Номенклатура)
18. У условной конструкции ВЫБОР есть альтернативный синтаксис для простого случая проверки равенства определенному значению, но, правда, он недокументированный: Выбор Выражение Когда 1 Тогда «Высший» Когда 2 Тогда «Средний» Иначе «Низший» Конец
19.Оператор проверки значения на NULL Eсть Null (Можно рекомендовать использовать англоязычный вариант Is Null). Такая конструкция появилась потому, что любая операция сравнения двух величин, хотя бы одно из которых Null, всегда ложь. Написать Где Наименование = Null неправильно. Интересна также форма отрицания данного оператора Не Есть Null - неправильно, а правильно Есть Не Null или форма Не (Поле1 Есть Null) - это существенное отличие от всех операторов, использующихся совместно с оператором Не.
20. Иногда полезна форма оператора В для проверки совпадения с одним из перечисленных значений.
Пример: ...Где Товар.Наименование В ("Бытовая техника","Компьютеры")
Для справочников может быть полезна форма оператора В проверки принадлежности по иерархии.
Пример: ...Где Номенклатура В ИЕРАРХИИ (&Группа)
Оператор В часто используется для проверки вхождения значения в результат вложенного запроса.
Пример: ...Где Номенклатура.Ссылка В (Выбрать Номенклатура.Ссылка ...).
Во вложенном запросе можно обращаться к полям внешнего запроса в условии.
Пример: // Выбрать названия товаров, которые присутствовали // в расходных накладных ВЫБРАТЬ Товары.Наименование ИЗ Справочник.Номенклатура КАК Товары ГДЕ Товары.Ссылка В (ВЫБРАТЬ РасходнаяНакладнаяСостав.Номенклатура ИЗ Документ.РасходнаяНакладная.Состав КАК РасходнаяНакладнаяСостав ГДЕ РасходнаяНакладнаяСостав.Номенклатура = Товары.Ссылка)
Операция В может использоваться с массивами, списками значений, таблицами значений, вложенными запросами. При этом возможно сокращение условий
Синтаксис для вложенного запроса (выражение1, выражение2,...,выражениеN) В (Выбрать выражение1, выражение2,...,выражениеN ...)
Синтаксис для таблицы значений (выражение1, выражение2,...,выражениеN) В (&ТЗ), где в таблице значений ТЗ используются N первых колонок
20. В интернете есть шутка по поводу того, как конструктор запроса постоянно делает ЛЕВОЕ соединение таблиц (и меняет их местами), как бы мы не указывали ПРАВОЕ: 1С:Предприятие любит «налево».
21. Сложные запросы удобно отлаживать в консоли запросов. Существует их в интернете много. После отладки запроса его можно скопировать и в конструкторе запроса есть замечательная кнопка «Запрос», куда можно вставить его в том же виде и сохранить (раньше была только возможность скопировать в конфигураторе и сделать форматирование запроса посредством символа переноса строки). В окне, которое открывается при нажатии кнопки «Запрос», можно редактировать запрос и смотреть результат выполнения, что довольно удобно.
22.При проектировании отчетов СКД нужно помнить, что если нужно обеспечить фильтрацию по некоторому полю, необязательно добавлять параметр в текст запроса. У конструктора запросов есть вкладка «Компоновка данных», где можно добавлять параметры в условия. Кроме того, на уровне отчета СКД есть закладка условия, где можно добавлять произвольные условия и сохранять в быстрых настройках. В таком случае условия будут универсальными (равенство, неравенство, принадлежность, вхождение в список и т.д.).
23. При работе с документами бывает нужно добавить сортировку по виртуальному полю таблицы МОМЕНТВРЕМЕНИ, но вот незадача - во вложенных запросах сортировка по этому полю правильно не работает. Помогают танцы с бубнами: сортировка по виртуальному полю МОМЕНТВРЕМЕНИ заменяется на две сортировки: по дате и по ссылке. Также решить проблему можно через временную таблицу переносом вложенного запроса в отдельный запрос. На протяжении уже многих релизов данная фича или баг не исправлена.
Пример неправильно работающего запроса, получающего последний проведенный документ по указанному контрагенту (вернее, табличную часть документа): ВЫБРАТЬ РасходнаяТовары.Ссылка, РасходнаяТовары.НомерСтроки, РасходнаяТовары.Товар, РасходнаяТовары.Количество, РасходнаяТовары.Цена, РасходнаяТовары.Сумма ИЗ Документ.Расходная.Товары КАК РасходнаяТовары ГДЕ РасходнаяТовары.Ссылка В (ВЫБРАТЬ ПЕРВЫЕ 1 Д.Ссылка ИЗ Документ.Расходная КАК Д ГДЕ Д.Ссылка.Проведен И Д.Контрагент = &Контрагент УПОРЯДОЧИТЬ ПО Д.Ссылка.МоментВремени УБЫВ)
Возможные решения:
A) Заменить на УПОРЯДОЧИТЬ ПО на УПОРЯДОЧИТЬ ПО Д.Дата УБЫВ УПОРЯДОЧИТЬ ПО Д.Ссылка УБЫВ
Б) Можно перенести вложенный запрос во временную таблицу: ВЫБРАТЬ ПЕРВЫЕ 1 Д.Ссылка ПОМЕСТИТЬ ТЗСсылка ИЗ Документ.Расходная КАК Д ГДЕ Д.Ссылка.Проведен И Д.Контрагент = &Контрагент УПОРЯДОЧИТЬ ПО Д.Ссылка.МоментВремени УБЫВ ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ РасходнаяТовары.Ссылка, РасходнаяТовары.НомерСтроки, РасходнаяТовары.Товар, РасходнаяТовары.Количество, РасходнаяТовары.Цена, РасходнаяТовары.Сумма ИЗ Документ.Расходная.Товары КАК РасходнаяТовары ГДЕ РасходнаяТовары.Ссылка В (ВЫБРАТЬ Т.Ссылка ИЗ ТЗСсылка КАК Т)
В) Можно обратиться к основной таблице документа, а уже затем к табличной части ВЫБРАТЬ ПЕРВЫЕ 1 Расходная.Ссылка, Расходная.Товары.( Ссылка, НомерСтроки, Товар, Количество, Цена, Сумма ) ИЗ Документ.Расходная КАК Расходная ГДЕ Расходная.Контрагент = &Контрагент И Расходная.Проведен УПОРЯДОЧИТЬ ПО Расходная.МоментВремени УБЫВ
24. При обращении к главной таблице документа(справочника) можно в условии обратиться к данным подчиненной таблицы (табличной части). Такая возможность называется разыменование полей табличной части. В качестве примера задачи можно привести задачу поиска документов, содержащих в табличной части определенный товар.
Пример: Выбрать Приходная.Ссылка ИЗ Документ.Приходная Где Приходная.Товары.Номенклатура = &Номенклатура.
Преимущество этого запроса перед запросом ко вложенной таблице Приходная.Товары в том, что если есть дубли в документах , результат запроса вернет только уникальные документы без использования ключевого слова РАЗЛИЧНЫЕ.
Сравните: Выбрать Различные Товары.Ссылка ИЗ Документ.Приходная.Товары как Товары Где Товары.Номенклатура = &Номенклатура.
На этом месте, пожалуй, всё. Понятно, что в языке запросов ещё много неосвещенных мной вопросов. Для написания статьи была использована информация, полученная мной после прохождения базового курса 1С 8.2 spec8.ru, а также из книги «1С 8.2 Руководство разработчика» и просторов интернета.
Всем спасибо!
Автор: fpat
Задача: Есть два склада Склад1 и Склад2. Нужно переместить определенное количество товара со склада1 на склад2. При списании со склада1 нужно проверять остаток, что хватает товара. Проведение сделать по регистру бухгалтерии.(проверку тоже по регистру бухгалтерии).
Решение: В Шапке документа Склад1 и Склад2. В Табличной части номенклатура и количество.
Событие ПриПолученииДанных использется для оформления ячеек строк данных, отображаемых табличным полем. Обработчик данного события вызывается табличным полем в тех же случаях, что и обработчик ПриВыводеСтроки, т.е. при обновлении данных, отображаемых табличным полем или при поиске по подстроке. Важно отметить, что обработчик данного события вызывается табличным полем перед вызовом обработчиков события ПриВыводеСтроки для всех видимых строк табличного поля. Основным отличием данного события от события ПриВыводеСтроки является то, что в обработчике события ПриПолученииДанных можно изменять настройки ячеек группы строк, а не одной строки как в обработчике события ПриВыводеСтроки.
Обрабатывая данное событие можно изменять шрифт, цвет фона или текста, как определенной ячейки, так и всей строки табличного поля, устанавливать высоту или видимость ячеек строки табличного поля, а также устанавливать картинку, флажок или новый текст в ячейке. Параметром данного события является объект типа ОформлениеСтрок - коллекция объектов типа ОформлениеСтроки, являющихся оформлениями строк табличного поля.
Важно отметить, что в некоторых случаях обработчик события ПриПолученииДанных может вызываться табличным полем более одного раза. Например, если текущая строка табличного поля находится в середине видимой области, то при обновлении обработчик события ПриПолученииДанных будет вызван табличным полем два раза: первый раз для группы строк, начиная с текущей строки до верхней видимой и второй раз для строки, следующей за текущей до нижней видимой строки. Такое поведение табличного поля связано с тем, что при обновлении табличное поле пытается сохранить позицию текущий строки в видимой области.
Поясним использовании события ПриПолученииДанных на следующем примере. Пусть существует форма списка справочника "Номенклатура" с двумя табличными полями. Пусть одно из табличных полей отображает указанный список справочника как дерево, а другое как иерархический список. Требуется в табличном поле, отображающем данные как иерархический список, отображать остатки по позициям номенклатуры.
Наиболее эффективным способом решения данной задачи является использование события ПриПолученииДанных. В обработчике данного события формируется запрос к регистру накопления "УчетНоменклатуры" для получения остатков. В качестве параметра данного запроса передается массив, содержащий ссылки на отображаемые строки табличного поля. Затем выполняется запрос и получается выборка. Полученная выборка обходится и значения остатков устанавливаются в ячейке "Остаток".
В том случае, когда в каком-то регистре сведений нужно заменить несколько видов значений какого-то конкретного ресурса на заданное значение, лучше использовать вот такую универсальную процедуру (при ее вызове достаточно подставить название регистра, название ресурса и передать старые заменяемые значения и новое, на которое они заменяются):