урок 4 из 18

Отбор: ГДЕ

Писать условия отбора со сравнениями, связками и скобками; различать пустую ссылку, NULL и ноль; отбирать по иерархии и понимать, какие условия мешают базе работать быстро.

17 мин чтения · 4 главы ·4 задания ·домашняя работа

Условие отбора и обязательные привычки

Часть ГДЕ решает, какие строки останутся в результате. Условие проверяется для каждой строки отдельно: если оно истинно — строка идёт дальше, если нет — исчезает. Строку при этом ГДЕ не меняет: отбор только пропускает или не пропускает.

ВЫБРАТЬ
    Док.Номер КАК Номер,
    Док.Дата КАК Дата,
    Док.СуммаДокумента КАК Сумма
ИЗ
    Документ.РеализацияТоваровУслуг КАК Док
ГДЕ
    Док.Проведён
все строки таблицы1 200 накладныхГДЕПроведёнИ Дата >= &Началоосталось840условие не меняет строки — оно только решает, брать их или нет
Условие проверяется для каждой строки по отдельности: строка либо остаётся целиком, либо выбрасывается целиком.

Обратите внимание на условие: Док.Проведён — и всё. Поле логического типа уже само по себе истина или ложь, и писать = ИСТИНА не нужно. Отрицание пишется словом НЕ: НЕ Док.ПометкаУдаления.

Сравнения обычные: =, <> (не равно), >, >=, <, <=. Работают они с числами, датами, строками и ссылками — но только с сопоставимыми типами. Сравнить ссылку со строкой нельзя: платформа ответит «недопустимые типы операндов». Это хорошая ошибка: она громкая и находится сразу.

Отдельно стоит разобрать, как в условие попадает постоянное значение. С числом и строкой всё просто: они пишутся прямо в тексте запроса. А вот ссылку прямо в тексте не напишешь — у неё нет записи буквами. Для этого есть функция ЗНАЧЕНИЕ:

ГДЕ
    Док.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОпераций.Продажа)
    И Док.Организация <> ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка)

В скобках пишется полное имя того, на что ссылаемся: перечисление и его значение, предопределённый элемент справочника, пустая ссылка нужного вида. Платформа проверяет это имя при разборе запроса — опечатка выявится сразу, а не превратится в пустой результат.

Всё остальное, что приходит снаружи, передаётся параметром: &Склад, &Начало, &Организация. Разница между ЗНАЧЕНИЕ и параметром — не в синтаксисе, а в том, кто решает: ЗНАЧЕНИЕ пишут для того, что закреплено в конфигурации и не меняется, параметр — для того, что выбирает человек или подставляет код. Следующий урок целиком про параметры, так что пока достаточно знать, что знак амперсанда означает «сюда придёт значение снаружи».

Второе условие, которое пишут почти всегда, — отсечение помеченных на удаление. Пометка не удаляет запись: она остаётся в базе и в запрос попадёт. Поэтому НЕ Тов.ПометкаУдаления — такая же привычка, как отбор проведённых.

И третья привычка, менее очевидная: условие в ГДЕ работает после того, как строки прочитаны. Для обычных таблиц это нормально — база умеет пользоваться индексами и не читать лишнего. Но для виртуальных таблиц регистров правило другое, и мы про него уже говорили: отбор надо отдавать в параметры таблицы, а не в ГДЕ. Разница в скорости бывает десятикратной.

И, ИЛИ, НЕ и три сокращения

Условия соединяются словами И, ИЛИ, НЕ. Здесь язык ведёт себя как математика, и именно это подводит.

ГДЕ
    Док.Проведён
    И Док.Дата >= &Начало
    И Док.Дата <= &Конец

Пока все связки — И, всё просто: строка остаётся, если истинны все условия. Трудность начинается, когда появляется ИЛИ. И связывает сильнее, чем ИЛИ — так же, как умножение сильнее сложения. Условие А ИЛИ Б И В читается как А ИЛИ (Б И В), а не как (А ИЛИ Б) И В.

А ИЛИ Б И Вто же, что: А ИЛИ (Б И В)(А ИЛИ Б) И Вскобки меняют смыслсклад Север ИЛИ склад ЮгИ сумма > 1000без скобок сюда попадётвесь склад Север целикомскобки дешевле, чем разбор жалобы на отчёт
Без скобок И связывает сильнее: условие читается не так, как написано в голове.

Разница между этими двумя вариантами в отчёте выглядит так. Задача: «продажи по складам Север и Юг на сумму больше тысячи». Без скобок получится «весь склад Север целиком, плюс со склада Юг только крупные» — и человек, который смотрит отчёт, увидит подозрительно много мелких строк по одному складу и ни одной по другому.

Со словом НЕ связана отдельная неприятность: оно охотно накапливается. Условие «не непроведённые и не без склада» человек читает вслух дважды и всё равно не уверен. Правило простое: отрицание применяют к одному простому условию, а не к длинному выражению. Там, где хочется написать «НЕ (А И Б)», почти всегда понятнее «НЕ А ИЛИ НЕ Б» — и, что важнее, понятнее тому, кто откроет запрос после вас. Проверить себя можно вслух: если условие не получается произнести одним предложением без запинки, его стоит переписать, а не оставлять с мыслью «потом разберусь».

Есть три сокращения, которые делают условия короче и понятнее.

В — проверка на попадание в список: Док.Склад В (&Север, &Юг). То же самое можно написать через ИЛИ, но с тремя складами это уже громоздко, а с параметром-списком — невозможно. В список можно передать и результат другого запроса, но это тема десятого урока.

МЕЖДУ — попадание в диапазон, включая границы: Док.Дата МЕЖДУ &Начало И &Конец. Это в точности то же, что два сравнения через И, только короче и читается лучше. Ловушка здесь в датах и границах периода — ей посвящён следующий урок.

ПОДОБНО — поиск по образцу в строках: Тов.Наименование ПОДОБНО "%молоко%". Знак процента означает «любое количество любых символов», подчёркивание — «ровно один символ». Вещь полезная и дорогая: поиск по образцу, начинающемуся с процента, не может воспользоваться индексом, и на большом справочнике это заметно.

У ПОДОБНО есть неочевидная сторона: а как искать сам знак процента, если он встречается в тексте? Для этого к образцу приписывают СПЕЦСИМВОЛ "\", и тогда "50\%%" означает «начинается с пятидесяти процентов». Нужно это редко, но когда нужно — не найти на ходу.

И четвёртая конструкция, которой нет в обычных базах, — проверка типа значения. В 1С поле бывает составного типа: «Регистратор» в регистре — это любой документ, «Субконто» — любой справочник из списка. Спросить, что именно лежит в поле, можно так:

ГДЕ
    Движ.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг

Условие истинно, когда в поле лежит ссылка именно этого вида. Рядом живёт функция ТИПЗНАЧЕНИЯ(Поле), которая возвращает сам тип и сравнивается с ТИП(Документ.РеализацияТоваровУслуг), — записи разные, смысл один. Пригождается это в любом запросе к движениям, где нужны только продажи, а регистратором бывает десяток разных документов.

Три сорта пустоты и иерархия

Отдельная группа условий — про пустоту. Здесь чаще всего и путаются, потому что «пусто» в 1С бывает трёх разных сортов.

Пустая ссылка — поле есть, оно ссылочного типа, но значение в нём не выбрано. Так выглядит незаполненный склад в документе. Проверяется сравнением с пустой ссылкой нужного типа:

ГДЕ
    Док.Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)

NULL — поля нет вовсе. Появляется он не в самой таблице, а там, где строке не нашлось пары: при левом соединении (урок 7) и в виртуальных таблицах, где движений не было. Проверяется словами ЕСТЬ NULL — сравнение через = с ним не работает, потому что NULL не равен ничему, включая самого себя.

Пустая ссылкаполе есть, значение не заполненоNULLполя нет: не нашлось пары= ЗНАЧЕНИЕ(Справочник.…ПустаяСсылка)ЕСТЬ NULLпроверяются они по-разному, и перепутать их — обычное дело
Пустое значение хранится в поле, а NULL означает, что поля нет вовсе.

Пустое значение непримитивного типа — ноль для числа, пустая строка для строки, «нулевая» дата. Отдельного слова для них нет: сравниваются обычным =.

Рядом стоит функция ЕСТЬNULL(Поле, Значение): она подставляет второе значение там, где первое оказалось NULL. В запросах к остаткам её пишут почти всегда: ЕСТЬNULL(Ост.КоличествоОстаток, 0) — иначе товар, по которому не было движений, даст в отчёте пустую ячейку вместо честного нуля.

И ещё одно условие, специфичное для 1С: В ИЕРАРХИИ. Оно проверяет, лежит ли элемент в группе или в любой её подгруппе:

ГДЕ
    Тов.Ссылка В ИЕРАРХИИ (&Группа)

Без него отбор «товары группы Молочное» найдёт только те, что лежат прямо в ней, и пропустит всё, что разложено по подгруппам. Забытая иерархия — типовая причина отчёта, в котором «половины товаров нет».

С иерархией связана и вторая ловушка, поменьше: группа — это тоже строка справочника. Запрос «все товары» вернёт и папки, и это редко то, что нужно: в отчёте появятся строки «Молочное» и «Бакалея» с пустой ценой. Отсекаются они полем ЭтоГруппа:

ГДЕ
    НЕ Тов.ЭтоГруппа
    И Тов.Ссылка В ИЕРАРХИИ (&Группа)

И последнее про пустоту — пустая дата. Дата в 1С не бывает незаполненной в смысле NULL: у неё есть «нулевое» значение, начало отсчёта. В условии его записывают как ДАТАВРЕМЯ(1, 1, 1), и проверка «дата оплаты не заполнена» выглядит как сравнение с ним. Написать «Дата ЕСТЬ NULL» тут нельзя — поле есть, просто значение в нём нулевое.

Какие условия стоят дорого

Теперь о том, как условия сказываются на скорости, — коротко, потому что подробно это второй уровень, но три вещи полезны уже сейчас.

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

Второе: условие с функцией по полю мешает индексу. Сравнение Док.Дата >= &Начало база может выполнить по индексу; условие вида «год документа равен 2026» — уже нет: чтобы вычислить год, надо прочитать каждую строку. Отсюда правило: сравнивают поле со значением, а не результат функции от поля.

Третье: ПОДОБНО с процентом в начале читает всё. Поиск «содержит молоко» вынуждает базу просмотреть каждую строку. На справочнике в тысячу позиций это незаметно, на ста тысячах — секунды. Если поиск по подстроке нужен постоянно, для этого есть полнотекстовый поиск, и он устроен иначе.

условиекак ведёт себя
Поле = значениеможет использовать индекс
Поле МЕЖДУ А И Бможет использовать индекс
Функция(Поле) = значениеиндекс не поможет
Поле ПОДОБНО "%текст%"читает всё подряд

Слово «индекс» тут стоит объяснить, потому что дальше оно встретится ещё не раз. Индекс — это отдельно хранимый упорядоченный список значений одного поля со ссылками на строки. Он устроен как алфавитный указатель в конце книги: чтобы найти все упоминания слова, не нужно читать книгу — достаточно открыть указатель на нужной букве. Поэтому условие «дата больше такой-то» база выполняет, не читая таблицу: она находит место в указателе и берёт всё, что дальше. А условие «год даты равен 2026» указателем не пользуется: в нём записаны даты, а не годы, и чтобы получить год, надо взять каждую строку.

Отсюда и правило про поле слева. Указатель построен по значениям поля — значит, и искать по нему можно только значения поля. Любое преобразование ломает соответствие: ГОД(Дата), НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ), склейка строк, арифметика по числу. Почти всегда такое условие переписывается в диапазон: вместо «месяц равен» — «дата между первым и последним моментом месяца», и это ровно тот приём, о котором говорит следующий урок.

И последнее, о чём стоит помнить при отборе, — порядок условий не важен для результата и не важен для скорости. База сама решает, какое условие применить первым, и обычно решает разумно. Писать «сначала самое отсекающее» не нужно: это привычка из других систем, здесь она ничего не даёт. Порядок условий имеет значение только для читателя, и его стоит выбирать по смыслу: сначала отбор по периоду, потом по организации, потом частности.

Задания урока

Каждое проверяется сразу: ответ сверяется с эталоном, и на неверный вариант приходит разбор.

  1. Какие условия почти всегда нужны в запросе к документам?средне
  2. Условие «Склад = Север ИЛИ Склад = Юг И Сумма > 1000» отберёт крупные продажи по двум складам.средне
  3. Соотнесите вид пустоты и способ проверки.средне
  4. Условие «НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) = &Дата» и условие «Дата МЕЖДУ &Начало И &Конец» одинаково хороши.сложно

Практика и материалы по теме курса

Пройти урок с проверкой заданий Курс «1С: запросы и отчёты» открыт и бесплатен, прогресс сохраняется.
Открыть курс