ВЫРАЗИТЬ в запросе 1С приводит выражение к одному типу: ВЫРАЗИТЬ(Поле КАК Тип). Главная работа оператора — поля составного типа: Регистратор, Субконто, ДокументОснование, Объект в регистрах сведений. Без приведения обращение к их реквизитам через точку соединяет таблицу с таблицами всех типов, которые допускает поле. Второе применение — разрядность чисел и длина строк.
Примеры рассчитаны на платформу 8.3 и серверный общий модуль: на клиенте объект Запрос недоступен. Имена объектов взяты из типовых конфигураций (БП 3.0, УТ, БСП) или условные — сверьте их со своей базой.
После КАК указывают один из пяти вариантов: БУЛЕВО, ЧИСЛО(Длина, Точность), СТРОКА(Длина), ДАТА или имя ссылочной таблицы. Ссылочный тип пишут так же, как таблицу в ИЗ: Документ.РеализацияТоваровУслуг, Справочник.Контрагенты. Так поле выражают как документ или как справочник.
Правило из документации платформы одно. Если нужный тип входит в состав типа поля, значения этого типа проходят как есть, а значения остальных типов превращаются в NULL. Если типа в составе нет, запрос завершается ошибкой.
| Что приводим | КАК | Что получится |
|---|---|---|
| Составное ссылочное поле: Регистратор, Субконто, ДокументОснование, Объект | Документ.Имя, Справочник.Имя | Ссылка одного типа, у записей с другим типом — NULL. Реквизиты через точку — одним соединением |
| Составное поле с примитивами: значение характеристики или доп. реквизита | ЧИСЛО, СТРОКА(N), ДАТА, БУЛЕВО | Значение нужного типа или NULL. Даты — в статье «Дата в запросе 1С» |
| Число | ЧИСЛО(15, 2) | Новая разрядность, лишние знаки после запятой округляются |
| Строка неограниченной длины | СТРОКА(N), N до 1024 | Первые N символов; поле можно сравнивать и группировать — см. строки в запросе |
| Ссылка одного типа | тот же тип | Ничего не меняется, ВЫРАЗИТЬ не нужен |
| Строка в число или дату, число в строку, Регистратор в справочник | тип, которого нет в составе поля | Запрос завершается ошибкой. Что делать — в разделе «Чего ВЫРАЗИТЬ не умеет» |
Ссылка составного типа хранится в базе двумя колонками: код типа и сама ссылка. Какой документ лежит в Регистраторе конкретной записи, при трансляции запроса неизвестно, поэтому Движения.Регистратор.Номер платформа превращает в левые соединения со всеми таблицами, которые допускает поле, и выбирает значение по коду типа. Сравнение «до и после» для регистра с 15 видами регистраторов:
| Что написано в запросе | Что получает СУБД |
|---|---|
Движения.Регистратор.Номер | 15 левых соединений и выбор значения по коду типа. Оптимизатор строит план на все 15 таблиц, даже если в выборке одни реализации |
ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Номер | Одно левое соединение с таблицей реализаций по коду типа и ссылке. У прочих регистраторов — NULL, их таблицы не читаются |
ВЫРАЗИТЬ(...) без точки | Соединений нет: проверяется код типа |
Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг | Соединений нет: сравнивается код типа |
У субконто в БП 3.0 в составе типа десятки справочников и документов, и Остатки.Субконто1.ИНН в отчёте по счёту 62 превращается в запрос с десятками соединений. При ограничениях доступа на уровне записей (RLS) к неявным соединениям добавляются ещё и условия прав. В отчёт на СКД выводите уже приведённое поле: представление составного поля система компоновки тоже получает по всем типам. Механика разыменования разобрана в статье «Ссылка в запросе 1С».
Пример — дебиторская задолженность по счёту 62 с ИНН контрагента и датой договора:
// Дебиторская задолженность по счёту 62 с ИНН и датой договора.
// Имена объектов — из БП 3.0.
Функция ДебиторскаяЗадолженность(Организация, НаДату) Экспорт
ВидыСубконто = Новый Массив;
ВидыСубконто.Добавить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты);
ВидыСубконто.Добавить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Остатки.Субконто1 КАК Справочник.Контрагенты) КАК Контрагент,
| ВЫРАЗИТЬ(Остатки.Субконто1 КАК Справочник.Контрагенты).ИНН КАК ИНН,
| ВЫРАЗИТЬ(Остатки.Субконто2 КАК Справочник.ДоговорыКонтрагентов) КАК Договор,
| ВЫРАЗИТЬ(Остатки.Субконто2 КАК Справочник.ДоговорыКонтрагентов).Дата КАК ДатаДоговора,
| Остатки.СуммаОстатокДт КАК Долг
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(
| &НаДату,
| Счет В ИЕРАРХИИ (&Счет),
| &ВидыСубконто,
| Организация = &Организация) КАК Остатки
|ГДЕ
| Остатки.СуммаОстатокДт > 0
|
|УПОРЯДОЧИТЬ ПО
| Долг УБЫВ";
Запрос.УстановитьПараметр("НаДату", Новый Граница(КонецДня(НаДату), ВидГраницы.Включая));
Запрос.УстановитьПараметр("Счет", ПланыСчетов.Хозрасчетный.НайтиПоКоду("62"));
Запрос.УстановитьПараметр("ВидыСубконто", ВидыСубконто);
Запрос.УстановитьПараметр("Организация", Организация);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
&ВидыСубконто задаёт порядок: Субконто1 — контрагент, Субконто2 — договор. Без параметра порядок берётся из настроек счёта.ВЫРАЗИТЬ без точки соединений не добавляет, а .ИНН и .Дата дают по одному: с контрагентами и с договорами.Граница с ВидГраницы.Включая учитывает движения, записанные в 23:59:59.Если реквизит нужен из двух-трёх видов документов, поле приводят в каждой ветке ВЫБОР. Пример — движения товара с контрагентом: поставщиком из поступления или покупателем из реализации.
// Движения товара с контрагентом из документа-регистратора.
// Регистр и документы условные, по образцу УТ 10.3.
Функция ДвиженияТовара(Номенклатура, НачалоПериода, КонецПериода) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Движения.Период КАК Период,
| Движения.Регистратор КАК Регистратор,
| Движения.ВидДвижения КАК ВидДвижения,
| Движения.Количество КАК Количество,
| ВЫБОР
| КОГДА Движения.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
| ТОГДА ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Контрагент
| КОГДА Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
| ТОГДА ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент
| ИНАЧЕ NULL
| КОНЕЦ КАК Контрагент
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК Движения
|ГДЕ
| Движения.Активность
| И Движения.Номенклатура = &Номенклатура
| И Движения.Период МЕЖДУ &НачалоПериода И &КонецПериода
|
|УПОРЯДОЧИТЬ ПО
| Период";
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(НачалоПериода));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(КонецПериода));
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
ССЫЛКА — по коду типа, без соединений.ВЫРАЗИТЬ — два соединения, сколько бы видов регистраторов ни было у регистра.ИНАЧЕ: строки остаются в выборке, в колонке «Контрагент» у них NULL.Сравнение составного поля со ссылкой в приведении не нуждается: Продажи.Регистратор = Реализации.Ссылка платформа сама сводит к сравнению кода типа и ссылки. ВЫРАЗИТЬ нужен, когда в условии ПО стоит точка после составного поля. Пример: ставка бонуса хранится по договору, а в регистре продаж договора нет — он есть только в документе.
// Бонус по ставке, заданной для договора.
// Регистры условные: в «Продажах» нет измерения Договор,
// договор берём из документа-регистратора.
Функция БонусыПоДоговорам(НачалоПериода, КонецПериода) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Регистратор КАК Реализация,
| Ставки.Договор КАК Договор,
| Ставки.Процент КАК Процент,
| СУММА(Продажи.Сумма) КАК Сумма,
| ВЫРАЗИТЬ(СУММА(Продажи.Сумма) * Ставки.Процент / 100 КАК ЧИСЛО(15, 2)) КАК Бонус
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СтавкиБонусов КАК Ставки
| ПО (ВЫРАЗИТЬ(Продажи.Регистратор КАК Документ.РеализацияТоваровУслуг).Договор = Ставки.Договор)
|ГДЕ
| Продажи.Активность
| И Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода
|
|СГРУППИРОВАТЬ ПО
| Продажи.Регистратор,
| Ставки.Договор,
| Ставки.Процент
|
|УПОРЯДОЧИТЬ ПО
| Бонус УБЫВ";
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(НачалоПериода));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(КонецПериода));
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
ПО берёт договор из реализации: к движениям присоединяется одна таблица документов, а не все регистраторы.ВНУТРЕННЕЕ СОЕДИНЕНИЕ отбрасывает возвраты: для них ВЫРАЗИТЬ даёт NULL, а NULL не равен ни одному договору. Нужны возвраты — добавьте ветку ВЫБОР, как в предыдущем примере.ЧИСЛО(15, 2) округляет бонус до копеек прямо в запросе.В ГДЕ действует то же правило: точка после приведённого поля — одно соединение. Вид документа отбирают оператором ССЫЛКА: он нагляднее, чем ВЫРАЗИТЬ(...) ЕСТЬ НЕ NULL, и не обращается к другим таблицам. Пример — отгрузки по заказам одного менеджера и задержка от даты заказа:
// Отгрузки по заказам менеджера и задержка от даты заказа.
// Документы условные: ДокументОснование у реализации — составного типа.
Функция ОтгрузкиПоЗаказамМенеджера(Менеджер, НачалоПериода, КонецПериода) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Реализации.Ссылка КАК Реализация,
| ВЫРАЗИТЬ(Реализации.ДокументОснование КАК Документ.ЗаказКлиента) КАК Заказ,
| РАЗНОСТЬДАТ(
| ВЫРАЗИТЬ(Реализации.ДокументОснование КАК Документ.ЗаказКлиента).Дата,
| Реализации.Дата,
| ДЕНЬ) КАК ДнейДоОтгрузки
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализации
|ГДЕ
| Реализации.Проведен
| И Реализации.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И Реализации.ДокументОснование ССЫЛКА Документ.ЗаказКлиента
| И ВЫРАЗИТЬ(Реализации.ДокументОснование КАК Документ.ЗаказКлиента).Менеджер = &Менеджер
|
|УПОРЯДОЧИТЬ ПО
| ДнейДоОтгрузки УБЫВ";
Запрос.УстановитьПараметр("Менеджер", Менеджер);
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(НачалоПериода));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(КонецПериода));
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
ССЫЛКА оставляет реализации, созданные из заказов; отгрузки по счетам в выборку не попадут.РАЗНОСТЬДАТ обращаются к заказу через ВЫРАЗИТЬ, поэтому присоединяется только таблица заказов.Регистры с измерением «Объект» хранят данные для любых объектов, и тип такого поля включает десятки справочников и документов. В регистре БСП «Дополнительные сведения» составные и Объект, и Значение:
// Контрагенты и значение дополнительного сведения «Регион».
// Регистр «ДополнительныеСведения» из БСП: Объект и Значение — составного типа.
Функция РегионыКонтрагентов(СвойствоРегион) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Сведения.Объект КАК Справочник.Контрагенты) КАК Контрагент,
| ВЫРАЗИТЬ(Сведения.Объект КАК Справочник.Контрагенты).ИНН КАК ИНН,
| ВЫРАЗИТЬ(Сведения.Значение КАК Справочник.ЗначенияСвойствОбъектов) КАК Регион
|ИЗ
| РегистрСведений.ДополнительныеСведения КАК Сведения
|ГДЕ
| Сведения.Свойство = &Свойство
| И Сведения.Объект ССЫЛКА Справочник.Контрагенты
| И НЕ ВЫРАЗИТЬ(Сведения.Объект КАК Справочник.Контрагенты).ПометкаУдаления
|
|УПОРЯДОЧИТЬ ПО
| ИНН";
Запрос.УстановитьПараметр("Свойство", СвойствоРегион);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
ИНН и ПометкаУдаления читаются из одной таблицы, а не из всех владельцев дополнительных сведений.NULL.ЧИСЛО(15, 2) — 15 знаков, из них 2 после запятой. Деление и умножение в запросе дают длинную дробную часть: цена Сумма / Количество не совпадёт на = с ценой из прайса, а бонус уйдёт в отчёт с долями копейки. ВЫРАЗИТЬ округляет результат и фиксирует разрядность колонки — это важно и для временных таблиц. Если целая часть не влезет в разрядность, MS SQL прервёт запрос ошибкой переполнения, так что длину берите с запасом. В 8.3.20 и новее есть функция ОКР(Число, 2), а ВЫРАЗИТЬ работает на любой версии 8.3.
Строки неограниченной длины (Комментарий, Описание) нельзя сравнивать, группировать и выбирать с РАЗЛИЧНЫЕ. ВЫРАЗИТЬ(Поле КАК СТРОКА(N)) снимает запрет и оставляет первые N символов, N — не больше 1024. Примеры и выбор длины — в статье «Строка в запросе 1С».
ВЫРАЗИТЬ меняет разрядность или выделяет тип из составного, но не разбирает значения. У строкового поля в составе нет типов Число и Дата, поэтому ВЫРАЗИТЬ(Артикул КАК ЧИСЛО) завершится ошибкой. Число в строку переводит функция СТРОКА() (8.3.20 и новее), обходные пути для дат собраны в статье «Дата в запросе 1С», а строку в число проще перевести после выборки:
// Артикулы хранятся строкой, а упорядочить их нужно как числа.
// ВЫРАЗИТЬ(Артикул КАК ЧИСЛО) не сработает — переводим после выборки.
Функция НоменклатураПоЧисловомуАртикулу() Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Номенклатура,
| Товары.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Товары
|ГДЕ
| НЕ Товары.ЭтоГруппа
| И Товары.Артикул <> """"";
Таблица = Запрос.Выполнить().Выгрузить();
Таблица.Колонки.Добавить("АртикулЧислом", Новый ОписаниеТипов("Число"));
Для Каждого СтрокаТаблицы Из Таблица Цикл
Попытка
СтрокаТаблицы.АртикулЧислом = Число(СокрЛП(СтрокаТаблицы.Артикул));
Исключение
// Артикулы с буквами («А-15») оставляем с нулём.
СтрокаТаблицы.АртикулЧислом = 0;
КонецПопытки;
КонецЦикла;
Таблица.Сортировать("АртикулЧислом");
Возврат Таблица;
КонецФункции
Попытка ловит артикулы с буквами: на них Число() выбрасывает исключение «Преобразование значения к типу Число не может быть выполнено».РАЗЛИЧНЫЕ. Приведите её к СТРОКА(N).ЧИСЛО(N, M). Увеличьте длину.ГДЕ или во внутреннем соединении отбрасывает записи других видов. Посмотрите ТИПЗНАЧЕНИЯ(Поле) в консоли запросов и добавьте ветки ВЫБОР.СТРОКА(N) обрезает текст: при маленьком N строки с одинаковым началом попадают в одну группу и проходят сравнение.NULL — когда нужный тип входит в состав поля, но в записи лежит значение другого типа. Если типа нет в составе вовсе, запрос не выполнится. Результат ВЫРАЗИТЬ оборачивайте в ЕСТЬNULL, если с ним дальше считают.
ССЫЛКА и ТИПЗНАЧЕНИЯ только проверяют тип: первый возвращает Булево, второй — значение типа Тип. ВЫРАЗИТЬ меняет тип выражения, и после него можно обращаться к реквизитам. Рабочая связка — отбор через ССЫЛКА, реквизиты через ВЫРАЗИТЬ.
Никак: в ВЫРАЗИТЬ указывается одна конкретная таблица. Для нескольких видов документов используйте ВЫБОР с ветками по ССЫЛКА. Если от регистратора нужна только дата, возьмите Период регистра — в движениях он обычно равен дате документа.
Нет. У поля одного типа обращение через точку и так даёт одно соединение. Для ссылок ВЫРАЗИТЬ нужен только при составном типе, для чисел и строк — когда меняют разрядность или длину.
Если отчёт тормозит из-за составных полей или запрос к большому регистру нужно переписать, передайте задачу программисту: доработка отчётов и обработок 1С. Разместите задание — исполнитель оценит объём работ до начала.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.