Как исключить счет из запроса 1с
Зачастую нужно заранее сделать выборку из базы данных по некоему условию. Для этого в 1С 8.3 необходимо использовать вложенные запросы.
Но следует учитывать, что в большинстве случаев вложенные запросы в 1С бесполезны без соединения их результата с другими таблицами. Такое соединение практически в любом случае приведет к сильному замедлению выполнения запроса в целом.
Пример вложенного запроса на языке запросов
Приведу пример вложенного запроса на языке запросов 1С. Допустим, нам нужно сделать выборку суммы некоторого остатка по отдельным клиентам на определенную дату:
ВЫБРАТЬ
НераспОплатыОстатки.Заказчик,
НераспОплатыОстатки.СуммаОст
ИЗ(ВЫБРАТЬ
Заказчики.Ссылка КАК СсылкаНаСпрЗаказчики
ИЗ
Справочник.Заказчики КАК Заказчики
ГДЕ
Заказчики.Ссылка В(&Заказчики)) КАК ВложЗапросЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления. НераспОплаты.Остатки КАК НераспОплаты
ПО ВложЗапрос.СсылкаНаСпрЗаказчики = НераспОплатыОстатки.Заказчик
Когда СУБД будет выполнять такой запрос, не исключены неверные действия оптимизатора, так как трудно определиться с планом обработки запроса. Когда СУБД соединяет две таблицы, оптимизатор строит алгоритм на основе вычисления количества записей в этих таблицах.
Когда же используется вложенный запрос, вычислить количество записей, вернувшихся из вложенного запроса, очень трудно.
Как лучше?
Именно поэтому фирма 1С крайне не рекомендует использовать вложенные запросы, а вместо них разработала временные таблицы. С использованием временных таблиц наш предыдущий запрос будет выглядеть так:
// Временная таблица
ВЫБРАТЬ
Заказчики.Ссылка КАК Заказчики
ПОМЕСТИТЬ табЗаказчики
ИЗ
Справочник.Заказчики КАК Заказчики
ГДЕ Заказчики.Ссылка В (&Заказчики)
;// Основной запрос
ВЫБРАТЬ
табКлиенты.Ссылка,
НераспОплатыОстатки.СуммаОст,
ИЗ
табЗаказчики КАК табЗаказчики
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.НераспОплаты.Остатки(
,
Заказчик В
(ВЫБРАТЬ
табЗаказчики.Заказчики
ИЗ
табЗаказчики)) КАК НераспОплатыОстатки
ПО табЗаказчики.Заказчики = НераспОплатыОстатки.Заказчики
Смотрите также видео-урок про вложенные запросы:
Если вы только начинаете программировать в 1С или просто хотите систематизировать свои знания - попробуйте Школу программирования 1С нашего друга Владимира Милькина. Пошаговые и понятные уроки даже для новичка с поддержкой учителя.
Попробуйте бесплатно по ссылке >>
Теперь оптимизатор знает заранее, сколько записей во временной таблице, и без труда оптимизирует алгоритм выполнения соединения таблиц.
(8) использовать "В" имеет смысл только в условии джойна.
в (1) самый оптимальный путь, по сколько джойн большого с малым очень быстрый и проверка на нулл в конце то-же быстрая
(10) проверка на нулл конечно в секции "где", то есть сначало джойн а потом условие на нулл по маленькой таблице, тем самым мы оставим только записи из большой таблице которых нет в маленькой
(11) Ну и казалось бы зачем тут джойн, если нужна только проверка.
(13)
в(12) прделагает сразу проверку наложить на невхождение в список из подзапроса.
Вопрос только в том, что быстрее будет соедеинение и простой отбор НЕ Есть Null
или отбор с условием Не В (список из подзапроса)
(9) Почему?
Чем такой запрос плох?
К тому же фирма 1С рекомендует так не делать, т.к. возможно появление тормозов.
В общем на выбор.
(18) Ну так джойн надо внутренний использовать, а не левый. В условиях соединения все и проверять, чтобы именно он убрал лишнее. А с левым те же яйца только в профиль, все равно в where проверка, а не в on.
(20) Вот запрос от балды, хочется увидеть вариант с внутренним соединением (для самообразования так сказать).
Получить не праздничные дни из графика
[1с]
ВЫБРАТЬ
РегламентированныйПроизводственныйКалендарь.ДатаКалендаря
ПОМЕСТИТЬ ВТПразднечныеДни
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
ГДЕ
РегламентированныйПроизводственныйКалендарь.ДатаКалендаря >= &ДатаНачала
И РегламентированныйПроизводственныйКалендарь.ДатаКалендаря <= &ДатаОкончания
И РегламентированныйПроизводственныйКалендарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Праздник)
ИНДЕКСИРОВАТЬ ПО
РегламентированныйПроизводственныйКалендарь.ДатаКалендаря
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ГрафикиРаботыПоВидамВремени.ГрафикРаботы,
ГрафикиРаботыПоВидамВремени.Дата,
ГрафикиРаботыПоВидамВремени.ОсновноеЗначение
ИЗ
РегистрСведений.ГрафикиРаботыПоВидамВремени КАК ГрафикиРаботыПоВидамВремени
ЛЕВОЕ СОЕДИНЕНИЕ ВТПразднечныеДни КАК ВТПразднечныеДни
ПО ГрафикиРаботыПоВидамВремени.Дата = ВТПразднечныеДни.ДатаКалендаря
ГДЕ
ГрафикиРаботыПоВидамВремени.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
И ГрафикиРаботыПоВидамВремени.ГрафикРаботы = &ГрафикРаботы
И ГрафикиРаботыПоВидамВремени.План
И ВТПразднечныеДни.ДатаКалендаря ЕСТЬ NULL
[/1с]
ВЫБРАТЬ
ЛК_ЛизингополучательОС.ДоговорКонтрагента КАК ДоговорКонтрагента
ПОМЕСТИТЬ вр_ДоговораОС
ИЗ
РегистрСведений.ЛК_ЛизингополучательОС КАК ЛК_ЛизингополучательОС
ГДЕ
ЛК_ЛизингополучательОС.Организация = &Организация
И ЛК_ЛизингополучательОС.ОсновноеСредство В(&ОсновноеСредство)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(ХозрасчетныйДвиженияССубконто.Период, ДЕНЬ) КАК Дата,
СУММА(ХозрасчетныйДвиженияССубконто.Сумма) КАК Сумма
ПОМЕСТИТЬ вр_Основная
ИЗ
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
,
,
СчетДт = &Счет51
И СчетКт В ИЕРАРХИИ (&Счет62)
И СубконтоКт2 В
(ВЫБРАТЬ
вр_ДоговораОС.ДоговорКонтрагента
ИЗ
вр_ДоговораОС КАК вр_ДоговораОС),
,
) КАК ХозрасчетныйДвиженияССубконто
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(ХозрасчетныйДвиженияССубконто.Период, ДЕНЬ)
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(ХозрасчетныйДвиженияССубконто.Период, ДЕНЬ),
ХозрасчетныйДвиженияССубконто.Сумма
ИЗ
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
,
,
СчетДт В ИЕРАРХИИ (&Счет62)
И СчетКт В ИЕРАРХИИ (&Счет62)
И (СубконтоДт2 В
(ВЫБРАТЬ
вр_ДоговораОС.ДоговорКонтрагента КАК ДоговорКонтрагента
ИЗ
вр_ДоговораОС КАК вр_ДоговораОС)
ИЛИ СубконтоКт2 В
(ВЫБРАТЬ
вр_ДоговораОС.ДоговорКонтрагента КАК ДоговорКонтрагента
ИЗ
вр_ДоговораОС КАК вр_ДоговораОС)),
,
) КАК ХозрасчетныйДвиженияССубконто
ГДЕ
ХозрасчетныйДвиженияССубконто.Регистратор ССЫЛКА Документ.КорректировкаДолга
И ХозрасчетныйДвиженияССубконто.СубконтоДт2 <> ХозрасчетныйДвиженияССубконто.СубконтоКт2
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
вр_Основная.Дата КАК Дата,
СУММА(вр_Основная.Сумма) КАК Сумма
ИЗ
вр_Основная КАК вр_Основная
ГДЕ
вр_Основная.Сумма > 0
Войдите как ученик, чтобы получить доступ к материалам школы
Язык запросов 1С 8.3 для начинающих программистов: соединения
Автор уроков и преподаватель школы: Владимир Милькин
Соединения в запросах
Соединение - одна из самых важных и нужных операций, выполняемых реляционными системами управления базами данных.
Соединения используются для того, чтобы сопоставить строки одной таблицы строкам другой таблицы.
Для того, чтобы осознать необходимость соединений давайте решим следующую задачу.
У нас в базе есть справочник Клиенты:
И справочник Ассоциации:
Наша задача вывести любимые ассоциации клиентов, основываясь на цвете.
Таким образом для Наташи любимой ассоциацией будет трава, так как её любимый цвет зелёный. А для Петра - солнце. Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь.
Для Андрея вообще нет подходящей ассоциации, так его любимый цвет красный, а ассоциаций красного цвета в базе нет.
Будем решать задачу постепенно.
Сначала запросим всех клиентов и их любимые цвета :
Затем запросим все ассоциации и их цвета :
Теперь нам каким-то образом следует совместить первую и вторую таблицу. Чтобы это сделать запросим информацию сразу из двух таблиц. Для этого перечислим обе таблицы в секции ИЗ через запятую. Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь. А в секции ВЫБРАТЬ укажем поля из обеих таблиц:
Если мы попробуем выполнить этот запрос, то получим ошибку:
Причина ошибки в том, что поле Наименование присутствует сразу в обеих таблицах (Клиенты и Ассоциации) и система просто не знает поле из какой именно таблицы имеется в виду.
Чтобы устранять подобные неоднозначности при выборке из более чем одной таблицы принято указывать полные названия полей. Полное название поля включает в себя полное имя таблицы (например, Справочник.Клиенты) и имя самого поля (например, Наименование).
Таким образом полное название поля Наименование из таблицы Клиенты будет Справочник.Клиенты.Наименование.
А полное названия поля Наименование из таблицы Ассоциации будет Справочник.Ассоциации.Наименование.
Перекрёстное соединение
Перепишем предыдущий запрос с полными именами полей:
Только что мы произвели перекрёстное соединение двух таблиц. Обратите внимание на то, каким образом сформировался результат:
Внутреннее соединение
Очевидно, что результат перекрестного соединения двух таблиц не есть решение нашей задачи. Нам нужны не все записи из перекрёстного соединения, а только те у которых поля ЛюбимыйЦвет и Цвет имеют одинаковое значение:
Чтобы получить эти записи добавим к предыдущему запросу секцию ГДЕ:
Это то, что нужно - мы решили, поставленную задачу!
В последнем запросе мы использовали перекрёстное соединение с дополнительным условием (в секции ГДЕ). Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь. Такое соединение называется внутренним .
Есть ещё один вариант написания того же самого внутреннего соединения :
Сравните этот и предыдущий запрос. Они совершенно одинаковы с точки зрения платформы, просто имеют разный синтаксис. И этот и предыдущий запросы содержат внутреннее соединение таблицы Клиенты с таблицей Ассоциации по полям ЛюбимыйЦвет и Цвет соответственно.
Левое внешнее соединение
Обратите внимание на то, что в результат внутреннего соединения не попал Андрей. А всё потому, что его любимый цвет красный, а красных ассоциаций у нас в базе нет вовсе.
Получается, что для Андрея с его красным цветом просто не нашлось пары из таблицы ассоциаций.
Перепишем запрос так, чтобы в результат попадали в том числе те записи из первой таблицы, для которых не нашлось ни одной пары из второй таблицы (в данном случае Андрей):
Такое соединение называется левым внешним соединением (слово внешнее можно опускать для простоты).
Р езультат левого внешнего соединения представляет из себя: все записи из внутреннего соединения ПЛЮС все записи из первой таблицы , не попавшие во внутреннее соединение (для которых не нашлось пары).
Правое внешнее соединение
Но давайте снова вернёмся к внутреннему соединению:
Обратите внимание на то, что результат внутреннего соединения не содержит ассоциацию белый снег, так как не нашлось ни одного клиента, у которого любимым цветом был бы белый.
Перепишем запрос так, чтобы в результат попадали в том числе те записи из второй таблицы, для которых не нашлась ни одной пары из первой таблицы (в данном случае белый снег):
Такое соединение называется правым внешним соединением (слово внешнее можно опускать для простоты).
Результат правого внешнего соединения представляет из себя: все записи из внутреннего соединения ПЛЮС все записи из второй таблицы , не попавшие во внутреннее соединение (для которых не нашлось пары).
Полное соединение
А что если нам нужно, чтобы в результат запроса попадали помимо внутреннего соединения Андрей и Снег одновременно?
Для этого потребуется совместить результаты левого и правого соединений. Такой вид соединения уже придуман и называется полным соединением:
Результат полного соединения представляет из себя: все записи из внутреннего соединения ПЛЮС все записи из первой таблицы, не попавшие во внутреннее соединение (для которых не нашлось пары) ПЛЮС все записи из второй таблицы, не попавшие во внутреннее соединение (для которых не нашлось пары).
Псевдонимы таблиц
Согласитесь, что все запросы, которые мы писали в этом уроке выглядят довольно громоздко. Это связано с тем, что мы вынуждены указывать полные имена полей, чтобы избежать возникновение неоднозначности.
Чтобы сократить полное написание имени таблицы (например, Справочник.Клиенты) допустимо (как и для самих полей) использовать псевдонимы .
Давайте перепишем последний запрос так, чтобы при формировании полных имён полей вместо Справочник.Клиенты можно было использовать псевдоним К, а вместо Справочник.Ассоциации - псевдоним А:
А чтобы результат запроса был ещё нагляднее добавим псевдонимы полей, которые мы уже рассматривали на одном из прошлых уроков:
Обработка NULL
Присмотритесь к результатам последнего запроса (как впрочем и многих предыдущих на этом уроке).
Чему равны значения полей Ассоциация и ЕёЦвет для первой строчки? А что вы скажете насчет полей Клиент и ЕгоЦвет для последней строки?
Они равны NULL, которое как мы уже знаем означает отсутствие какого либо значения:
А так как NULL означает отсутствие значения, то любая попытка выполнить с ним какую-либо операцию (сравнение, сложение . ) вызовет неопределенное поведение базы данных, непредсказуемую ошибку.
Поэтому обязательной считается обработка значений NULL всегда, когда они могут возникнуть.
Под обработкой подразумевается то, что мы должны сказать в нашем запросе, что если одно из полей будет равно NULL, то в это поле следует подставить какое-то другое значение.
В данном случае для полей Клиент и Ассоциация в случае обнаружения NULL мы будем подставлять пустую строку "".
А вот поля ЕгоЦвет и ЕёЦвет являются ссылками на элементы справочника Цвета, поэтому в них можно подставлять только значения являющиеся ссылками указанных типов. Каждый ссылочный тип (например, Справочник или Документ) имеет предопределенный элемент ПустаяСсылка. Чтобы указать его значение в запросе воспользуемся функцией ЗНАЧЕНИЕ.
Для определения того, что в поле попало NULL будем использовать уже знакомую нам по прошлым урокам функцию ЕСТЬNULL:
С виду (из консоли запросов) результат не изменился. Мы по-прежнему видим пустые поля. Но это только потому, что строковые представления у NULL и у пустых полей всех типов совпадают и равны пустой строке.
На самом же деле эти пустые поля уже не есть NULL (отсутствие значения), теперь в них появились значения (пустые), с которыми уже можно работать (совершать операции).
Запомните пустое значение и отсутствие значение - это две большие разницы.
Соединение более двух таблиц
Можно последовательно соединять сколько угодно таблиц.
Предположим нужно решить следующую задачу. Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь. Вывести все возможные варианты клиентов и их любимых ассоциаций и их любимых продуктов исходя из их любимого цвета.
Для этого последовательно соединим по цвету таблицу Клиенты с таблицей Ассоциации, а затем (получившийся результат) с таблицей Еда:
Читайте также: