Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Hướng dẫn cơ bản của bạn về tham gia SQL:OUTER JOIN - Phần 2

Tham gia bên ngoài là ở giai đoạn trung tâm ngày hôm nay. Và đây là phần 2 của hướng dẫn cơ bản về các phép nối SQL. Nếu bạn bỏ lỡ phần 1, đây là liên kết.

Nhìn bề ngoài, bên ngoài đối lập với bên trong. Tuy nhiên, nếu bạn xem xét kết nối bên ngoài theo cách này, bạn sẽ bị nhầm lẫn. Trên hết, bạn không cần phải bao gồm từ bên ngoài trong cú pháp của bạn một cách rõ ràng. Đó là tùy chọn!

Nhưng trước khi chúng ta đi sâu vào, hãy thảo luận về những vấn đề không liên quan đến kết nối bên ngoài.

Nulls và OUTER JOIN

Khi bạn nối 2 bảng, một trong các giá trị từ một trong hai bảng có thể là giá trị rỗng. Đối với INNER JOIN, các bản ghi có giá trị rỗng sẽ không khớp và chúng sẽ bị loại bỏ và sẽ không xuất hiện trong tập kết quả. Nếu bạn muốn nhận các bản ghi không khớp, lựa chọn duy nhất của bạn là THAM GIA NGOÀI TRỜI.

Quay trở lại với từ trái nghĩa, đó có phải là từ trái nghĩa với INNER JOIN không? Không hoàn toàn, như bạn sẽ thấy trong phần tiếp theo.

Tất cả về SQL Server OUTER JOIN

Việc hiểu các phép nối bên ngoài bắt đầu với đầu ra. Dưới đây là danh sách đầy đủ những gì bạn có thể mong đợi:

  • Tất cả các bản ghi phù hợp với điều kiện nối hoặc vị từ. Đó là biểu thức ngay sau từ khóa ON, giống như đầu ra INNER JOIN. Chúng tôi gọi vấn đề này là hàng bên trong .
  • Các giá trị không phải NULL từ bên trái bảng có các đối số rỗng từ bên phải bàn. Chúng tôi gọi vấn đề này là hàng ngoài .
  • Các giá trị không phải NULL từ bên phải bảng có các đối số rỗng từ bên trái bàn. Đây là một dạng khác của các hàng bên ngoài.
  • Cuối cùng, nó có thể là sự kết hợp của tất cả những điều được mô tả ở trên.

Với danh sách đó, chúng ta có thể nói rằng OUTER JOIN trả về các hàng bên trong và bên ngoài .

  • Bên trong - vì kết quả chính xác của INNER JOIN có thể là đã trả lại.
  • Bên ngoài - vì các hàng bên ngoài cũng có thể là đã trả lại.

Đó là sự khác biệt so với INNER JOIN.

THAM GIA BÊN TRONG CHỈ TRỞ LẠI CÁC TUYẾN TRONG. CÁC THAM GIA NGOÀI TRỜI CÓ THỂ QUAY LẠI CẢ CON ĐƯỜNG TRONG VÀ NGOÀI TRỜI

Lưu ý rằng tôi đã sử dụng "có thể được" và "cũng có thể được." Nó phụ thuộc vào mệnh đề WHERE của bạn (hoặc nếu bạn bao gồm mệnh đề WHERE) nếu nó trả về cả hai hàng bên trong và / hoặc bên ngoài.

Nhưng từ một câu lệnh SELECT, làm cách nào bạn có thể xác định đâu là bảng bên trái hay bên phải ? Câu hỏi hay!

Làm thế nào để biết được bảng bên trái hay bên phải trong tham gia?

Chúng ta có thể trả lời câu hỏi này bằng các ví dụ:

SELECT *
FROM Table1 a
LEFT OUTER JOIN Table2 b on a.column1 = b.column1

Từ ví dụ trên, Table1 là bảng bên trái và Table2 là bàn bên phải. Bây giờ, hãy xem một ví dụ khác. Lần này, đó là một phép tham gia nhiều lần đơn giản.

SELECT *
FROM Table1 a
LEFT OUTER JOIN Table2 b on a.column1 = b.column1
LEFT OUTER JOIN Table3 c on b.column2 = c.column1

Trong trường hợp này, để biết điều gì là bên trái hay bên phải, hãy nhớ rằng một phép liên kết hoạt động trên 2 bảng.

Bảng1 vẫn là bảng bên trái và Table2 là bàn bên phải. Điều này đề cập đến việc kết hợp 2 bảng: Table1 Table2 . Còn về việc tham gia Table2 Table3 ? Bảng2 trở thành bảng bên trái và Table3 là bảng bên phải.

Nếu chúng ta thêm bảng thứ tư, Table3 trở thành bảng bên trái và Table4 là bàn bên phải. Nhưng nó không kết thúc ở đó. Chúng ta có thể nối một bảng khác vào Table1 . Đây là một ví dụ:

SELECT *
FROM Table1 a
LEFT OUTER JOIN Table2 b on a.column1 = b.column1
LEFT OUTER JOIN Table3 c on b.column2 = c.column1
LEFT OUTER JOIN Table4 d on c.column1 = d.column2
LEFT OUTER JOIN Table5 e on a.column2 = e.column1

Bảng1 là bảng bên trái và Table5 là bàn bên phải. Bạn cũng có thể làm tương tự với các bảng khác.

Được rồi, hãy quay lại danh sách kết quả mong đợi ở trên. Chúng tôi cũng có thể lấy các loại liên kết bên ngoài từ chúng.

Các kiểu tham gia bên ngoài

Có 3 loại dựa trên kết quả đầu ra OUTER JOIN.

THAM GIA BÊN NGOÀI TRÁI (THAM GIA TRÁI)

LEFT JOIN trả về các hàng bên trong + Giá trị không phải NULL từ bên trái bảng với các đối tác rỗng của bảng bên phải. Do đó, nó là LEFT JOIN vì bảng bên trái là bảng thống trị của hai bảng trong phép nối có giá trị không phải null.

THAM GIA NGOÀI TRÁI VÍ DỤ 1
-- Return all customerIDs with orders and no orders

USE AdventureWorks
GO

SELECT
 c.CustomerID
,soh.OrderDate
FROM Sales.Customer c
LEFT OUTER JOIN Sales.SalesOrderHeader soh ON c.CustomerID = soh.CustomerID 

Trong ví dụ trên, Khách hàng là bảng bên trái và SalesOrderHeader là bàn bên phải. Kết quả của truy vấn là 32,166 bản ghi - nó bao gồm cả hàng trong và hàng ngoài. Bạn có thể thấy một phần của nó trong Hình 1:

Giả sử chúng ta chỉ muốn trả lại các hàng bên ngoài hoặc những khách hàng không có đơn đặt hàng nào. Để làm điều đó, hãy thêm mệnh đề WHERE để chỉ bao gồm các hàng có giá trị rỗng từ SalesOrderHeader .

SELECT
 c.CustomerID
,soh.OrderDate
FROM Sales.Customer c
LEFT OUTER JOIN Sales.SalesOrderHeader soh ON c.CustomerID = soh.CustomerID
WHERE soh.SalesOrderID IS NULL

Tập kết quả mà tôi nhận được là 701 bản ghi . Tất cả chúng đều giống như Ngày đặt hàng null từ Hình 1.

Nếu tôi chỉ nhận được các hàng bên trong, kết quả sẽ là 31.465 bản ghi . Tôi có thể làm điều đó bằng cách thay đổi mệnh đề WHERE để bao gồm các SalesOrderID đó không rỗng. Hoặc tôi có thể thay đổi liên kết thành INNER JOIN và xóa mệnh đề WHERE.

Để xem liệu nó có được kiểm tra từ đầu ra của ví dụ đầu tiên mà không có mệnh đề WHERE hay không, hãy tổng hợp các bản ghi.

Hàng bên trong Hàng ngoài Tổng số hàng
31.465 bản ghi 701 bản ghi 32.166 bản ghi

Từ Tổng số hàng ở trên với 32.166 bản ghi, bạn có thể thấy rằng nó kiểm tra với kết quả ví dụ đầu tiên. Điều này cũng cho thấy cách hoạt động của LEFT OUTER JOIN.

THAM GIA BÊN NGOÀI TRÁI VÍ DỤ 2

Lần này, ví dụ là một phép nối nhiều. Cũng lưu ý rằng chúng tôi loại bỏ từ khóa OUTER.

-- show the people with and without addresses from AdventureWorks
USE AdventureWorks
GO

SELECT
 P.FirstName
,P.MiddleName
,P.LastName
,a.AddressLine1
,a.AddressLine2
,a.City
,adt.Name AS AddressType
FROM Person.Person p
LEFT JOIN Person.BusinessEntityAddress bea ON P.BusinessEntityID = bea.BusinessEntityID
LEFT JOIN Person.Address a ON bea.AddressID = a.AddressID
LEFT JOIN person.AddressType adt ON bea.AddressTypeID = adt.AddressTypeID 

Nó đã tạo ra 19.996 bản ghi. Bạn có thể kiểm tra phần đầu ra trong Hình 2 bên dưới. Các bản ghi có AddressLine1 rỗng là các hàng ngoài cùng. Phía trên nó là các hàng bên trong.

THAM GIA ĐÚNG NGƯỜI RA (RIGHT THAM GIA)

RIGHT JOIN trả về các hàng bên trong + Giá trị không phải NULL từ bên phải bảng với các đối tác rỗng của bảng bên trái.

VÍ DỤ THAM GIA NGAY NGƯỜI RA ĐÚNG
-- From the product reviews, return the products without product reviews
USE AdventureWorks
GO

SELECT
P.Name
FROM Production.ProductReview pr
RIGHT OUTER JOIN Production.Product p ON pr.ProductID = p.ProductID
WHERE pr.ProductReviewID IS NULL 

Hình 3 cho thấy 10 trong số 501 bản ghi trong tập kết quả.

Trong ví dụ trên, ProductReview là bảng bên trái và Sản phẩm là bàn bên phải. Vì đây là THAM GIA RIGHT OUTER, chúng tôi dự định bao gồm các giá trị Non-NULL từ bảng bên phải.

Tuy nhiên, việc lựa chọn THAM GIA TRÁI hoặc THAM GIA PHẢI phụ thuộc vào bạn. Tại sao? Bởi vì bạn có thể thể hiện truy vấn, cho dù THAM GIA TRÁI hoặc PHẢI và nhận được cùng một kết quả. Hãy thử nó với THAM GIA TRÁI.

-- return the products without product reviews using LEFT OUTER JOIN
USE AdventureWorks
GO

SELECT
P.Name
FROM Production.Product p
LEFT OUTER JOIN Production.ProductReview pr ON pr.ProductID = p.ProductID
WHERE pr.ProductReviewID IS NULL

Hãy thử thực hiện những điều trên, và bạn sẽ có kết quả giống như trong Hình 3. Nhưng bạn có nghĩ rằng Trình tối ưu hóa truy vấn sẽ xử lý chúng theo cách khác không? Hãy cùng tìm hiểu trong Kế hoạch thực hiện của cả hai trong Hình 4.

Nếu bạn chưa quen với điều này, có một vài điều bất ngờ trong Kế hoạch thực thi.

  1. Các sơ đồ trông giống nhau và đó là:hãy thử So sánh sơ đồ trình diễn và bạn sẽ thấy QueryPlanHash tương tự .
  2. Lưu ý sơ đồ trên cùng với một phép kết hợp Hợp nhất. Chúng tôi đã sử dụng THAM GIA RIGHT OUTER, nhưng SQL Server đã thay đổi nó thành THAM GIA TRÁI. Nó cũng chuyển đổi bảng bên trái và bên phải. Nó làm cho nó tương đương với truy vấn thứ hai với LEFT JOIN.

Như bạn thấy bây giờ, kết quả là như nhau. Vì vậy, chọn THAM GIA NGOÀI TRỜI sẽ thuận tiện hơn.

Tại sao SQL Server lại thay đổi RIGHT JOIN thành LEFT JOIN?

Công cụ cơ sở dữ liệu không nhất thiết phải tuân theo cách bạn thể hiện các phép nối hợp lý. Miễn là nó có thể tạo ra kết quả chính xác theo cách nhanh nhất mà nó cho là có thể, nó sẽ thực hiện thay đổi. Ngay cả các phím tắt.

Đừng kết luận rằng RGHT JOIN là xấu và LEFT JOIN là tốt.

VÍ DỤ THAM GIA NGAY LẬP TỨC 2

Hãy xem ví dụ dưới đây:

-- Get the unassigned addresses and the address types with no addresses
SELECT
 P.FirstName
,P.MiddleName
,P.LastName
,a.AddressLine1
,a.AddressLine2
,a.City
,adt.Name AS AddressType
FROM Person.Person p
RIGHT JOIN Person.BusinessEntityAddress bea ON P.BusinessEntityID = bea.BusinessEntityID
RIGHT JOIN Person.Address a ON bea.AddressID = a.AddressID
RIGHT JOIN person.AddressType adt ON bea.AddressTypeID = adt.AddressTypeID
WHERE P.BusinessEntityID IS NULL 

Có 2 điều bạn có thể nhận được từ truy vấn này, như bạn có thể thấy trong Hình 5 bên dưới:

Kết quả truy vấn hiển thị như sau:

  1. Các địa chỉ chưa được gán - những bản ghi này là những bản ghi có tên rỗng.
  2. Loại Địa chỉ không có địa chỉ. Các loại địa chỉ Lưu trữ, Thanh toán và Chính không có địa chỉ tương ứng. Đó là từ hồ sơ 817 đến 819.

FULL OUTER JOIN (THAM GIA ĐẦY ĐỦ)

FULL JOIN trả về kết hợp các hàng bên trong và hàng bên ngoài, trái và phải.

-- Get people with and without addresses, unassigned addresses, and address types without addresses
SELECT
 P.FirstName
,P.MiddleName
,P.LastName
,a.AddressLine1
,a.AddressLine2
,a.City
,adt.Name AS AddressType
FROM Person.Person p
FULL JOIN Person.BusinessEntityAddress bea ON P.BusinessEntityID = bea.BusinessEntityID
FULL JOIN Person.Address a ON bea.AddressID = a.AddressID
FULL JOIN person.AddressType adt ON bea.AddressTypeID = adt.AddressTypeID

Bộ kết quả bao gồm 20.815 bản ghi. Giống như những gì bạn mong đợi, đó là tổng số bản ghi từ tập hợp kết quả của INNER JOIN, LEFT JOIN và RIGHT JOIN.

LEFT và RIGHT JOIN bao gồm mệnh đề WHERE để chỉ hiển thị các kết quả có giá trị rỗng trong bảng bên trái hoặc bên phải.

INNER JOIN THAM GIA TRÁI
(WHERE a .AddressID LÀ KHÔNG ĐẦY ĐỦ)
THAM GIA ĐÚNG
(Ở đâu P.BusinessEntityID LÀ KHÔNG ĐẦY ĐỦ)
TOTAL (Giống như FULL JOIN)
18.798 bản ghi 1.198 bản ghi 819 bản ghi 20.815 bản ghi

Lưu ý rằng FULL JOIN có thể tạo ra một tập kết quả lớn từ các bảng lớn. Vì vậy, chỉ sử dụng nó khi bạn cần.

Công dụng thực tế của OUTER JOIN

Nếu bạn vẫn còn do dự khi có thể và nên sử dụng OUTER JOIN, thì đây là một số ý tưởng.

Kết hợp bên ngoài để xuất ra cả hàng bên trong và hàng bên ngoài

Ví dụ có thể là:

  • Danh sách các đơn đặt hàng đã thanh toán và chưa thanh toán theo thứ tự bảng chữ cái.
  • Danh sách nhân viên đi muộn hoặc không đi muộn theo thứ tự bảng chữ cái.
  • Danh sách các chủ hợp đồng đã gia hạn và không gia hạn các hợp đồng bảo hiểm gần đây nhất của họ.

Outer Joins That Output Outer Rows Only

Các ví dụ bao gồm:

  • danh sách nhân viên không đi trễ theo thứ tự bảng chữ cái để được trao giải thưởng không đi trễ
  • danh sách các lãnh thổ không có khách hàng
  • danh sách các đại lý bán hàng không bán một sản phẩm cụ thể nào
  • nhận kết quả từ các giá trị bị thiếu, chẳng hạn như các ngày không có đơn đặt hàng bán hàng trong một khoảng thời gian nhất định (ví dụ bên dưới)
  • các nút không có nút con trong mối quan hệ cha-con (ví dụ bên dưới)

Nhận kết quả từ các giá trị bị thiếu

Giả sử bạn cần tạo một báo cáo. Báo cáo đó phải hiển thị số ngày cho mỗi tháng trong một khoảng thời gian nhất định mà không có bất kỳ đơn đặt hàng nào. SalesOrderHeader trong AdventureWorks chứa Ngày đặt hàng , nhưng họ không có ngày không có đơn đặt hàng. Bạn có thể làm gì?

1. Tạo một bảng tất cả các ngày trong một khoảng thời gian

Tập lệnh mẫu bên dưới sẽ tạo một bảng ngày tháng cho cả năm 2014:

DECLARE @StartDate date = '20140101', @EndDate date = '20141231';

CREATE TABLE dbo.Dates
(
	d DATE NOT null PRIMARY KEY
)

WHILE @StartDate <= @EndDate
BEGIN
  INSERT Dates([d]) SELECT @StartDate;
  SET @StartDate = DATEADD(DAY, 1, @StartDate);
END

SELECT d FROM Dates ORDER BY [d];
2. Sử dụng THAM GIA TRÁI để tạo ra những ngày không có đơn đặt hàng
SELECT
 MONTH(d.d) AS [month]
,YEAR(d.d) AS [year]
,COUNT(*) AS NoOrderDays
FROM Dates d
LEFT JOIN Sales.SalesOrderHeader soh ON d.d = soh.OrderDate
WHERE soh.OrderDate IS NULL
GROUP BY YEAR(d.d), MONTH(d.d)
ORDER BY [year], [month]

Đoạn mã trên đếm số ngày không có đơn đặt hàng nào được thực hiện. SalesOrderHeader chứa các ngày có đơn đặt hàng. Vì vậy, các giá trị null được trả lại trong tham gia sẽ được tính là ngày không có đơn đặt hàng.

Trong khi đó, nếu bạn muốn biết ngày chính xác, bạn có thể xóa số lượng và nhóm.

SELECT
 d.d
,soh.OrderDate
FROM Dates d
LEFT JOIN Sales.SalesOrderHeader soh ON d.d = soh.OrderDate
WHERE soh.OrderDate IS NULL

Hoặc, nếu bạn muốn đếm đơn đặt hàng trong một khoảng thời gian nhất định và xem ngày nào không có đơn đặt hàng nào, thì đây là cách thực hiện:

SELECT DISTINCT
 D.d AS SalesDate
,COUNT(soh.OrderDate) AS NoOfOrders
FROM Dates d
LEFT JOIN Sales.SalesOrderHeader soh ON d.d = soh.OrderDate
WHERE d.d BETWEEN '02/01/2014' AND '02/28/2014'
GROUP BY d.d
ORDER BY d.d

Đoạn mã trên tính đơn hàng cho tháng 2 năm 2014. Xem kết quả:

Tại sao nó lại làm nổi bật ngày 3 tháng 2 năm 2014? Trong bản sao AdventureWorks của tôi, không có đơn đặt hàng nào cho ngày đó.

Bây giờ, hãy thông báo COUNT (soh.OrderDate) trong mã. Sau đó, chúng tôi sẽ làm rõ tại sao điều này lại quan trọng như vậy.

Có được nút không có con trong mối quan hệ cha mẹ và con cái

Đôi khi chúng ta cần biết các nút không có nút con nào trong mối quan hệ cha-con.

Hãy sử dụng cơ sở dữ liệu tôi đã sử dụng trong bài viết của tôi về HierarchyID. Bạn cần lấy các nút không có nút con trong bảng quan hệ cha-con bằng cách sử dụng tự nối.

SELECT 
 r1.RankParentId
,r1.Rank AS RankParent
,r.RankId
FROM Ranks r
RIGHT JOIN Ranks r1 ON r.RankParentId = r1.RankId
WHERE r.RankId is NULL 

Lưu ý khi sử dụng OUTER JOIN

Vì OUTER JOIN có thể trả về các hàng bên trong giống như INNER JOIN, nên nó có thể gây nhầm lẫn. Các vấn đề về hiệu suất cũng có thể xuất hiện. Vì vậy, hãy lưu ý 3 điểm dưới đây (thỉnh thoảng tôi quay lại với chúng - tôi không còn trẻ nữa nên tôi cũng quên mất).

Lọc Bảng bên phải trong THAM GIA TRÁI với Giá trị không phải Null trong Mệnh đề WHERE

Có thể là một vấn đề nếu bạn đã sử dụng LEFT OUTER JOIN nhưng lại lọc bảng bên phải với giá trị khác rỗng trong mệnh đề WHERE. Lý do là, nó sẽ trở nên tương đương về mặt chức năng với INNER JOIN. Hãy xem xét ví dụ dưới đây:

USE AdventureWorks
GO

SELECT
 P.FirstName
,P.MiddleName
,P.LastName
,a.AddressLine1
,a.AddressLine2
,a.City
,adt.Name AS AddressType
FROM Person.Person p
LEFT JOIN Person.BusinessEntityAddress bea ON P.BusinessEntityID = bea.BusinessEntityID
LEFT JOIN Person.Address a ON bea.AddressID = a.AddressID
LEFT JOIN person.AddressType adt ON bea.AddressTypeID = adt.AddressTypeID
WHERE bea.AddressTypeID = 5 

Từ đoạn mã trên, hãy kiểm tra 2 bảng: Người BusinessEntityAddress . Người là bảng bên trái và BusinessEntityAddress là bảng bên phải.

LEFT JOIN được sử dụng, vì vậy nó giả định BusinessEntityID null ở đâu đó trong BusinessEntityAddress . Ở đây, hãy chú ý mệnh đề WHERE. Nó lọc đúng bảng với AddressTypeID =5. Nó loại bỏ hoàn toàn tất cả các hàng bên ngoài trong BusinessEntityAddress .

Đây có thể là bất kỳ cái nào sau đây:

  • Nhà phát triển đang thử nghiệm điều gì đó trong kết quả nhưng lại quên xóa nó.
  • INNER JOIN đã được dự định, nhưng vì một số lý do, LEFT JOIN đã được sử dụng.
  • Nhà phát triển không hiểu sự khác biệt giữa LEFT JOIN và INNER JOIN. Anh ấy cho rằng bất kỳ điều nào trong số cả 2 đều sẽ hiệu quả và điều đó không quan trọng vì trong trường hợp này, kết quả là như nhau.

Bất kỳ mục nào trong số 3 điều trên đều xấu, nhưng mục nhập thứ ba có hàm ý khác. Hãy so sánh mã ở trên với mã INNER JOIN tương đương:

SELECT
 P.FirstName
,P.MiddleName
,P.LastName
,a.AddressLine1
,a.AddressLine2
,a.City
,adt.Name AS AddressType
FROM Person.Person p
INNER JOIN Person.BusinessEntityAddress bea ON P.BusinessEntityID = bea.BusinessEntityID
INNER JOIN Person.Address a ON bea.AddressID = a.AddressID
INNER JOIN person.AddressType adt ON bea.AddressTypeID = adt.AddressTypeID
WHERE bea.AddressTypeID = 5

Nó trông tương tự như mã trước đó ngoại trừ kiểu nối. Kết quả cũng tương tự, nhưng bạn nên lưu ý các lần đọc logic trong IO THỐNG KÊ:

Trong Hình 7, số liệu thống kê I / O đầu tiên là từ việc sử dụng INNER JOIN. Tổng số lần đọc logic là 177. Tuy nhiên, số liệu thống kê thứ hai dành cho LEFT JOIN với giá trị đọc logic cao hơn là 223. Do đó, việc sử dụng sai LEFT JOIN trong ví dụ này sẽ yêu cầu nhiều trang hoặc tài nguyên hơn từ SQL Server. Do đó, nó sẽ chạy chậm hơn.

Takeaway

Nếu bạn định xuất các hàng bên trong, hãy sử dụng INNER JOIN. Nếu không, không lọc bảng bên phải trong THAM GIA TRÁI với giá trị khác rỗng. Nếu điều này xảy ra, bạn sẽ nhận được một truy vấn chậm hơn so với khi bạn sử dụng INNER JOIN.

MẸO THƯỞNG :Tình huống này cũng xảy ra trong THAM GIA PHẢI khi bảng bên trái được lọc với giá trị không phải null.

Sử dụng không đúng kiểu tham gia trong phần nhiều tham gia

Giả sử chúng ta muốn lấy tất cả các nhà cung cấp và số lượng đơn đặt hàng mua sản phẩm cho mỗi nhà cung cấp. Đây là mã:

USE AdventureWorks
GO

SELECT
 v.BusinessEntityID
,v.Name AS Vendor
,pod.ProductID
,pod.OrderQty
FROM Purchasing.Vendor v
LEFT JOIN Purchasing.PurchaseOrderHeader poh ON v.BusinessEntityID = poh.VendorID
LEFT JOIN Purchasing.PurchaseOrderDetail pod ON poh.PurchaseOrderID = pod.PurchaseOrderID 

Đoạn mã trên trả về cả những nhà cung cấp có đơn đặt hàng và những nhà cung cấp không có. Hình 8 cho thấy Kế hoạch Thực thi Thực tế của đoạn mã trên.

Nghĩ rằng mọi đơn đặt hàng đều có thông tin chi tiết về đơn đặt hàng được đảm bảo, THAM GIA INNER sẽ tốt hơn. Tuy nhiên, nó có thực sự như vậy không?

Đầu tiên, hãy sửa đổi mã với INNER JOIN.

USE AdventureWorks
GO

SELECT
 v.BusinessEntityID
,v.Name AS Vendor
,pod.ProductID
,pod.OrderQty
FROM Purchasing.Vendor v
LEFT JOIN Purchasing.PurchaseOrderHeader poh ON v.BusinessEntityID = poh.VendorID
INNER JOIN Purchasing.PurchaseOrderDetail pod ON poh.PurchaseOrderID = pod.PurchaseOrderID 

Hãy nhớ rằng, yêu cầu ở trên cho biết "tất cả" nhà cung cấp. Vì chúng tôi đã sử dụng THAM GIA TRÁI trong mã trước đó, chúng tôi sẽ nhận được các nhà cung cấp mà không trả lại đơn đặt hàng. Đó là do PurchaseOrderID không có giá trị .

Thay đổi tham gia thành INNER JOIN sẽ loại bỏ tất cả PurchaseOrderIDs không có giá trị. Nó cũng sẽ hủy tất cả VendorIDs không có giá trị từ Nhà cung cấp bàn. Trên thực tế, nó trở thành THAM GIA BÊN TRONG.

Đó có phải là một giả định đúng? Kế hoạch Thực thi sẽ tiết lộ câu trả lời:

Như bạn thấy, tất cả các bảng đã được xử lý bằng INNER JOIN. Do đó, giả định của chúng tôi là đúng. Nhưng phần tệ nhất, tập hợp kết quả hiện không chính xác vì không bao gồm các nhà cung cấp không có đơn đặt hàng nào.

Takeaway

Giống như trong trường hợp trước, nếu bạn có ý định INNER JOIN, hãy sử dụng nó. Nhưng bạn biết phải làm gì nếu bạn gặp phải tình huống như ở đây.

Trong trường hợp này, INNER JOIN sẽ loại bỏ tất cả các hàng bên ngoài cho đến bảng trên cùng trong mối quan hệ. Ngay cả khi tham gia khác của bạn là THAM GIA TRÁI, điều đó sẽ không thành vấn đề. Chúng tôi đã chứng minh điều đó trong các Kế hoạch Thực thi.

Sử dụng không chính xác COUNT () trong kết nối bên ngoài

Hãy nhớ mã mẫu của chúng tôi đếm số lượng đơn đặt hàng mỗi ngày và kết quả trong Hình 6?

Tại đây, chúng tôi sẽ làm rõ lý do tại sao ngày 02/03/2014 được đánh dấu và mối quan hệ của nó với COUNT (soh.OrderDate) .

Nếu bạn thử sử dụng COUNT (*), số lượng đơn đặt hàng cho ngày đó sẽ trở thành 1, điều này là sai. Không có đơn đặt hàng vào ngày đó. Vì vậy, khi sử dụng COUNT () với OUTER JOIN, hãy sử dụng đúng cột để đếm.

Trong trường hợp của chúng tôi, soh.OrderDate có thể là null hoặc không. Khi nó không rỗng, COUNT () sẽ bao gồm hàng trong số lượng. COUNT (*) sẽ làm cho nó đếm mọi thứ, bao gồm cả các giá trị rỗng. Và cuối cùng, kết quả sai.

Bài học THAM GIA NGOÀI TRỜI

Hãy tóm tắt các điểm:

  • OUTER JOIN có thể trả về cả hàng bên trong và hàng bên ngoài. Các hàng bên trong là kết quả tương tự như kết quả của INNER JOIN. Các hàng bên ngoài là các giá trị không null với các giá trị bằng rỗng của chúng dựa trên điều kiện kết hợp.
  • OUTER JOIN có thể là LEFT, RIGHT hoặc FULL. Chúng tôi đã có các ví dụ cho từng loại.
  • Các hàng bên ngoài do OUTER JOIN trả về có thể được sử dụng theo nhiều cách thực tế. Chúng tôi đã có ý tưởng về thời điểm bạn có thể sử dụng công cụ này.
  • Chúng tôi cũng có những lưu ý khi sử dụng OUTER JOIN. Hãy lưu ý 3 điểm trên để tránh lỗi và các vấn đề về hiệu suất.

Phần cuối của loạt bài này sẽ thảo luận về CROSS JOIN. Vì vậy, cho đến lúc đó. Và nếu bạn thích bài đăng này, hãy chia sẻ một số tình yêu bằng cách nhấp vào các nút mạng xã hội. Chúc bạn viết mã vui vẻ!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Biến môi trường LD_DEBUG

  2. Người đọc giải pháp cho thách thức Quần đảo đặc biệt

  3. Lập mô hình cơ sở dữ liệu để ghi lại doanh số bán hàng. Phần 1

  4. Chất lượng dữ liệu và Tìm kiếm mờ

  5. Di chuyển Dự án Django của bạn sang Heroku