Глиф Учебники

Урок 8. Запросы: ВЫБРАТЬ … ИЗ …

Курс «1С:Предприятие» · урок 8 из 9 · 4 минуты чтения

Запрос — способ получить из базы ровно те данные, которые нужны: товары дороже 100 рублей, остатки на складе, продажи за месяц по покупателям. Язык запросов 1С похож на SQL (о нём — тема SQL), только ключевые слова русские, а таблицы называются по объектам конфигурации.

Первый запрос

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

    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        Сообщить(Выборка.Наименование + ": " + Выборка.Цена);
    КонецЦикла;
КонецПроцедуры

По частям:

ВЫБРАТЬ — в результат идут поля Наименование и Цена ИЗ Справочник.Товары ГДЕ Товары.Цена > &МинЦена УПОРЯДОЧИТЬ ПО Товары.Цена УБЫВ НаименованиеЦена НаименованиеЦена НаименованиеЦена Карандаш2 Ластик1 Ручка3 Тетрадь4 Карандаш2 Ручка3 Тетрадь4 Тетрадь4 Ручка3 Карандаш2 Ластик 1 УстановитьПараметр("МинЦена", 1) 1 > 1 — нет, Ластик не прошёл Выполнить() .Выбрать()
Запрос берёт таблицу Справочник.Товары, ГДЕ с параметром МинЦена = 1 отбрасывает товар с ценой 1, УПОРЯДОЧИТЬ ПО … УБЫВ ставит дорогие первыми, а Выполнить().Выбрать() отдаёт результат.

Запросы выполняются только на сервере — отсюда директива &НаСервереБезКонтекста.

Таблицы и поля

Таблица в запросе называется по виду и имени объекта: Справочник.Товары, Документ.ПриходТовара, РегистрНакопления.ОстаткиТоваров. Табличная часть документа — отдельная таблица: Документ.ПриходТовара.Товары.

Кроме своих реквизитов у таблиц есть стандартные поля: Ссылка, Код, Наименование, ПометкаУдаления у справочников; Ссылка, Номер, Дата, Проведен у документов. Через точку можно взять реквизит связанного объекта: ПриходТовараТовары.Товар.Цена.

Параметры вместо склеивания строк

Значения в запрос передавайте только параметрами:

1С
Запрос.УстановитьПараметр("Склад", СсылкаНаСклад);
Запрос.УстановитьПараметр("Шаблон", "%кар%");

В тексте — ГДЕ Остатки.Склад = &Склад и ГДЕ Товары.Наименование ПОДОБНО &Шаблон. ПОДОБНО ищет по шаблону: % — любые символы. Склеивать значения прямо в текст запроса нельзя: ссылку так не передать вовсе, а строка с кавычкой сломает запрос.

Группировка и итоги

Сколько товара пришло всего по каждому товару — по табличной части всех проведённых документов:

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

Функции группировки: СУММА, КОЛИЧЕСТВО, МАКСИМУМ, МИНИМУМ, СРЕДНЕЕ. Все поля в ВЫБРАТЬ, кроме этих функций, должны стоять в СГРУППИРОВАТЬ ПО. Отбор по результату группировки — ИМЕЮЩИЕ, например ИМЕЮЩИЕ СУММА(ПриходТовараТовары.Количество) > 50.

Остатки регистра

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

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

Поле ресурса в этой таблице получает окончание: Количество → КоличествоОстаток. Условие по измерениям (Склад = &Склад) пишут в скобках виртуальной таблицы, а не в ГДЕ — так платформа отбирает данные до подсчёта, и запрос работает быстрее. Обороты за период даёт таблица Обороты(&Начало, &Конец), а ОстаткиИОбороты — и то и другое сразу.

Движения регистра РегистрНакопления.ОстаткиТоваров ВидДвиженияТоварСкладКоличество ПриходКарандашОсновной100 ПриходКарандашМагазин20 РасходКарандашОсновной30 ПриходРучкаОсновной50 строка другого склада отбрасывается условием в скобках — ещё до подсчёта Виртуальная таблица Остатки(, Склад = &Склад) &Склад — склад «Основной» Товар КоличествоОстаток Карандаш 70 Ручка 50 приход минус расход: Карандаш 100 − 30 = 70
Виртуальная таблица Остатки сама складывает приход и вычитает расход по движениям регистра, а условие Склад = &Склад в скобках отбрасывает движения другого склада ещё до подсчёта.

Соединения

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

1С
Запрос.Текст =
    "ВЫБРАТЬ
    |    Товары.Наименование КАК Наименование,
    |    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
    |ИЗ
    |    Справочник.Товары КАК Товары
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки
    |        ПО Товары.Ссылка = Остатки.Товар";

ЛЕВОЕ СОЕДИНЕНИЕ берёт все строки левой таблицы, а из правой — подходящие по условию ПО. Если пары нет, поля правой таблицы равны NULL, и ЕСТЬNULL(…, 0) заменяет его нулём. Остатки здесь — по всем складам вместе, потому что измерение Склад не выбрано.

ЛЕВОЕ СОЕДИНЕНИЕ, пары по условию ПО Товары.Ссылка = Остатки.Товар Товары все строки Остатки только пары Результат Наименование ТоварКоличествоОстаток НаименованиеОстаток КарандашРучкаТетрадь Карандаш90 Ручка50 Карандаш90 Ручка50 строки нет Тетрадь NULL → 0 у Тетради пары нет — поля правой таблицы NULL ЕСТЬNULL(…, 0) заменяет NULL нулём
ЛЕВОЕ СОЕДИНЕНИЕ оставляет все товары справочника: Карандаш и Ручка получают остаток по паре, а у Тетради пары нет, её остаток равен NULL, и ЕСТЬNULL заменяет его нулём.

Результат целиком

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

1С
Таблица = Запрос.Выполнить().Выгрузить();
Сообщить("Строк: " + Таблица.Количество());

Проверить, что запрос ничего не нашёл, — Запрос.Выполнить().Пустой(). Другие полезные слова: ВЫБРАТЬ ПЕРВЫЕ 10 — первые десять строк, ВЫБРАТЬ РАЗЛИЧНЫЕ — без повторов, ПОМЕСТИТЬ — временная таблица для следующего запроса в том же тексте (запросы разделяются ;).

Конструктор запроса

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

Частые ошибки

Коротко

Проверьте себя

1. Как правильно передать в запрос нужный склад?
2. Как в запросе получить остаток товара по регистру накопления?
3. Зачем в запросе с ЛЕВОЕ СОЕДИНЕНИЕ пишут ЕСТЬNULL(Остатки.КоличествоОстаток, 0)?
4. Что обязательно, если в запросе есть СУММА(...) и ещё поле Товар?