рубрики: Запросы | Дата: 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 советую посмотреть как разные виды соединений отображаются в конструкторе запросов на закладке «Связи».
Спасибо за публикацию, очень правильно все написано!