自联接的说明


84

我不了解自我加入的必要。有人可以给我解释一下吗?

一个简单的例子将非常有帮助。

Answers:


95

您可以将自我联接视为两个相同的表。但是在规范化中,您无法创建表的两个副本,因此只能模拟具有两个具有自联接的表。

假设您有两个表:

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 '18

22

当您有一个引用自己的表时,这很常见。示例:一个employee表,其中每个雇员都可以有一个经理,您想列出所有雇员及其经理的姓名。

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

18

自我联接是表与其自身的联接。

一个常见的用例是当表存储实体(记录)之间具有层次关系时。例如,一个包含个人信息(姓名,DOB,地址...)的表,其中包括一列,其中包括父亲(和/或母亲)的ID。然后用一个小查询

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

如果您的表是自引用的,则它们很有用。例如,对于页面表,每个页面可以具有nextprevious链接。这些将是同一表中其他页面的ID。如果要在某个时候获得三张连续的页面,则可以在nextprevious列上使用同一表的id列进行两个自联接。


4

想象一下一个名为Employee如下所述的表。所有员工都有一个同时也是员工的经理(可能是CEO除外,CEO的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)2010年

4

除了上面提到的答案(很好地解释了)外,我想添加一个示例,以便可以轻松显示“自我连接”的使用。假设您有一个名为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此答案非常重要,因为SO上有如此多的SQL问题,答案是“使用自我连接”,当人们没有明确的(分层的)自我参考时,人们往往看不到这些问题。
JimmyB

1
即使这是来自w3schools的复制面食,我认为以上答案也不能解释自我联接,而是内部联接,这是不同的。
乔治K

3

这里有许多正确答案,但有一个变体也同样正确。您可以将联接条件放置在join语句中,而不是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
嗯,在小狗中,为什么要加入“大于”而不是“等于”?
Marcel 2014年

1
你好 我已经看到一些示例使用“ FROM xxx,yyy WHERE”和其他一些“ FROM xxx JOIN yyy WHERE”。您能解释一下其中的区别吗?
skan 2014年

@Skan这是一个非常好的问题。简短的答案是,这是旧的速记方法,将不建议使用。我十多年前在学校使用过它,很少在实践中看到它。这里是最简洁的描述,我可以找到:bidn.com/blogs/KathiKellenberger/sql-server/2875/...
BClaydon

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子句查找重复项要快得多。从My_Bookings GROUP BY名称中选择名称,电子邮件,COUNT(),在日期中获得COUNT()> 1
George K

@GeorgeK是的。我想这仅对于模糊匹配(除按TRIM(LOWER(Name))分组之外)是必需的,而对于严格的相等性则不是必需的。
史蒂文·斯图尔特·加卢斯

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

我只是在尝试一个简单的类比,但是是的,一棵树也可以工作。
切片2010年

-4

这是外行自我加入的过程。自我联接不是另一种联接类型。如果您了解其他类型的联接(内部,外部和交叉联接),则自我联接应该很简单。在“内部”,“外部”和“交叉联接”中,联接2个或更多不同的表。但是,在自我联接中,您将使用itslef联接同一表。在这里,我们没有2个不同的表,但是使用表别名将同一个表视为不同的表。如果仍然不清楚,我建议您观看以下youtube视频。

自我加入的例子

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.