Как с помощью языка запросов 1С получить множество значений, состоящее из значений текущего множества, за исключением подмножества, принадлежащего другому множеству.
См. рис. По условию задачи требуется получить значения, попадающие в синюю область значений множества «А» и не попадающие в заштрихованную фиолетовую область значений подмножества «С»
Решить задачу можно разными способами. Самый простой (и, пожалуй, оптимальный) — ограничить выборку правильным условием «ГДЕ», т.е. в условии «ГДЕ» сформировать таблицу исключаемых значений и использовать при этом конструкцию «НЕ В».
Т.е. решение будет таким:
"ВЫБРАТЬ | ТаблицаА.ИзмерениеА |ИЗ | РегистрСведений.ТаблицаА КАК ТаблицаА |ГДЕ | (НЕ ТаблицаА.ИзмерениеА В | (ВЫБРАТЬ | ТаблицаА.ИзмерениеА | ИЗ | РегистрСведений.ТаблицаА КАК ТаблицаА ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ТаблицаВ КАК ТаблицаВ | ПО | ТаблицаА.ИзмерениеА = ТаблицаВ.ИзмерениеВ))"
Теперь решим эту задачу с использованием временных таблиц.
Это решение кому-то быть может покажется более понятным, оно тоже верное, но, надо заметить, более ресурсоемкое. Вот оно.
Для решения запросом получаем значения, попадающие в фиолетовую область «С», параллельно добавляя к каждой строке результата некое поле, по значению которого затем исключаем элементы из таблицы «А».
Поясним подробнее.
1. Итак, вот запрос для получения подмножества «С» с одновременным присоединением поля, по которому будем исключать (обведено на рисунке ниже красным цветом):
2. Поместим этот запрос во временную таблицу втПодмножествоС
3. Присоединим к множеству А значение «Исключить» подможества «С» и поместим результат во временную таблицу втПодмножествоА:
4. Осталось получить значения, в строках которых поле «ИсключитьИзА» ЕСТЬ NULL:
Теперь немного усложним задачу. Допустим, требуется исключить подмножество С по совпадению не одного, а сразу нескольких значений.
Т.е., допустим, имеются две исходные таблицы:
Нужно получить строки Таблицы А, в которых нет строк, полностью совпадающих со строками Таблицы В (совпадающие строки обведены красным цветом)
Решение приведем, снова используя условие «ГДЕ»:
"ВЫБРАТЬ | ТаблицаА.ИзмерениеА, | ТаблицаА.РеквизитА |ИЗ | РегистрСведений.ТаблицаА КАК ТаблицаА |ГДЕ | (НЕ (ТаблицаА.ИзмерениеА, ТаблицаА.РеквизитА) В | (ВЫБРАТЬ | ТаблицаА.ИзмерениеА, | ТаблицаА.РеквизитА | ИЗ | РегистрСведений.ТаблицаА КАК ТаблицаА ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ТаблицаВ КАК ТаблицаВ | ПО | ТаблицаА.ИзмерениеА = ТаблицаВ.ИзмерениеВ | И ТаблицаА.РеквизитА = ТаблицаВ.РеквизитВ))"
Результатом этого запроса будет искомая табличка:
Материал безусловно полезен, т.к. до этого я долго ломал голову над этой задачей и придумал третий способ еще более ресурсоемкий. Заключался в следующем: поместить в виртуальную таблицу результат сравнения, добавить колонку вместо NULL числа как строку «666». Далее по ним сделать выборку, т.к. выяснилось, что предложение «Выбрать * из ВремТаб ГДЕ ВремТаб.поле1 = NULL» (в любых вариациях не работает). Такое свойство SQL сервера (или языка уже не помню, что нашел в справке) что-то вроде NULL не NULL и сравнивать их нельзя (?).
Далее, просто хотел разобраться с работой менеджера виртуальных таблиц. Также пришел к выводу, что работа с пакетным запросом в режиме конструктора гораздо эффективнее. Получение виртуальных таблиц в отдельных запросах эффективна только для хранения в ОЗУ таблиц из внешних источников данных (была задача чтения из dbf информации по контрагентам и дальнейшая ее подгрузка в справочник 1С 8). На первое место всегда встает задача сделать лиш бы работало. Дальнейшая оптимизация (по моему опыту) проводится либо другими людьми, либо при дальнейшем сопровождении системы.
Тем не менее, виртуальные таблицы довольно мощная вещь для обеспечения наглядности, т.к. в первую очередь необходима наглядность при разработке и скорейшей отладке.
Константин, спасибо за интересный комментарий. И да, Вы правы, действительно, при внедрении до оптимизации руки обычно доходят только при последующих «прочтениях» кода, а поначалу на первом месте — быстрее сделать. И даже не потому, что кодеру «лень подумать», а потому, что чаще всего клиенту некогда ждать.
Кстати, про наглядность виртуальных таблиц, позвольте порекомендовать статью http://www.1c-h.ru/?p=1332 — обратите внимание на функцию «ДанныеЗапроса», бывает очень полезна.
Спасибо, я рад, что Вы также подсказали как и чем правильнее работать с виртуальными таблицами. На первое место тут выходит уже сама возможность смотреть промежуточные результаты.
Спасибо, очень во время нашла Вашу статью. Исключением данных по одному полю пользовалась не раз, а по группе полей алгоритм не был для меня очевиден. в итоге полдня «проиграла» с методом научного тыка. 🙂
Статья про наглядность виртуальных таблиц также была интересна, тк до этого я пользовалась пакетными запросами: в последний запрос добавляла интересующую меня таблицу и просматривала результат в отладчике. Достаточно неудобно.
Александра, спасибо за отзыв. Приятно, что пригодилось!
Отличный пример. Спасибо.
Супер!!!
Спасибо!!!
Очень помогло!!!
Прекрасный материал! Все очень просто и доступно! Спасибо!!
Картинки не отображаются 🙂
А материал актуален и полезен. 🙂
Спасибо, картинки постараюсь вскоре добавить. После обновления все слетели, руки не доходят.