Урок 8. Запросы: ВЫБРАТЬ … ИЗ …
Запрос — способ получить из базы ровно те данные, которые нужны: товары дороже 100 рублей, остатки на складе, продажи за месяц по покупателям. Язык запросов 1С похож на SQL (о нём — тема SQL), только ключевые слова русские, а таблицы называются по объектам конфигурации.
Первый запрос
&НаСервереБезКонтекста
Процедура ДорогиеТовары()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Наименование КАК Наименование,
| Товары.Цена КАК Цена
|ИЗ
| Справочник.Товары КАК Товары
|ГДЕ
| Товары.Цена > &МинЦена
|УПОРЯДОЧИТЬ ПО
| Товары.Цена УБЫВ";
Запрос.УстановитьПараметр("МинЦена", 1);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Наименование + ": " + Выборка.Цена);
КонецЦикла;
КонецПроцедурыПо частям:
Новый Запрос— объект запроса,Текст— сам запрос: многострочная строка, каждая следующая строка начинается с|;ВЫБРАТЬ— какие поля нужны,КАК— их имена в результате;ИЗ Справочник.Товары КАК Товары— откуда: таблица справочника и короткое имя для неё (псевдоним);ГДЕ— условие отбора;&МинЦена— параметр, его значение задаётУстановитьПараметр;УПОРЯДОЧИТЬ ПО … УБЫВ— сортировка от большего к меньшему (ВОЗРили ничего — от меньшего);Выполнить()возвращает результат,Выбрать()— выборку, которую читают циклом, как в прошлом уроке.
Запросы выполняются только на сервере — отсюда директива &НаСервереБезКонтекста.
Таблицы и поля
Таблица в запросе называется по виду и имени объекта: Справочник.Товары, Документ.ПриходТовара, РегистрНакопления.ОстаткиТоваров. Табличная часть документа — отдельная таблица: Документ.ПриходТовара.Товары.
Кроме своих реквизитов у таблиц есть стандартные поля: Ссылка, Код, Наименование, ПометкаУдаления у справочников; Ссылка, Номер, Дата, Проведен у документов. Через точку можно взять реквизит связанного объекта: ПриходТовараТовары.Товар.Цена.
Параметры вместо склеивания строк
Значения в запрос передавайте только параметрами:
Запрос.УстановитьПараметр("Склад", СсылкаНаСклад);
Запрос.УстановитьПараметр("Шаблон", "%кар%");В тексте — ГДЕ Остатки.Склад = &Склад и ГДЕ Товары.Наименование ПОДОБНО &Шаблон. ПОДОБНО ищет по шаблону: % — любые символы. Склеивать значения прямо в текст запроса нельзя: ссылку так не передать вовсе, а строка с кавычкой сломает запрос.
Группировка и итоги
Сколько товара пришло всего по каждому товару — по табличной части всех проведённых документов:
Запрос.Текст =
"ВЫБРАТЬ
| ПриходТовараТовары.Товар КАК Товар,
| СУММА(ПриходТовараТовары.Количество) КАК Количество
|ИЗ
| Документ.ПриходТовара.Товары КАК ПриходТовараТовары
|ГДЕ
| ПриходТовараТовары.Ссылка.Проведен
|СГРУППИРОВАТЬ ПО
| ПриходТовараТовары.Товар";Функции группировки: СУММА, КОЛИЧЕСТВО, МАКСИМУМ, МИНИМУМ, СРЕДНЕЕ. Все поля в ВЫБРАТЬ, кроме этих функций, должны стоять в СГРУППИРОВАТЬ ПО. Отбор по результату группировки — ИМЕЮЩИЕ, например ИМЕЮЩИЕ СУММА(ПриходТовараТовары.Количество) > 50.
Остатки регистра
Остатки не нужно считать по документам: у регистра остатков есть виртуальная таблица Остатки. Она сама складывает приход и расход. Первый параметр в скобках — дата; если его пропустить, получаются текущие остатки:
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Товар КАК Товар,
| Остатки.КоличествоОстаток КАК Количество
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(, Склад = &Склад) КАК Остатки";
Запрос.УстановитьПараметр("Склад", СсылкаНаСклад);Поле ресурса в этой таблице получает окончание: Количество → КоличествоОстаток. Условие по измерениям (Склад = &Склад) пишут в скобках виртуальной таблицы, а не в ГДЕ — так платформа отбирает данные до подсчёта, и запрос работает быстрее. Обороты за период даёт таблица Обороты(&Начало, &Конец), а ОстаткиИОбороты — и то и другое сразу.
Соединения
Чтобы показать все товары вместе с остатком, в том числе товары без остатка, справочник соединяют с остатками:
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Наименование КАК Наименование,
| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
|ИЗ
| Справочник.Товары КАК Товары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки
| ПО Товары.Ссылка = Остатки.Товар";ЛЕВОЕ СОЕДИНЕНИЕ берёт все строки левой таблицы, а из правой — подходящие по условию ПО. Если пары нет, поля правой таблицы равны NULL, и ЕСТЬNULL(…, 0) заменяет его нулём. Остатки здесь — по всем складам вместе, потому что измерение Склад не выбрано.
Результат целиком
Вместо выборки результат можно получить таблицей значений:
Таблица = Запрос.Выполнить().Выгрузить();
Сообщить("Строк: " + Таблица.Количество());Проверить, что запрос ничего не нашёл, — Запрос.Выполнить().Пустой(). Другие полезные слова: ВЫБРАТЬ ПЕРВЫЕ 10 — первые десять строк, ВЫБРАТЬ РАЗЛИЧНЫЕ — без повторов, ПОМЕСТИТЬ — временная таблица для следующего запроса в том же тексте (запросы разделяются ;).
Конструктор запроса
Набирать запросы руками не обязательно. В модуле щёлкните правой кнопкой мыши внутри текста запроса или на пустом месте и выберите Конструктор запроса…. В нём таблицы, поля, условия, группировки и соединения выбираются мышью, а конструктор пишет текст сам. Новичкам полезно делать запрос в конструкторе и читать, что получилось.
Частые ошибки
- Запрос в цикле. Выполнять запрос для каждого товара по отдельности — очень медленно. Получите всё одним запросом с соединением или группировкой.
- Кавычки в тексте запроса. Строка внутри строки пишется удвоенными кавычками:
""Карандаш"". Проще передать значение параметром. - Забыта
|в начале строки многострочного текста — синтаксическая ошибка модуля. - Поле не выбрано. Если поля нет в
ВЫБРАТЬ, обращениеВыборка.Поледаст ошибку «Поле объекта не обнаружено». - NULL в результате. После левого соединения поля без пары —
NULL. В запросе арифметика с ним даёт сноваNULL, а в коде — ошибку; используйтеЕСТЬNULL.
Коротко
- Запрос:
Новый Запрос,Текст,УстановитьПараметр,Выполнить().Выбрать()или.Выгрузить(). - Основа текста:
ВЫБРАТЬ … ИЗ … ГДЕ … СГРУППИРОВАТЬ ПО … УПОРЯДОЧИТЬ ПО …. - Значения передаются параметрами
&Имя, не склейкой строк. - Остатки и обороты регистров — виртуальные таблицы
Остатки,Обороты,ОстаткиИОбороты, условия — в скобках. - Запросы выполняются на сервере; большой запрос лучше собрать в конструкторе.