6
January
2006

Операторы Inner Join и Outer (left, right, full) Join в SQL (Oracle)

Posted in: Базы данных, SQL, Oracle |

Ключевое слово join в SQL используется при построении select выражений. ?нструкция Join позволяет объединить колонки из нескольких таблиц в одну. Объединение происходит временное и целостность таблиц не нару?ается. Существует три типа join-выражений:

  • inner join;
  • outer join;
  • cross join;

В свою очередь, outer join может быть left, right и full (слово outer обычно опускается).
В качестве примера (DBMS Oracle) создадим две простые таблицы и сконструируем для них SQL-выражения с использованием join.

В первой таблице будет хранится ID пользователя и его nick-name, а во второй - ID ресурса, имя ресурса и ID пользователя, который может этот ресурс администрировать.

create table t_users (
t_id number(11, 0),
t_nick varchar(16),
primary key (t_id) )

create table t_resources (
t_id number(11, 0),
t_name varchar(16),
t_userid number (11, 0),
primary key (t_id) )

Содержимое таблиц пусть будет таким:

T_ID  T_NICK
  1    user1
  3    user3
  4    user4 

T_ID  T_NAME  T_USERID
  1    res1     3
  2    res2     1
  3    res3     2
  5    res5     3

Конструкция join выглядит так:

... join_type join table_name on condition …

Где join_type - тип join-выражения, table_name - имя таблицы, которая присоединяется к результату, condition - условие объединения таблиц.
Кострукция join располагается сразу после select-выражения. Можно использовать несколько таких конструкций подряд для объединения соответствующего кол-ва таблиц. Логичнее всего использовать join в том случае, когда таблица имеет вне?ний ключ (foreign key).
Inner join необходим для получения только тех строк, для которых существует соответствие записей главной таблицы и присоединяемой. ?ными словами условие condition должно выполняться всегда. Пример:

select t_resources.t_name, t_users.t_nick
  from t_resources
  inner join t_users on t_users.t_id = t_resources.t_userid

Результат будет таким:

 T_NAME  T_NICK
  res2    user1
  res1    user3
  res5    user3

В случае с left join из главной таблицы будут выбраны все записи, даже если в присоединяемой таблице нет совпадений, то есть условие condition не учитывает присоединяемую (правую) таблицу. Пример:

select t_resources.t_name, t_users.t_nick
  from t_resources
  left join t_users on t_users.t_id = t_resources.t_userid

Результат выполнения запроса:

 T_NAME  T_NICK
  res1    user3
  res2    user1
  res3    (null)
  res5    user3

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

Right join отображает все строки удовлетворяющие правой части условия condition, даже если они не имеют соответствия в главной (левой) таблице:

select t_resources.t_name, t_users.t_nick
  from t_resources
  right join t_users on t_users.t_id = t_resources.t_userid

А результат будет следующим:

 T_NAME  T_NICK
  res2    user1
  res1    user3
  res5    user3
  (null)  user4

Результирующая таблица показывает ресурсы и их администраторов. Если адмнистратор не задействован, эта запись тоже будет отображена. Такое может случиться, например, если ресурс был удален.

Updated (8.03.2007):
Full outer join (ключевое слово outer можно опустить) необходим для отображения всех возможных комбинаций строк из нескольких таблиц. ?ными словами, это объединение результатов left и right join.

select t_resources.t_name, t_users.t_nick
  from t_resources
  full join t_users on t_users.t_id = t_resources.t_userid

А результат будет таким:

 T_NAME  T_NICK
  res1      user3
  res2      user1
  res3      (null)
  res5      user3
 (null)     user4

Некоторые СУБД не поддерживают такую функциональность (например, MySQL), в таких случаях обычно используют объединение двух запросов:

select t_resources.t_name, t_users.t_nick
  from t_resources
  left join t_users on t_users.t_id = t_resources.t_userid
union
select t_resources.t_name, t_users.t_nick
  from t_resources
  right join t_users on t_users.t_id = t_resources.t_userid

Наконец, cross join. Этот тип join еще называют декартовым произведением (на английском - cartesian product). Настоятельно рекомендую использовать его с умом, так как время выполнения запроса с увеличением числа таблиц и строк в них растет по экспоненте.
Вот пример запроса, который аналогичен cross join:

select t_resources.t_name, t_users.t_nick
  from t_resources, t_users

Конструкция Join (в сочетании с другими SQL конструкциями, например, group by) часто встречается при программировании под базы данных. Думаю, эта статья будет вам полезна. Кстати, для проверки своих знаний в области баз данных (и в частности Oracle) рекомендую воспользоваться этим сайтом онлайн тестирования - Тесты по базам данных.

98 Comments »

RSS feed for comments on this post. TrackBack URI



wert2all
January 6, 2006 #

думаю будет полезна.. но мало рассказано.. так всё быстро… а вот как написать запрос, что бы выводились те записи с первой таблицы. которых нет во второй? ;) это тоже следует написать

January 6, 2006 #

В статье описано, как и для чего можно использовать конструкцию join. Естественно, для определенных задач и для сложных баз данных запросы будут сложнее: со вложенными запросами, с конструкциями where, group by, c ключевыми сдовами типа distinct и так далее…

Alexander
April 8, 2006 #

Как раз то, что нужно - сейчас 3 часа ночи и вот появилось легкое непонимание разниц INNER и LEFT/
(Тут еще OUTER JOINT проскакивает - буду разбираться еще).
Вы помогли _быстро_ разобраться :)

Спасибо!

StacK515
September 3, 2006 #

Отлично! Как в хоро?ем справочнике: коротко и ясно. Спасибо!

CMP
September 6, 2006 #

Очень хоро?ая статья. Все четко и понятно. Молодцы.

River
November 16, 2006 #

Хоро?ая статья, помогла. Кратко и ясно. То, что нужно было для начала ;).

Rustam
November 23, 2006 #

Понятно но сли?ком уж кратко. Хотя бы ссылку на более подробную статью чтоли. Но все равно спасибо. Главное дано сравнение всех JOIN. Но не понятно что делать если объединяется одна и та же таблица под разными именами

Gribass
December 27, 2006 #

Статья действительно хоро?а. Спасибо.

ikota
February 8, 2007 #

Огромное спасибо, отличная статья. Моментально стало всё ясно.

April 9, 2007 #

? я благодарность наверное выпи?у за статейку :)

andrey
April 16, 2007 #

Спасибо. Как раз по лабе, которую щас буду делать :)

Boris
August 16, 2007 #

Хоро?ая статья. Мне на собеседовании вопрос про outer join задавали, а я толком ничего сказать не смог. Теперь вроде бы все ясно, спасибо!

Stan
August 17, 2007 #

Да статья действительно получилось хоро?ая. Она не вдаваясь в детали объясняет суть! А за подробностями можно не полениться и залезть в мануал СУБД

August 28, 2007 #

Ещё стоило бы упомянуть, что в Oracle, по крайней мере в 9i, есть определённые проблемы с ANSI-?ным синтаксисом join-ов. Хотя в документации и советуется его использовать взамен оракловых (+).
Поэтому пользоваться ANSI-синтаксисом следует с осторожностью (особенно full).
Подробности можно посмотреть на Металинке.

Alexxz
August 29, 2007 #

Хоро?ая статейка, мне понравилось. Коротко, ясно, а главное доступно… Без засирания мозга полным синтакиссом опреаторов и прочего. Очень наглядно продемонстрировано. Сам работаю с MySQL, однако было очень интересно прочитать. Спасибо.

Intruder
October 30, 2007 #

Всё хоро?о, корме одного:

В Oracle нет операции JOIN. Вне?ние соединения обеспечиваются в Oracle оператором (+) в эквисоединении.

Livon
November 7, 2007 #

Хоро?ая статья. Спасибо за простое изложение информации.
Неплохо было бы добавить чуть-чуть инфы о том когда следует пользоваться join.

StyleX
November 11, 2007 #

Боль?ое спасибо, инфа полезная! Как раз сдавать лабы по бд!

Aleksey
December 2, 2007 #

Боль?ое спасибо за такую понятную статью. очень доступно всё описано.

mishag
December 2, 2007 #

А что делает такой select:
Select …
from table1 left join table2 right join table3
on (join condition table2 - table3)
on (join condition table1 - table2)

Какие колонки должны попасть в результат?

anonymous
January 17, 2008 #

? мне статья понравилась: просто и понятно. Спасибо

Trinity
January 25, 2008 #

Great Thanks to you!

From Ubonratchathani University
will try to explain it to the students!

Vladimir
January 30, 2008 #

Спасибо, коротко и доступно о нужном )

hifishka
February 26, 2008 #

Боль?ое спасибо, очень полезная стать!

Aleksey
March 1, 2008 #

Класс….. +1

devochko
April 3, 2008 #

>>>а вот как написать запрос, что бы выводились те записи с первой таблицы. которых нет во второй?

select t_resources.t_name, t_users.t_nick
from t_resources
left join t_users
where t_users.t_nick is null
;)
а я рань?е работала с mssql, на новой работе оракл, и почему-то запросы с джоинами не выполняются, даже простей?ие, типа select t1.p1,t2.p2 from t1 left join t2 on t1.p1=t2.p2 не могу понять, в оракле другой синтаксис или вообще нет оператора join?:(

devochko
April 3, 2008 #

всем спасибо, я уже на?ла)))) это будет так:
select t1.p1,t2.p2 from t1, t2 where t1.p1=t2.p2 (+) = left join
select t1.p1,t2.p2 from t1, t2 where t1.p1(+)=t2.p2 = right join

Chuvak
April 7, 2008 #

Очень неплохая статья.

Anna
April 7, 2008 #

Спасибки, статейка полезная ))

LexSTV
April 13, 2008 #

мда, я ничего не имею против деву?ек it, но я хотел узнать, как правильно искользовать джойны, и заглянул сюда. Первый же пример вызвал у меня сомнения… Создал все в точности в оракловой базе, и в певом запросе выдет 4 записи, а не 3, как показано тут. Следовательно объяснения про inner join уже не верны, даль?е читать расхотелось…

April 18, 2008 #

Может мы о разных Ораклах говорим?

ONIX
April 18, 2008 #

Спасибо! самая суть…четко , коротко и понятно!!

belchonock
April 23, 2008 #

Спасибо, я наконец поняла как полозоваться джоином :)))

zuko
May 2, 2008 #

Целый день “гуглил” инет, искал “а вот как написать запрос, что бы выводились те записи с первой таблицы. которых нет во второй?”, где-то к обеду узнал, что мне нужен JOIN и только к полуночи инет все таки раскрыл ТАЙНУ кто такой JOIN. Огромное спасибо ва?ей статье!!!

Дима
May 11, 2008 #

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

mart
May 22, 2008 #

2Дима:
То что проще, не обязательно быстрее.

Автору спасибо

mishag
May 26, 2008 #

Minus вместо Union выводит то из первой таблицы, чего нет во второй.

san
June 20, 2008 #

Мне вот интересно сравнить скорость двух запросов возвращающих одинаковые данные но использующие inner join и left join
?

h
July 3, 2008 #

?нтересно-сравни.

PavelK
July 4, 2008 #

в оракле поддержка join-ов появилась с 9-й версии, если мне память не изменяет.

July 9, 2008 #

LexSTV - ты видимо что-то не так делал. Я создал таблицы в точности с приведенными примерами, проверил все опубликованные запросы в MySQL, и убедился в их правильности - все результаты абсолютно сообтветствовали с опубликованными примерами.
Возможно Oracle интерпритирует данные запросы по другим правилам, в результате чего результат отличаеться, но скорее всего ты НЕ буквально воссоздал картину, показанную на примере вы?е. Поэтому “захоти” и почитай статью внимательнее, может что-то полезное для себя узнае?ь.

Автору спасибо!

alex
July 15, 2008 #

Да, статейка действительно доходчивая - доза теории и двойная доза практики :)

Спасибо.

SindBAD
July 17, 2008 #

Классно :) саое понятное из всех объяснений принципа работы JOIN, которое мне попадалось! Благодарю!

Надин
August 13, 2008 #

Оч хоро?ая статья!
Автору респект!
Ждем новых статей =)

ellokko
August 14, 2008 #

Спасибо! Очень помогло!

XeNt
August 20, 2008 #

Кратко и понятно!

Lavr
September 5, 2008 #

“wert2all January 6, 2006 # … а вот как написать запрос, что бы выводились те записи с первой таблицы. которых нет во второй? это тоже следует написать”

For you:

select t_resources.t_name, t_users.t_nick
from t_resources
right join t_users on t_users.t_id = t_resources.t_userid
where t_resources.t_name is null

А результат будет следующим:

T_NAME T_NICK
(null) user4

September 11, 2008 #

Спасибо. Теперь стало понятнее, чем именно отличаются все эти LEFT, RIGHT JOIN и т.д.

хорек
September 19, 2008 #

спасибо, статья помогла все быстро выяснить

Диня
November 12, 2008 #

Отличная статья! Все четко и по сути!

jocker1331
November 19, 2008 #

———-
Наконец, cross join. Этот тип join еще называют декартовым произведением (на английском - cartesian product). Настоятельно рекомендую использовать его с умом, так как время выполнения запроса с увеличением числа таблиц и рядков в них растет по экспоненте.
———-
может стоит открыть учебник алгебры и изучить что такое экспонента?

T
November 21, 2008 #

Спасибо. Полезная статья.

Pascal
December 1, 2008 #

спс!

Anna
December 10, 2008 #

LexSTV April 13, 2008 # мда, я ничего не имею против деву?ек it, но я хотел узнать, как правильно искользовать джойны, и заглянул сюда. Первый же пример вызвал у меня сомнения… Создал все в точности в оракловой базе, и в певом запросе выдет 4 записи, а не 3, как показано тут. Следовательно объяснения про inner join уже не верны, даль?е читать расхотелось…

Я думаю автор статьи - Константин - обидится за то, что его обозвали “деву?кой it”
а то, что ты первым делом обратил внимание на пол автора, говорит о том, что ты “ничего не имее?ь против деву?ек (it), но они все поголовно дуры”. Думаю, предвзятость идет из внутренних комплексов и проблем в личном общении

#может стоит открыть учебник алгебры и изучить что такое экспонента?
стоит. изучи.

Автору спасибо за статью!

Nizamovich
December 23, 2008 #

jocker1331…тут уже тебе ре?ать, открывать алгебру или нет…

статья очень полезна, спасибо!!!

vit
February 2, 2009 #

автору респект и уважуха

Sergey
February 11, 2009 #

ЗАДАЧА
1. Таблица GROUP (содержит значения Группа1, Группа2, Группа3)
2. Таблица STUDENT (содержит значения Петров, ?ванов, Сидоров в привязке к Группе1)
3. Таблица BALL (содержит итоговый балл: по Петрову - 82, по ?ванову - 69, по Сидорову - NULL)
НАДО вывести Группу1, всех студентов этой группы и ?тоговый балл, даже если он еще не назначен.

РЕШЕН?Е:
SELECT group.name, student.name, ball.score
from ball
RIGHT JOIN (student RIGHT JOIN group ON group.id = student.id )
ON student.id = ball.id
WHERE group.name = ‘Группа1′

March 12, 2009 #

JOIN прикольная тема

а описано все как нужно. конкретно и без слюней :)

Egor
April 9, 2009 #

2 Sergey

В скобках надо использовать LEFT JOIN.
?наче будет работать неправильно, если для студента не будет указана группа (или будет указана группа, отсутствующая в таблице GROUP):

SELECT group.name, student.name, ball.score
from ball
RIGHT JOIN (student LEFT JOIN group ON group.id = student.id )
ON student.id = ball.id
WHERE group.name = ‘Группа1′

Nuke
April 10, 2009 #

А кто знает, как сделать, чтобы вместо (null) в DataGrid выводился, например, пробел?

Luda
April 24, 2009 #

Отличная статья, спасибо!

Painerman
May 12, 2009 #

Спасибо!
А не подскажите, каким способом эти таблицы тупо склеить в одну, при условии уникальности ID и совпадения названий полей чтобы делать выборку уже оттуда?
T_ID T_NICK
1 user1
3 user3
4 user4
6 res1
7 res2
8 res3
5 res5

SELECT `T_ID` FROM t_users+t_resources WHERE `T_NICK`=’res5′

??? Спасибо!

SHAMo
May 21, 2009 #

Хоро?ая статья… давно хотел разобраться с этими “джоинами” ;)
Спасибо!

alsodeep
May 24, 2009 #

Спасибо, помогло быстро разобраться.

urihivoo
June 5, 2009 #

Честно говоря пытаясь на собственных таблицах создать select с join’ом сначала запутался, но потом разобрался почему:
потому что в самом начале статьи я бы переписал:

Конструкция join выглядит так:

… join_type join table_name on condition …”
на:

Конструкция join выглядит так:

…table1_name join_type join table2_name on condition …”

? вот уже отсюда, по-моему, чуть яснее, кто есть правая, а кто левая таблицы.
А вообще - спасибо за статью :)

tvv1
June 11, 2009 #

полностью все 100% описано понятно и ясно сходу.
теория + примеры.
спс.

ap
June 17, 2009 #

Нормальная статья, только слово “рядки” насме?ило сильно. Правильно “ряды”, конечно.

krasovcheg
June 23, 2009 #

Спасибо за статью, ре?ил просто освежить знания и наткнулся на вас.

Кайрат Юсупов
June 24, 2009 #

Немного запутано про левые и правые таблицы.
В целом все понятно. Спасибо.

June 27, 2009 #

2 ap: спасибо, исправил. Это я с украинским языком спутал

rus92
August 13, 2009 #

А кто знает, как сделать, чтобы вместо (null) в DataGrid выводился, например, пробел?

nvl(,)

выглядит так
select nvl(a.name,’нет имени’) from students a

хммм
September 10, 2009 #

Если добавить пару картинок, как например тут То по моему будет более наглядно.

А так всё мило :)

Юрий
September 18, 2009 #

Отличная статья! Спасибо очень быстро разобрался с Full Join. Как раз то что нужно было!

MaryG
November 25, 2009 #

wert2all как раз LEFT JOIN и отвечает на Ва? вопрос: все записи с первой таблицы

sergey_mp
December 1, 2009 #

не вижу смысла вообще использовать inner join
использую Oracle SQL 10 лет и мне удобнее
и нагляднее написать (особенно если много полей
в условии where)
select t_resources.t_name, t_users.t_nick
from t_resources, t_users
where t_users.t_id = t_resources.t_userid

чем

select t_resources.t_name, t_users.t_nick
from t_resources
inner join t_users on t_users.t_id = t_resources.t_userid
Спра?иваю у программиста на новой работе- почему ты используе?ь inner join вместо простого сравнения полей , отвечает меня так научили

December 2, 2009 #

Хоро?ая статья, вот только искал описание по NATURAL JOIN, я себе представляю как работает, но хотелось бы точно)
Пример:
SELECT E.employee_id, E.last_name, department_id, D.department_name
FROM employees E
NATURAL JOIN
departments D
WHERE department_id = 30;

Если я правильно понял, то идет пересение по ключам (priary и foreign key))

ЧайникПолный
December 15, 2009 #

Спасибо, прекрасная статья.

Vitalik
January 5, 2010 #

Наконец то я понял, как работают разные Join … спасибо за краткое и понятное обьяснение

Programator
January 19, 2010 #

Работаю с PL/SQL-Developer уже боль?е пол-года, несколько раз пробовал понять этот join, и на этом примере токо уразумел (опробовал, все норм). Спасибо автору.

debuger
February 25, 2010 #

Статейка классная ибо автор воздержался блеснуть умом и доходчиво рассказал по сути!
Спасибо!

Лю?а
February 27, 2010 #

skAmZ,
natural join сочленяет по столбцам с одинаковыми именами (обычно по одному столбцу имена совпадают (в боль?инстве случаев там, где и хоче?ь сочленить), но могут несколько совпасть, тогда по ним сочленяется (ON(Т1.с1=Т2.c1)AND(Т1.с2=Т2.c2)) хотя корректней писать (ON(Т1.с1, Т1.с2)=(Т2.с1, Т2.с2)) )
также вместо ON Т1.с1=Т2.c1 можно писать USING(c1)

July
March 19, 2010 #

Отличная статья помогла разобраться с join. Спасибо !
2 Sergey
Спасибо! Ва? пост помог ре?ить мою задачу, используя вложенные join.

dervish
April 9, 2010 #

to Nuke:
А кто знает, как сделать, чтобы вместо (null) в DataGrid выводился, например, пробел?

COL[UMN]имя_столбца NULL “то, что хоче?ь
вставить вместо NULL”;

Удалить: CLEAR COLUMN

dervish
April 9, 2010 #

также:
SELECT tr.t_name, tu.t_nick
FROM t_resources tr
FULL OUTER JOIN t_users tu
ON tu.t_id = tr.t_userid;

Результат:
T_NAME T_NICK
res2 user1
res5 user3
res1 user3
res3
user4

dervish
April 9, 2010 #

Насчет FULLa - незаметил, sorry.

dervish
April 10, 2010 #

2Rustam:
Но не понятно что делать если объединяется одна и та же таблица под разными именами

SELECT p.t_name, g.t_name
FROM t_resources g, t_resources p
WHERE g.t_id = p.t_userid;

April 13, 2010 #

[…] » Операторы Inner Join и Outer left, right, full Join в SQL Oracle. […]

Prk
May 7, 2010 #

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

jamland
May 9, 2010 #

спасиба!!

staS
June 20, 2010 #

Как обьединить несколько left join в delphi?

June 25, 2010 #

Статья помогла написать
Ялтинский портал

bt
June 28, 2010 #

Блин, спасибо, огромное. А то в поисковике голимые цитаты из официального мануала, где ужасно дуратские примеры :) А так сразу всё встало на свои места.

June 28, 2010 #

Рыспэкт! Разобрался в 2 минуты!

DM
June 30, 2010 #

Жаль в оракле старый синтаксис, ansi join там только начинает приживаться в новых версиях, например в materialized views при автообновлении он неподдерживается, а сам ansi join довольно неплохой оператор, позволяет избежать мусора (ненужных столбцов) в select.
Кстати, вопрос про старый оракловский синтаксис - если связаный подзапрос (во where) имеет join-связь между несколькими таблицами, как тогда построить запрос? Если используем старый синтаксис, то в select должны перечислить все столбцы, а подзапрос во where должен вернуть одно единственное значение, соответственно поверх подзапроса ставим select (count, max, min) одного столбца, но тогда теряется связь с главным запросом, так как в оракле область видимости подзапроса только на 1 уровень вверх. Тупик?
С новым ansi join сделать подобный запрос не составит труда, так как не нужно всю кучу столбцов извлекать в select.

Виталий
July 19, 2010 #

Спасибо огромное ! Ваша статья помогла и выручила ;)

July 23, 2010 #

Норм статья, по ней понял что такое left join

Єс
July 28, 2010 #

Файно розписано. Дзенькую.אַ דאַנק Köszönöm

Артём
August 5, 2010 #

Спасибо за статью! Прекрасные примеры быстро помогли вспомнить не так давно забытое)

Leave a comment

XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong> <pre>