Приведение поля к строке фиксированной длины в языке запросов 1С
Содержание
Чтобы выразить поле как строку в запросе 1С, пишут ВЫРАЗИТЬ(Таблица.Поле КАК СТРОКА(N)), где N — длина результата в символах. Чаще всего так превращают строку неограниченной длины (например, Комментарий документа) в строку фиксированной длины. После этого поле можно сравнивать, группировать, сортировать и использовать в соединениях.
Отдельного метода «ВыражатьКакСтрока» в 1С нет. Это операция языка запросов ВЫРАЗИТЬ с типом СТРОКА. Она работает на сервере СУБД, а не во встроенном языке. Поэтому её не вызывают у объекта Запрос, а пишут прямо в тексте запроса. Альтернатив две: ПОДСТРОКА(Поле, 1, N) — старый приём с тем же эффектом, и ПОДОБНО — если нужно только проверить текст, а не группировать по нему.
Зачем приводить поле к строке в запросе
У строкового реквизита в конфигураторе есть длина. Если длину поставить 0, строка становится неограниченной. Такие поля удобны для комментариев и описаний, но в запросах у них жёсткие ограничения.
Поле неограниченной длины нельзя напрямую:
- 🔹 сравнивать через
=,<>,Вв условияхГДЕиИМЕЮЩИЕ; - 🔹 указывать в
СГРУППИРОВАТЬ ПОиУПОРЯДОЧИТЬ ПО; - 🔹 выбирать с
РАЗЛИЧНЫЕи объединять черезОБЪЕДИНИТЬбезВСЕ(там скрыто то же «различные»); - 🔹 использовать в условии соединения
ПО; - 🔹 включать в индекс временной таблицы (
ИНДЕКСИРОВАТЬ ПО).
Если нарушить любое из этих правил, запрос упадёт с ошибкой ещё при выполнении Запрос.Выполнить(). ВЫРАЗИТЬ ... КАК СТРОКА(N) снимает ограничение: на выходе получается обычная строка длиной до N символов, с ней можно делать всё перечисленное.
Вторая задача — обрезка. Если в отчёт нужно вывести только первые 50 символов наименования, приведение к СТРОКА(50) обрежет хвост прямо в СУБД. С сервера приходит меньше данных, а форма отчёта не растягивается от длинных текстов.
Третья задача — поля составного типа. Если среди типов поля есть строка, ВЫРАЗИТЬ(Поле КАК СТРОКА(100)) вернёт строку для строковых значений и NULL для всех остальных.
Синтаксис ВЫРАЗИТЬ и типы, к которым приводят значение
Общая форма операции:
ВЫРАЗИТЬ(<Выражение> КАК <Тип>)
Для строки тип записывают так:
ВЫРАЗИТЬ(Документ.Комментарий КАК СТРОКА(150)) КАК Комментарий
Что можно указать после КАК:
| Тип | Запись | Для чего обычно |
|---|---|---|
| Строка | СТРОКА(N) | неограниченную строку в фиксированную, обрезка до N символов |
| Число | ЧИСЛО(Длина, Точность) | округление результата деления, фиксация разрядности |
| Дата | ДАТА | приведение поля составного типа к дате |
| Булево | БУЛЕВО | приведение поля составного типа |
| Ссылка | Справочник.Номенклатура, Документ.РеализацияТоваровУслуг | выбор одного типа из составного поля, например из Регистратор |
Несколько правил, которые нужно держать в голове:
- Ключевые слова не зависят от регистра:
ВЫРАЗИТЬ,ВыразитьиCAST(английский синтаксис) работают одинаково. - После приведения полю нужен псевдоним
КАК ИмяПоля. Без него платформа назовёт колонкуПоле1, и обращаться к ней в коде будет неудобно. - В
СГРУППИРОВАТЬ ПОповторяют то же выражение целиком, а не псевдоним. - Приведение к строке работает для строковых значений. Число или дату в строку через ВЫРАЗИТЬ не перевести — запрос вернёт ошибку. Строковое представление числа получают уже в коде через
Формат()или выводят поле как есть, а отчёт сам его отформатирует.
В конструкторе запроса приведение добавляют на вкладке «Таблицы и поля»: дважды щёлкните по полю в списке выбранных и допишите выражение вручную. Конструктор сохранит его и предложит задать псевдоним.
Примеры запросов с ВЫРАЗИТЬ КАК СТРОКА
Группировка документов по комментарию
Задача: посчитать, сколько реализаций за период оформлено с каждым комментарием, пустые не брать.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Реализация.Комментарий КАК СТРОКА(200)) КАК Комментарий,
| КОЛИЧЕСТВО(Реализация.Ссылка) КАК ЧислоДокументов
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И НЕ Реализация.ПометкаУдаления
| И ВЫРАЗИТЬ(Реализация.Комментарий КАК СТРОКА(1)) <> """"
|
|СГРУППИРОВАТЬ ПО
| ВЫРАЗИТЬ(Реализация.Комментарий КАК СТРОКА(200))
|
|УПОРЯДОЧИТЬ ПО
| ЧислоДокументов УБЫВ";
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДатаСеанса()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДатаСеанса()));
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Комментарий + ": " + Формат(Выборка.ЧислоДокументов, "ЧГ=0"));
КонецЦикла;
Обратите внимание на условие КАК СТРОКА(1)) <> """". Это быстрый способ отсечь пустые комментарии: для проверки «есть текст или нет» достаточно первого символа. Внутри строкового литерала встроенного языка кавычки удваиваются, поэтому пустая строка выглядит как четыре кавычки.
Поиск по точному тексту
Если нужно найти документы с конкретным комментарием, сравнение Комментарий = &Текст не пройдёт. Рабочий вариант:
ГДЕ
ВЫРАЗИТЬ(Реализация.Комментарий КАК СТРОКА(100)) = &Текст
Длину берите не меньше длины искомого текста. Если искомая фраза 120 символов, а в приведении стоит 100, сравнение никогда не совпадёт: слева будет обрезанная строка.
Для поиска по вхождению приведение не нужно, ПОДОБНО работает и с неограниченными строками:
ГДЕ
Реализация.Комментарий ПОДОБНО "%возврат%"
Соединение с таблицей значений по строковой колонке
Частая ситуация: из файла загрузили артикулы в таблицу значений и хотите сопоставить их с номенклатурой. Если колонку создали без описания типов или с типом Строка без длины, она уходит в запрос как неограниченная, и соединение ПО по ней падает.
Решение — привести колонку при помещении во временную таблицу:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Загрузка.Артикул КАК СТРОКА(50)) КАК Артикул,
| Загрузка.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Загрузка
|ИЗ
| &ТаблицаЗагрузки КАК Загрузка
|ИНДЕКСИРОВАТЬ ПО
| Артикул
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Загрузка.Артикул КАК Артикул,
| ВТ_Загрузка.Количество КАК Количество,
| Номенклатура.Ссылка КАК Номенклатура
|ИЗ
| ВТ_Загрузка КАК ВТ_Загрузка
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
| ПО ВТ_Загрузка.Артикул = Номенклатура.Артикул";
Запрос.УстановитьПараметр("ТаблицаЗагрузки", ТаблицаЗагрузки);
Результат = Запрос.Выполнить().Выгрузить();
Ещё надёжнее задать тип колонки сразу при создании таблицы значений:
ТаблицаЗагрузки = Новый ТаблицаЗначений;
ТаблицаЗагрузки.Колонки.Добавить("Артикул",
Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(50)));
ТаблицаЗагрузки.Колонки.Добавить("Количество",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
Таблица значений, переданная параметром, должна иметь типизированные колонки. Колонка вообще без типа в запросе не обработается, и ВЫРАЗИТЬ здесь уже не спасёт.
Значение составного типа
Поле Значение дополнительных сведений может хранить ссылку, число, дату или строку. Если нужны только строковые значения:
ВЫБРАТЬ
ДопСведения.Объект КАК Объект,
ВЫРАЗИТЬ(ДопСведения.Значение КАК СТРОКА(150)) КАК ЗначениеСтрокой
ИЗ
РегистрСведений.ДополнительныеСведения КАК ДопСведения
ГДЕ
ДопСведения.Свойство = &Свойство
Для нестроковых значений в колонке будет NULL. Если в отчёте нужен пустой текст, оберните выражение в ЕСТЬNULL(..., "").
Производительность и отладка запроса с приведением типов
Приведение к строке почти ничего не стоит, если оно стоит в списке полей ВЫБРАТЬ. СУБД обрезает значение при чтении строки, и всё.
Дороже становится, когда приведение попадает в условие или соединение по большой таблице:
- 🐢 выражение над полем не даёт СУБД использовать индекс по этому полю, читается вся таблица;
- 🐢 группировка по строке длиной 1000 символов требует больше памяти и места во временной базе СУБД, чем группировка по
СТРОКА(100); - 🐢 соединение по приведённым строкам из двух больших таблиц почти всегда идёт полным перебором.
Практические правила:
- Сначала сузьте выборку по индексированным полям (дата, ссылка, организация), а условие с
ВЫРАЗИТЬставьте вторым. - Длину выбирайте по данным, а не «с запасом». Для группировки комментариев обычно хватает 150–300 символов.
- Если по строке нужно соединять несколько раз, приведите её один раз во временной таблице и проиндексируйте, как в примере с артикулами.
- Не приводите к строке поле, у которого длина и так ограничена.
ВЫРАЗИТЬ(Номенклатура.Наименование КАК СТРОКА(10))в условииГДЕлишает запрос индекса по наименованию. Для поиска по началу строки лучшеНаименование ПОДОБНО &Началос параметром вида"Болт%".
Отдельный случай: ВЫРАЗИТЬ для поля Регистратор
К теме строк это не относится, но тот же оператор — главный инструмент оптимизации при работе с составными ссылками. Запись Движения.Регистратор.Контрагент заставляет платформу соединить таблицу движений со всеми документами, которые могут быть регистраторами. Запись с приведением соединяет только с одним:
ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Контрагент КАК Контрагент
Как посмотреть, во что превратился запрос
Для разбора медленного запроса есть два штатных инструмента.
Замер производительности. В конфигураторе при запущенной отладке включите Отладка → Замер производительности, выполните код и посмотрите время строки Запрос.Выполнить().
Технологический журнал. Он показывает текст SQL, который реально ушёл в СУБД. Создайте файл logcfg.xml в папке conf каталога установки платформы, например C:\Program Files\1cv8\conf\:
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="C:\v8log" history="2">
<event>
<eq property="name" value="DBMSSQL"/>
</event>
<event>
<eq property="name" value="DBPOSTGRS"/>
</event>
<property name="all"/>
</log>
</config>
Журнал с property name="all" растёт очень быстро, на рабочем сервере — гигабайты за час. Включайте его на короткое время, после разбора удалите или переименуйте logcfg.xml. Журнал подхватывается без перезапуска, сеансы пользователей не обрываются.
Как приведение к строке работает в MS SQL, PostgreSQL и файловой базе
Текст запроса 1С одинаковый для всех вариантов базы. Платформа сама переводит ВЫРАЗИТЬ в конструкцию конкретной СУБД.
| Вариант базы | Как хранится неограниченная строка | Во что превращается ВЫРАЗИТЬ КАК СТРОКА(N) |
|---|---|---|
| MS SQL Server | nvarchar(max) (в старых базах встречается ntext) | CAST(поле AS NVARCHAR(N)) |
| PostgreSQL (сборка для 1С) | специальный тип mvarchar | приведение к mvarchar(N) |
| Файловая база | собственный формат платформы | выполняет движок файловой базы |
Отличия, которые заметны на практике:
- 📌 Регистр букв. Сравнение строк в запросах 1С не учитывает регистр во всех вариантах. В PostgreSQL для этого и нужны типы
mchar/mvarcharиз сборки для 1С. Поэтому базу нельзя разворачивать на «чистом» PostgreSQL без патчей 1С. - 📌 Хвостовые пробелы. Строки фиксированной длины дополняются пробелами. При сравнении и группировке платформа и СУБД их не учитывают, но при выводе в код строка может прийти с пробелами. Если склеиваете результат, используйте
СокрП(). - 📌 Скорость. В файловой базе тяжёлые группировки по длинным строкам заметно медленнее, чем на клиент-серверной СУБД. Запрос, который на MS SQL идёт секунду, в файловой копии той же базы может идти минуту.
Если запрос работает в файловой копии и падает на сервере (или наоборот), причина почти никогда не в ВЫРАЗИТЬ. Чаще разница в данных: на сервере длиннее тексты или есть значения другого типа в составном поле.
Ошибки и ограничения при использовании ВЫРАЗИТЬ КАК СТРОКА
Ещё несколько ограничений, о которых редко пишут:
- 🔸 Приведение работает только внутри запроса. Во встроенном языке аналога нет: там длину строки режут через
Лев(Строка, N). - 🔸 При обрезке ничего не сообщается. Запрос не предупредит, что текст был длиннее N. Для контроля можно один раз выбрать максимальную длину: на платформе 8.3.20 и новее в запросах есть функция
ДЛИНАСТРОКИ(). - 🔸 В системе компоновки данных приведение пишут в тексте запроса набора данных. Поле
Комментарийбез приведения СКД сама не даст использовать в группировке отчёта.