Инструменты пользователя

Инструменты сайта


1c:база:запросы

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
1c:база:запросы [2014/12/25 11:05]
admin [Объединения] уточнение
1c:база:запросы [2020/10/01 03:34] (текущий)
admin мелкое оформление
Строка 1: Строка 1:
 +====== Запросы ======
 +===== Описание =====
 +Запросы представляют собой, табличную модель доступа к данным. С помощью запросов удобно организовывать чтение данных, по той причине, что с помощью **одного** запроса (здесь читаем обращения к серверу) можно в большинстве случаев получить все необходимые для работы данные. В случае с объектной моделью доступа(работа с классом ''Справочник.Выборка''), при получении каждого элемента в переборе система будет обращаться к серверу. В том случае если база 1С работает под управлением СУБД (клиент-серверный вариант) использование запросов является более оптимальным, потому что работа СУБД ориентирована на использование запросов. **Результатом запроса всегда является одна таблица за исключением специфических случаев** (например в случае пакетного запроса). <WRAP center round tip 60%>
 +Перед тем как возьметесь за конструктор, попробуйте представить поля выходной таблицы, источники этой таблицы, приблизительно как должна получать эти данные система.
 +</WRAP>
  
 +===== Виды таблиц =====
 +Таблицы в 1С делятся на реальные и виртуальные. Реальные таблицы, это те которые действительно существуют в базе данных. Виртуальные таблицы в базе не существуют, и представляют по сути, функции которые возвращают определенным образом отфильтрованные данные из реальных таблиц. Эти таблицы сделаны для удобства разработчиков. У виртуальных таблиц могут быть параметры. Для таблиц оборотов регистра накопления к примеру можно указать дату начала и дату окончания выборки оборотов. А для таблицы остатков этого же регистра, можно указать только дату, на которую будут получены остатки.  Для этой таблицы можно указать условие (этим условием может быть отдельный запрос) и тогда будет наложен фильтр с указанным условием. 
 +<WRAP round important>
 +Если используется какое-либо условие при обращении к виртуальной таблице, необходимо указывать его в параметрах виртуальной таблицы, а не на закладке «Условия». Так как если указать условие в параметрах фильтр будет наложен в момент выполнения запроса к реальной таблице, а если указать в условии, то данные сначала будут получены, в полном объеме а уже потом наложен фильтр. В некоторых случаях такой запрос может оказаться просто "неподъемным" для сервера.
 +</WRAP>
 +Не следует переоценивать роль параметров виртуальной таблицы. Бывает начинающие разработчики разобравшись как устанавливаются параметры в виртуальных таблицах, начинают использовать их вместо реальных, даже когда в этом нет необходимости, объясняя это тем, что параметры виртуальной таблицы, работают быстро, а условие в запросе медленно. Так как обращение к виртуальной таблице, это все равно, сложный развернутый запрос к реальной таблице, то такой подход, конечно, не имеет смысла.
 +Запрос объявляется следующим образом:
 +<code 1c>Запрос = Новый Запрос
 +// и далее можно указать текст запроса, параметры и тд
 +Запрос.Текст = "ВЫБРАТЬ Номенклатура.Ссылка ИЗ Справочник.Номенклатура КАК Номенклатура"
 +</code>
 +===== Основной синтаксис языка запросов. =====
 +Для составления запроса, рекомендуется пользоваться конструктором запросов, по крайней мере в первое время, бывают случаи когда проще оперировать блоками текста, чем щелкать мышкой, но это происходит не часто и если вы начинающий разработчик, то конструктор запроса, единственный инструмент для построения запроса.
 +Опишем основные разделы часто используемые при построении запросов, полный перечень и все элементы которые можно использовать при построении запроса с детальным описанием, можно увидеть в справке.
 +
 +==== Таблицы и поля ====
 +Любой запрос начинается с выражения «Выбрать» или Select, далее следуют перечисление полей которые вы хотите видеть в запросе и источник откуда будут браться эти поля как в запросе выше, в качестве источника могут быть как таблицы базы данных, так и связи этих таблиц. Если в запросе создаются временные таблицы, после перечисления полей должно стоять ключевое слово "Поместить" и имя временной таблицы.
 +{{http://i.imgur.com/k1ww9VU.png}}
 +
 +==== Группировка строк запроса. ====
 +При формировании запроса очень часто бывает необходимо "свернуть" данные запроса, то есть к примеру у нас в результате выборки получились такие записи
 +  - Петров 100
 +  - Иванов 200
 +  - Иванов 400
 +  - Сидоров 90
 +  - Петров 150
 +Здесь в процессе группировки в качестве группируемых полей будет выступать сотрудник, в качестве суммируемых сумма. 
 +В итоге мы должны получить следующие записи:
 +  - Петров 250
 +  - Иванов 600
 +  - Сидоров 90
 +Не следует путать группировку и итоги, что бы закрепить понимание, нужно запомнить, что в результате группировки записей будет или меньше, или столько же(если нет записей которые можно сгруппировать). Помимо функции Сумма, доступны и другие функции для группировки, полный список смотрите в конструкторе. Когда вы применяете группировку, поле должно либо быть группируемым(быть в верхней правой части на закладке "Группировка"), либо к нему должна применяться какая то агрегатная функция(поле должно быть в нижней части на закладке "Группировка"). При использовании других функций("количество различных" например) суммируемое поле, может быть не числовым.
 +Пример запроса с группировкой
 +<code  1C> Запрос = Новый Запрос;
 + Запрос.Текст = 
 + "ВЫБРАТЬ
 + | РеализацияТоваровУслугТовары.Номенклатура,
 + | СУММА(РеализацияТоваровУслугТовары.Сумма) КАК Сумма
 + |ПОМЕСТИТЬ СправочникТоваров
 + |ИЗ
 + | Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
 + |
 + |СГРУППИРОВАТЬ ПО
 + | РеализацияТоваровУслугТовары.Номенклатура";
 +</code>
 +{{http://i.imgur.com/H9xwwMd.png}}
 +
 +==== Условие и параметры в запросе ====
 +На результат выборки запроса, можно накладывать условия, которые могут быть достаточно разнообразными, в качестве условия могут выступать строковые или числовые константы, значения  перечислений, предопределенные элементы справочников, подзапросы или любое значение переданное в параметре запроса. Для того, что бы указать, что выражение является параметром, перед ним указывают символ "&". За указание условия в запросе, отвечает секция "ГДЕ"
 +<code 1c> Запрос.Текст = 
 + "ВЫБРАТЬ
 + | Номенклатура.Ссылка
 + |ПОМЕСТИТЬ СправочникТоваров
 + |ИЗ
 + | Справочник.Номенклатура КАК Номенклатура
 + |ГДЕ
 + | Номенклатура.Ссылка В(&СписокСсылок)";
 +</code>
 +Передать параметр в запрос, можно следующим образом:
 +<code 1c>Запрос.УстановитьПараметр("ИмяПараметра", ЗначениеПараметра);</code>
 +
 +==== Псевдонимы ====
 +В случаях когда результат запроса может быть сразу выгружен в табличную часть документа, или в набор записей регистра, необходимо, что бы выходные поля запроса имели имена идентичные именам принимающей таблицы. Для того что бы присвоить полю свое имя его можно указать на закладке ''Объединения/Псевдонимы'' или в тексте запроса в секции указания списка полей указать ключевое слово КАК НовоеИмяВыходногоПоля напротив нужно поля. Поле для которого указан псевдоним, подсвечивается в конструкторе жирным шрифтом.
 +<code 1c> Запрос.Текст = 
 + "ВЫБРАТЬ
 + | Товары.Ссылка КАК Товар
 + |ПОМЕСТИТЬ СправочникТоваров
 + |ИЗ
 + | Справочник.Номенклатура КАК Товары
 + |ГДЕ
 + | Товары.Ссылка В(&СписокСсылок)";
 +</code>
 +{{http://i.imgur.com/B2Fwske.png}}
 +==== Объединения ====
 +Когда необходимо выбрать данные из двух никак не связанных таблиц, или получить выборку данных не связывая между собой таблицы, необходимо использовать объединение, <wrap hi>оно соединяет таблицы горизонтально, то есть вы получаете не новые поля, а новые строки</wrap>. Для этого в конструкторе на закладке ''Объединения/Псевдонимы'' необходимо добавить запрос и установить сопоставление полей с первым запросом.  Или в тексте запроса добавить конструкцию "Объединить ВСЕ"  после которой следует написать запрос, данные которого будут использоваться для объединения и проставить поля в том порядке в котором они следуют в первом запросе. Опция ''ВСЕ'' у конструкции ''ОБЪЕДИНИТЬ'' указывает на то, что в выборку попадут абсолютно все записи результата запроса, если убрать это слово то в результате второго запроса мы увидим, только те записи, которых нет в результате выборки первого запроса.
 +<code 1c> Запрос.Текст = 
 + "ВЫБРАТЬ
 + | Товары.Ссылка КАК Товар,
 + | Товары.Наименование,
 + | Товары.Код
 + |ПОМЕСТИТЬ СправочникТоваров
 + |ИЗ
 + | Справочник.Номенклатура КАК Товары
 + |ГДЕ
 + | Товары.Ссылка В(&СписокСсылок)
 + |
 + |ОБЪЕДИНИТЬ ВСЕ
 + |
 + |ВЫБРАТЬ
 + | РеализацияТоваровУслугТовары.Номенклатура,
 + | РеализацияТоваровУслугТовары.Номенклатура.Наименование,
 + | РеализацияТоваровУслугТовары.Номенклатура.Код
 + |ИЗ
 + | Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
 + |ГДЕ
 + | РеализацияТоваровУслугТовары.Ссылка = &Ссылка";
 +</code>
 +{{http://i.imgur.com/WxDvab7.png}}
 +==== Соединения ====
 +Соединения позволяют получить <wrap hi>в одной строке результата запроса данные из нескольких таблиц</wrap>, каким то образом их связав между собой. То есть почти всегда мы указываем условие, по которому система сопоставит данные из одной таблицы, с данными из другой таблицы. Например нам надо, получить остаток товара, для каждой позиции номенклатуры, которая находится в табличной части нужного нам документа. Тогда мы накладываем условие на поле номенклатура(или связываем две таблицы по полю номенклатура): 
 +{{http://i.imgur.com/mxdOWEz.png}}
 +<code 1c> Запрос.Текст = 
 + "ВЫБРАТЬ
 + | РеализацияТоваровУслугТовары.Номенклатура,
 + | ТоварыНаСкладахОстатки.КоличествоОстаток
 + |ИЗ
 + | Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
 + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
 + | ПО РеализацияТоваровУслугТовары.Номенклатура = ТоварыНаСкладахОстатки.Номенклатура" 
 +</code>
 +
 +Перед построением запроса, необходимо четко определить какие данные и из каких таблиц должны попадать в результат запроса. Огромное значение имеет то, как запрос будет связывать между собой данные из нескольких таблиц. Существуют следующие виды соединений:
 +  * **Декартово произведение**, или cross join, такое соединение получается  если не указывать какой тип связи нам нужен, система для каждой таблицы создаст набор записей, например если в одной таблице было 7 записей а во второй 12 в результате запроса вы получите 7 * 12 = 84 то есть все комбинации которые можно составить из этих данных. Забыв указать тип соединения и объединив таблицы с несколькими десятками тысяч записей(регистр остатков товара в небольшой базе) можно создать при выполнении запроса и выводе результата серьезную нагрузку на базу.
 +  * **Внутреннее соединение** или inner join(галочка "ВСЕ" не стоит не слева, не справа),  необходимо использовать тогда когда из двух таблиц нужно получить только те данные которые совпадают по условию связи в обоих таблицах.
 +  * **Левое соединение** или left inner join (галочка "ВСЕ" стоит слева) – в результат запроса попадают все записи которые находятся в левой таблице, и те записи из правой таблицы которые отвечают условию связи.
 +  * **Правое соединение** или right inner join тоже самое что и левое соединение, только в результат попадают все записи из таблицы справа(галочка "ВСЕ" стоит справа), следует отметить, что 1С старается придерживаться левого соединения и если вы попробуете настроить правое соединение,  с помощью конструктора, при нажатии на кнопку ОК, она поменяет местами таблицы и сделает левое соединение.
 +  * **Полное соединение** или full outer join (галочка "ВСЕ" стоит и слева и справа) в запрос попадут все записи из обоих таблиц, которые 1С попытается сопоставить с помощью условия связи.
 +
 +==== Вложенные запросы ====
 +Вложенные запросы это "подзапрос" в запросе, который добавляет еще одну таблицу в источники данных запроса, содержимое которой будет определяться его результатом. Вложенные запросы бывают полезны в основном при создании сложных связей, условий или когда нужно добавить уровень абстракции к определенному набору данных их можно обернуть вложенным запросом, область применения у вложенных запросов достаточно широкая. Однако при их использовании следует помнить о производительности. Создать вложенный запрос можно с помощью кнопки на закладке "Таблицы и поля". После нажатия на эту кнопку, откроется еще одно окно построителя запросов. Где можно будет построить еще один запрос.
 +{{http://i.imgur.com/8mjHq5W.png}}
 +Пример запроса, сам по себе натянутый, так как кроме вложенного запроса, в нем ничего нет, но как таковой вложенный запрос демонстрирует достаточно хорошо.
 +<code> Запрос.Текст = 
 + "ВЫБРАТЬ
 + | ВложенныйЗапрос.Номенклатура
 + |ИЗ
 + | (ВЫБРАТЬ
 + | РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура
 + | ИЗ
 + | Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
 + | ГДЕ
 + | РеализацияТоваровУслугТовары.Ссылка = &Ссылка) КАК ВложенныйЗапрос" 
 +</code>
 +
 +==== Сортировка ====
 +Если необходимо упорядочить результаты запроса, такое поведение, можно настроить на закладке конструктора ''Порядок'',  на этой закладке, можно перечислить список полей по которым нужно производить  сортировку или можно в тексте запроса указать конструкцию "УПОРЯДОЧИТЬ ПО"  и перечислить поля по которым необходимо производить сортировку. Также доступно выражение "АВТОУПОРЯДОЧИВАНИЕ", с помощью которого для ссылочных типов данных происходит сортировка по представлению ссылки. 
 +
 +==== Тип данных NULL ====
 +NULL тип данных который можно получить только в одном месте: в запросе, этот тип данных получается, когда при соединении таблиц левым, правым или полным соединением, нет данных удовлетворяющих условию соединения.  Любая проверка значения с этим типом всегда возвращает Ложь. Любая операция с этим полем возвращает NULL. Для обработки этого типа существуют следующие операторы: 
 +  * ''ЕСТЬNULL(ПроверяемоеЗначение, ЗначениеКотороеНадоВернутьЕслиВПроверяемомЗначенииNULL)'' выражение вернет либо первое значение, либо второе если первое NULL, удобно использовать в полях выходной таблицы
 +  * ''ЕСТЬ NULL(ЗначениеТипаNULL)'' выражение возвращает либо Истина, либо Ложь.
 +  * ''ЕстьNULL'' FIXME не могу вспомнить как юзать, помню что возвращает ИСТИНА если NULL слева.
 +
 +==== Использование функций ====
 +Язык запросов обладает ограниченным набором функций, для обработки данных, так как считается, что запросы это средство для получения данных, а не для их обработки. Но необходимый минимум, все таки имеется. Например нет возможность получить дату без времени, но есть возможность привести дату к началу дня, месяца, года, с помощью функции, начало периода. Условный оператор тоже присутствует в виде функции "Выбор". Функция "Значение" позволяет в запросе получать значения перечислений, и к некоторым значениям системных перечислений(например вид движения регистра) или значений предопределенных значений справочника. Описание функций языка запросов, отсутствует во встроенном синтаксис помощнике, но его можно найти в  справке которая находится в меню «Справка» или по кнопке F1. Там нужно открыть  содержание справки (можно сразу его открывать из этого же меню, или по shift F1) и выбрать ''Встроенный язык – Работа с запросами – Синтаксис языка запросов – Ключевые слова и функции – Функции.''
 +
 +===== Получение данных из табличных частей документов =====
 +Если необходимо получить данные из табличной части какого либо документа, следует обращаться напрямую к табличной части документа. Если рассматривать конструктор запросов, то вот так делать **неправильно**:
 +{{http://i.imgur.com/f3Te6zy.gif}}
 +<code>
 + Запрос.Текст = 
 + "ВЫБРАТЬ
 + | ОтчетОРозничныхПродажах.Товары.(
 + | Номенклатура
 + | )
 + |ИЗ
 + | Документ.ОтчетОРозничныхПродажах КАК ОтчетОРозничныхПродажах";
 +
 +</code>
 +
 +А вот так будет правильно:
 +{{http://i.imgur.com/FgYPDrB.gif}}
 +<code>
 + Запрос.Текст = 
 + "ВЫБРАТЬ
 + | ОтчетКомитентуОПродажахТовары.Номенклатура
 + |ИЗ
 + | Документ.ОтчетКомитентуОПродажах.Товары КАК ОтчетКомитентуОПродажахТовары";
 +</code>
 +Разумеется в любом случае нужно наложить условие на поле "Ссылка" что бы не получить в результате запроса табличные части всех существующих в системе документов.