Объяснение самоподключений


87

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

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

Ответы:


99

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

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

Стол emp1

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

1
В этом примере я не могу понять, кто здесь главный. Хотя опыт хорош и понятен.
MAC

2
left joinЯ думаю, было бы лучше не упускать из виду сотрудника (или начальника), у которого нет начальника; лучшая собака!
Rockin4Life33

Должно быть от emp c1 вместо emp1 c1? @pointlesspolitics
Рохит Сингх

22

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

SELECT e.name, m.name
FROM employees e LEFT OUTER JOIN employees m
ON e.manager = m.id

18

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

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

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

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


5

Допустим, у вас есть стол users, настроенный так:

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

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

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

4

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


4

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

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

4

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


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

4

Помимо упомянутых выше ответов (которые очень хорошо объяснены), я хотел бы добавить один пример, чтобы можно было легко продемонстрировать использование 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;

3
+1 Этот ответ очень важен, потому что существует так много вопросов SQL по SO, на которые можно ответить «используйте самосоединение», что люди, как правило, не видят, если у них нет явной (иерархической) ссылки на себя.
JimmyB

1
Даже несмотря на то, что это копировальная паста из w3schools, я думаю, что приведенный выше ответ не объясняет самосоединение, а внутреннее соединение, которое отличается.
Джордж К.

3

Здесь есть много правильных ответов, но есть и вариант, который также верен. Вы можете поместить свои условия соединения в оператор соединения вместо предложения 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

1
Хм, в щенке, почему вы присоединяетесь к "больше чем" вместо "равно"?
Марсель

1
Привет. Я видел, что в некоторых примерах используется «FROM xxx, yyy WHERE», а в некоторых других «FROM xxx JOIN yyy WHERE». Не могли бы вы объяснить разницу, пожалуйста?
skan

@Skan Это действительно хороший вопрос. Короткий ответ заключается в том, что это старый сокращенный метод, и он будет устаревшим. Я использовал его в школе более десяти лет назад и редко вижу это на практике. Вот самое краткое описание, которое я смог найти: bidn.com/blogs/KathiKellenberger/sql-server/2875/…
BClaydon 02

1

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

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

Для поиска дубликатов гораздо быстрее использовать GROUP BY и предложение HAVING. ВЫБЕРИТЕ имя, адрес электронной почты, COUNT ( ) ИЗ My_Bookings ГРУППА ПО имени, дате HAVING COUNT ( )> 1
Джордж К.

@GeorgeK Верно. Я полагаю, это необходимо только для нечеткого совпадения (помимо группировки по TRIM (LOWER (Name))), а не для строгого равенства.
Molossus Spondee

1

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

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

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

SELECT NAME FROM Employee e1, Employee e2 WHERE e1.intialDesignationId = e2.currentDesignationId

0

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


Фактически, учитывая, что более чем одна строка может ссылаться на «родительский элемент», это также может быть дерево, как, например, в часто цитируемом примере employee-> manager.
NVRAM

Я просто пытался провести простую аналогию, но да, дерево тоже может работать.
Unsliced

-4

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.