Объяснение самосоединений

Я не понимаю необходимости самообъединений. Может кто-нибудь объяснить их мне?

Простой пример был бы очень полезен.


person Alex Gordon    schedule 16.03.2010    source источник


Ответы (13)


Самообъединение можно рассматривать как две идентичные таблицы. Но при нормализации вы не можете создать две копии таблицы, поэтому вы просто имитируете наличие двух таблиц с самообъединением.

Предположим, у вас есть две таблицы:

Таблица 1_

Id Name Boss_id            
1   ABC   3                   
2   DEF   1                   
3   XYZ   2                   

Таблица emp2

Id Name Boss_id            
1   ABC   3                   
2   DEF   1                   
3   XYZ   2                   

Теперь, если вы хотите получить имя каждого сотрудника с именами его или ее босса:

select c1.Name , c2.Name As Boss
from emp1 c1
    inner join emp2 c2 on c1.Boss_id = c2.Id

Что выведет следующую таблицу:

Name  Boss
ABC   XYZ
DEF   ABC
XYZ   DEF
person pointlesspolitics    schedule 16.03.2010
comment
В этом примере я не могу понять, кто главный. Хотя опыт хороший и понятный. - person Ram; 15.08.2018
comment
left join Я думаю, что было бы лучше не оставлять без внимания сотрудника (или начальника), у которого нет начальника; топ собака! - person Rockin4Life33; 05.09.2018
comment
Должен ли он быть из emp c1 вместо emp1 c1? @pointlesspolitics - person Rohit Singh; 28.12.2020

Это довольно распространено, когда у вас есть таблица, которая ссылается сама на себя. Пример: таблица сотрудников, в которой у каждого сотрудника может быть менеджер, и вы хотите перечислить всех сотрудников и имя их менеджера.

SELECT e.name, m.name
FROM employees e LEFT OUTER JOIN employees m
ON e.manager = m.id
person windyjonas    schedule 16.03.2010

Самосоединение — это соединение таблицы с самой собой.

Общий вариант использования — когда в таблице хранятся объекты (записи), между которыми существует иерархическая связь. Например, таблица, содержащая информацию о человеке (имя, дата рождения, адрес...) и включающая столбец, в который включен идентификатор отца (и/или матери). Затем с небольшим запросом, например

SELECT Child.ID, Child.Name, Child.PhoneNumber, Father.Name, Father.PhoneNumber
FROM myTableOfPersons As Child
LEFT OUTER JOIN  myTableOfPersons As Father ON Child.FatherId = Father.ID
WHERE Child.City = 'Chicago'  -- Or some other condition or none

мы можем получить информацию как о ребенке, так и об отце (и матери, со вторым самостоятельным соединением и т. д., и даже о великих родителях и т. д.) в одном запросе.

person mjv    schedule 16.03.2010

Допустим, у вас есть таблица users, настроенная так:

  • Логин пользователя
  • имя пользователя
  • идентификатор менеджера пользователя

В этой ситуации, если вы хотите получить информацию о пользователе и информацию о менеджере в одном запросе, вы можете сделать следующее:

SELECT users.user_id, users.user_name, managers.user_id AS manager_id, managers.user_name AS manager_name INNER JOIN users AS manager ON users.manager_id=manager.user_id
person ceejayoz    schedule 16.03.2010

Представьте себе таблицу с именем Employee, как описано ниже. У всех сотрудников есть менеджер, который также является сотрудником (возможно, за исключением генерального директора, чей manager_id будет равен нулю)

Table (Employee): 

int id,
varchar name,
int manager_id

Затем вы можете использовать следующий выбор, чтобы найти всех сотрудников и их менеджеров:

select e1.name, e2.name as ManagerName
from Employee e1, Employee e2 where
where e1.manager_id = e2.id
person Klaus Byskov Pedersen    schedule 16.03.2010

Они полезны, если ваша таблица является самореферентной. Например, для таблицы страниц каждая страница может иметь ссылку next и previous. Это будут идентификаторы других страниц в той же таблице. Если в какой-то момент вы захотите получить тройку последовательных страниц, вы должны выполнить два самосоединения в столбцах next и previous со столбцом id той же таблицы.

person Max Shawabkeh    schedule 16.03.2010

Без возможности таблицы ссылаться на себя нам пришлось бы создавать столько таблиц для уровней иерархии, сколько слоев в иерархии. Но поскольку эта функциональность доступна, вы соединяете таблицу с самой собой, и sql обрабатывает ее как две отдельные таблицы, поэтому все удобно хранится в одном месте.

person Eugene    schedule 16.03.2010
comment
но теперь вы (надеюсь) понимаете, что произошло бы, если бы ссылка на себя была недоступна. - person Eugene; 17.03.2010

Помимо ответов, упомянутых выше (которые очень хорошо объяснены), я хотел бы добавить один пример, чтобы можно было легко показать использование Self Join. Предположим, у вас есть таблица CUSTOMERS со следующими атрибутами: CustomerID, CustomerName, ContactName, City, Country. Теперь вы хотите перечислить всех тех, кто из «того же города». Вам придется придумать реплику этой таблицы, чтобы мы могли присоединиться к ним на базе CITY. Следующий запрос ясно покажет, что это значит:

SELECT A.CustomerName AS CustomerName1, B.CustomerName AS CustomerName2, 
A.City
FROM Customers A, Customers B
WHERE A.CustomerID <> B.CustomerID
AND A.City = B.City 
ORDER BY A.City;
person Mazhar MIK    schedule 07.10.2017
comment
+1 Этот ответ очень важен, потому что в SO так много вопросов SQL, на которые ответом является использование самосоединения, которое люди, как правило, не видят, когда у них нет явной (иерархической) ссылки на себя. - person JimmyB; 31.07.2018
comment
Несмотря на то, что это копия пасты из w3schools, я думаю, что приведенный выше ответ объясняет не самосоединение, а внутреннее соединение, которое отличается. - person George K; 24.08.2018

Здесь много правильных ответов, но есть вариант, не менее правильный. Вы можете поместить условия соединения в оператор соединения вместо предложения WHERE.

SELECT e1.emp_id AS 'Emp_ID'
  , e1.emp_name AS 'Emp_Name'
  , e2.emp_id AS 'Manager_ID'
  , e2.emp_name AS 'Manager_Name'
FROM Employee e1 RIGHT JOIN Employee e2 ON e1.emp_id = e2.emp_id

Имейте в виду, что иногда вам нужно e1.manager_id > e2.id

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

Никто не обращался к тому, что происходит, когда у Сотрудника нет менеджера. Хм? Они не включены в набор результатов. Что делать, если вы хотите включить сотрудников, у которых нет менеджеров, но не хотите, чтобы возвращались неправильные комбинации?

Попробуйте этого щенка;

SELECT e1.emp_id AS 'Emp_ID'
   , e1.emp_name AS 'Emp_Name'
   , e2.emp_id AS 'Manager_ID'
   , e2.emp_name AS 'Manager_Name'
FROM Employee e1 LEFT JOIN Employee e2 
   ON e1.emp_id = e2.emp_id
   AND e1.emp_name = e2.emp_name
   AND e1.every_other_matching_column = e2.every_other_matching_column
person BClaydon    schedule 27.03.2013
comment
Хм, щенок, почему ты присоединяешься к большему, а не к равному? - person Marcel; 05.02.2014
comment
Привет. Я видел, что некоторые примеры используют FROM xxx, yyy WHERE, а некоторые другие FROM xxx JOIN yyy WHERE. Не могли бы вы объяснить разницу, пожалуйста? - person skan; 28.08.2014
comment
@Skan Это действительно хороший вопрос. Короткий ответ заключается в том, что это старый сокращенный метод, который будет объявлен устаревшим. Я использовал его в школе десять с лишним лет назад и редко вижу его на практике. Вот самое краткое описание, которое мне удалось найти: bidn.com/blogs/KathiKellenberger/sql-server/2875/ - person BClaydon; 02.09.2014

Одним из вариантов использования является проверка дубликатов записей в базе данных.

SELECT A.Id FROM My_Bookings A, My_Bookings B
WHERE A.Name = B.Name
AND A.Date = B.Date
AND A.Id != B.Id
person Molossus Spondee    schedule 14.02.2017
comment
Гораздо быстрее использовать GROUP BY и предложение HAVING для поиска дубликатов. ВЫБЕРИТЕ имя, адрес электронной почты, COUNT() FROM My_Bookings СГРУППИРОВАТЬ ПО имени, дате HAVING COUNT() › 1 - person George K; 24.08.2018
comment
@GeorgeK Верно. Я предполагаю, что это необходимо только для нечеткого совпадения (помимо группировки по TRIM(LOWER(Name))), а не для строгого равенства. - person Molossus Spondee; 25.08.2018

Самосоединение полезно, когда вам нужно оценить данные таблицы с самой собой. Это означает, что он будет сопоставлять строки из одной и той же таблицы.

Syntax: SELECT * FROM TABLE t1, TABLE t2 WHERE t1.columnName = t2.columnName

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

SELECT NAME FROM Employee e1, Employee e2 WHERE e1.intialDesignationId = e2.currentDesignationId
person Sumanth Varada    schedule 21.01.2019

Это эквивалент базы данных связанного списка/дерева, где строка содержит ссылку в той или иной степени на другую строку.

person Unsliced    schedule 16.03.2010
comment
На самом деле, учитывая, что на родительскую строку может ссылаться более одной строки, она также может быть деревом, как, например, в часто цитируемом примере «сотрудник-›менеджер». - person NVRAM; 17.03.2010
comment
Я просто пытался провести простую аналогию, но да, дерево тоже может работать. - person Unsliced; 17.03.2010

Вот объяснение самостоятельного соединения с точки зрения непрофессионала. Самосоединение не является другим типом соединения. Если вы знакомы с другими типами соединений (внутренними, внешними и перекрестными соединениями), то самостоятельное соединение должно быть простым. В INNER, OUTER и CROSS JOINS вы объединяете 2 или более разных таблиц. Однако при самосоединении вы присоединяетесь к одной и той же таблице с ее левым звеном. Здесь у нас нет двух разных таблиц, но мы рассматриваем одну и ту же таблицу как другую таблицу, используя псевдонимы таблиц. Если это все еще не ясно, я бы рекомендовал посмотреть следующие видео на YouTube.

Самостоятельное присоединение с примером

person user1472512    schedule 31.08.2012