Профессия — 1С

Рукопашный бой Карташ

Категории

Соединение таблиц в запросах 1С

рубрики: Запросы | Дата: 31 Январь, 2016

В предыдущей статье был рассмотрен вопрос чем отличается соединение таблиц от объединения. А сейчас рассмотрим подробнее соединение таблиц.




Напомню, что видов соединений в языке запросов 1С8 может быть несколько, а именно: ЛЕВОЕ СОЕДИНЕНИЕ, ПРАВОЕ СОЕДИНЕНИЕ, ВНУТРЕННЕЕ СОЕДИНЕНИЕ, ПОЛНОЕ СОЕДИНЕНИЕ. Рассмотрим каждое из них подробно.

  • ЛЕВОЕ СОЕДИНЕНИЕ

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

    КодТовара Наименование
    001 Яблоки
    002 Апельсины
    003 Мандарины

    Сформируем эту таблицу в консоли запросов 1С с помощью вот такого запроса:

    
    ВЫБРАТЬ
    	"001" КАК КодТовара,
    	"Яблоки" КАК Наименование
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"002",
    	"Апельсины"
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"003",
    	"Мандарины"
    

    А еще есть таблица «Страны» вот такого вида:

    КодТовара Страна
    001 Россия
    002 Турция
    003 Марокко

    Также сконструируем ее запросом:

    
    ВЫБРАТЬ
    	"001" КАК КодТовара,
    	"Россия" КАК Страна
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"002",
    	"Турция"
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"003",
    	"Марокко"
    

    А теперь соединим эти две таблицы с помощью левого соединения, чтобы получить одну, в которой будет и код товара, и наименование, и страна. Для этого поместим наши таблицы во временные и в пакетном запросе выполним левое соединение.




    Записи будем связывать конечно же по полям КодТовара

    
    ВЫБРАТЬ
    	"001" КАК КодТовара,
    	"Яблоки" КАК Наименование
    ПОМЕСТИТЬ ВТ_Товар
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"002",
    	"Апельсины"
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"003",
    	"Мандарины"
    ;
    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
    	"001" КАК КодТовара,
    	"Россия" КАК Страна
    ПОМЕСТИТЬ ВТ_Страна
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"002",
    	"Турция"
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"003",
    	"Марокко"
    ;
    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
    	ВТ_Товар.КодТовара,
    	ВТ_Товар.Наименование,
    	ВТ_Страна.Страна
    ИЗ
    	ВТ_Товар КАК ВТ_Товар
    		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Страна КАК ВТ_Страна
    		ПО ВТ_Товар.КодТовара = ВТ_Страна.КодТовара
    

    Можете скопировать этот код в консоль запросов и выполнив его получите вот такой результат:

    КодТовара Наименование Страна
    001 Яблоки Россия
    002 Апельсины Турция
    003 Мандарины Марокко

    Здесь мы рассмотрели идеальную ситуацию, когда каждой записи в левой таблице соответствует одна запись в правой. Давайте немного усложним.




    Допустим для нашего товара у нас есть еще цены. Причем они могут меняться в зависимости от даты:

    КодТовара Дата Цена
    001 01.01.2016 120
    001 01.02.2016 150
    002 01.01.2016 200
    004 01.01.2016 350

    Здесь мы видим, что для товара с кодом 001 (Яблоки) у нас 2 записи в таблице цен. Для мандаринов цена отсутствует. И кроме того в ценах есть код товара 004, которого нет в таблице с товарами. Давайте выполним левое соединение для товаров и цен с условием связи по полю код и посмотрим, что у нас получится.

    
    ВЫБРАТЬ
    	"001" КАК КодТовара,
    	"Яблоки" КАК Наименование
    ПОМЕСТИТЬ ВТ_Товар
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"002",
    	"Апельсины"
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"003",
    	"Мандарины"
    ;
    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
    	"001" КАК КодТовара,
    	"01.01.2016" КАК Дата,
    	120 КАК Цена
    ПОМЕСТИТЬ ВТ_Цена
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"001",
    	"01.02.2016",
    	150
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"002",
    	"01.01.2016",
    	200
    
    ОБЪЕДИНИТЬ ВСЕ
    ВЫБРАТЬ
    	"004",
    	"01.01.2016",
    	350
    ;
    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
    	ВТ_Товар.КодТовара,
    	ВТ_Товар.Наименование,
    	ВТ_Цена.Цена,
    	ВТ_Цена.Дата
    ИЗ
    	ВТ_Товар КАК ВТ_Товар
    		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Цена КАК ВТ_Цена
    		ПО ВТ_Товар.КодТовара = ВТ_Цена.КодТовара
    

    После выполнения запроса видим вот такую картину:

    КодТовара Наименование Цена Дата
    001 Яблоки 120 01.01.2016
    001 Яблоки 150 01.02.2016
    002 Апельсины 200 01.01.2016
    003 Мандарины NULL NULL

    Проанализируем полученный результат. Из таблицы «Товары» были выбраны все записи, т.к. она у нас основная. Для мандаринов цена имеет значение NULL, т.к. записи с кодом 003 нет в таблице с ценами. А запись с кодом 004 из таблицы цен (а она у нас вспомогательная) была проигнорирована, т.к. для нее нет соответствия в таблице товаров. И как мы видим у нас появилось 2 записи с яблоками несмотря на то, что в таблице товаров запись с кодом 001 одна. В этом и заключается некоторое коварство соединений таблиц.




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

  • ПРАВОЕ СОЕДИНЕНИЕ

    Оно практически ничем не отличается от левого. В итоговую таблицу попадают все записи из правой таблицы, а из левой только те, для которых выполняется условие соединения. На практике правое соединение практически не используется и рассматривать его отдельно не будем. Есть даже небольшой забавный момент, связанный с правым соединением в конструкторе запросов 1С. Если при составлении запроса в конструкторе попытаться использовать правое соединение, то после нажатия кнопки ОК правое соединение будет автоматически преобразовано в левое.

  • ВНУТРЕННЕЕ СОЕДИНЕНИЕ

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

    
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Цена КАК ВТ_Цена
    

    на

    
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Цена КАК ВТ_Цена
    

    то в итоге получим:

    КодТовара Наименование Цена Дата
    001 Яблоки 120 01.01.2016
    001 Яблоки 150 01.02.2016
    002 Апельсины 200 01.01.2016

    То есть запись с мандаринами у нас исчезла, т.к. для нее не нашлось соответствия в таблице с ценами.

  • ПОЛНОЕ СОЕДИНЕНИЕ

    В случае полного соединения в итоговую таблицу попадут все записи из обоих таблиц.
    В нашем случае при использовании строки соединения

    
    ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Цена КАК ВТ_Цена
    

    получим следующий результат

    КодТовара Наименование Цена Дата
    001 Яблоки 120 01.01.2016
    001 Яблоки 150 01.02.2016
    002 Апельсины 200 01.01.2016
    003 Мандарины NULL NULL
    NULL NULL 350 01.01.2016

    На практике полное соединение используется достаточно редко, но иногда бывает необходимо.

Для тех кто только начинает работать с запросами 1С8 советую посмотреть как разные виды соединений отображаются в конструкторе запросов на закладке «Связи».

Один комментарий на «“Соединение таблиц в запросах 1С”»

  1. ScottBof:

    Спасибо за публикацию, очень правильно все написано!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

   

2018г. Профессия — 1С. Обмен опытом по программированию в 1С