Database
 sql >> Datenbank >  >> RDS >> Database

Ihr ultimativer Leitfaden für SQL-Joins:OUTER JOIN – Teil 2

Outer Join steht heute im Mittelpunkt. Und dies ist Teil 2 Ihres ultimativen Leitfadens für SQL-Joins. Falls Sie Teil 1 verpasst haben, hier ist der Link.

So wie es aussieht, ist außen das Gegenteil von innen. Wenn Sie den Outer Join jedoch auf diese Weise betrachten, werden Sie verwirrt sein. Darüber hinaus müssen Sie das Wort outer nicht einfügen explizit in Ihrer Syntax. Es ist optional!

Aber bevor wir ins Detail gehen, lassen Sie uns über Nullen in Bezug auf äußere Verknüpfungen sprechen.

Nulls und OUTER JOIN

Wenn Sie zwei Tabellen verknüpfen, kann einer der Werte aus beiden Tabellen null sein. Bei INNER JOINs stimmen Datensätze mit Nullen nicht überein und sie werden verworfen und erscheinen nicht in der Ergebnismenge. Wenn Sie die Datensätze erhalten möchten, die nicht übereinstimmen, ist Ihre einzige Option OUTER JOIN.

Zurück zu Antonyme, ist das nicht das Gegenteil von INNER JOINs? Nicht ganz, wie Sie im nächsten Abschnitt sehen werden.

Alles über SQL Server OUTER JOIN

Das Verständnis von Outer Joins beginnt mit der Ausgabe. Hier ist eine vollständige Liste dessen, was Sie erwarten können:

  • Alle Datensätze, die der Join-Bedingung oder dem Prädikat entsprechen. Das ist der Ausdruck direkt nach dem Schlüsselwort ON, ähnlich wie die INNER JOIN-Ausgabe. Wir bezeichnen dieses Problem als innere Reihe .
  • Nicht-NULL-Werte von links Tabelle mit den Null-Gegenstücken von rechts Tisch. Wir bezeichnen dieses Problem als äußere Zeilen .
  • Nicht-NULL-Werte von rechts Tabelle mit den Null-Gegenstücken von links Tisch. Dies ist eine andere Form von äußeren Reihen.
  • Schließlich könnte es eine Kombination aller oben beschriebenen Dinge sein.

Mit dieser Liste können wir sagen, dass OUTER JOIN innere und äußere Zeilen zurückgibt .

  • Inner – weil die genauen Ergebnisse des INNER JOIN sein können zurückgegeben.
  • Äußere – weil die äußeren Zeilen auch sein können zurückgegeben.

Es ist der Unterschied zu INNER JOIN.

INNER JOINS GEBEN NUR INNERE REIHEN ZURÜCK. OUTER JOINS KÖNNEN SOWOHL INNERE ALS AUCH ÄUSSERE ZEILEN ZURÜCKGEBEN

Beachten Sie, dass ich „can be“ und „can also be“ verwendet habe. Es hängt von Ihrer WHERE-Klausel ab (oder ob Sie jemals eine WHERE-Klausel einschließen), ob sie sowohl innere als auch äußere Zeilen zurückgibt.

Aber wie können Sie anhand einer SELECT-Anweisung bestimmen, welche die linke oder rechte Tabelle ist ? Gute Frage!

Woher wissen Sie, welche Tabelle in einem Join die linke oder die rechte ist?

Wir können diese Frage mit Beispielen beantworten:

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

Aus dem obigen Beispiel Table1 ist die linke Tabelle und Table2 ist der richtige Tisch. Nun, lassen Sie uns ein anderes Beispiel haben. Diesmal ist es ein einfacher Multi-Join.

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

Um in diesem Fall zu wissen, was links oder rechts ist, denken Sie daran, dass ein Join an 2 Tabellen funktioniert.

Tabelle1 ist immer noch die linke Tabelle und Table2 ist der richtige Tisch. Dies bezieht sich auf das Verbinden von 2 Tabellen:Tabelle1 und Tabelle2 . Was ist mit dem Beitritt zu Table2? und Tabelle3 ? Tabelle2 wird zur linken Tabelle und Table3 ist die richtige Tabelle.

Wenn wir eine vierte Tabelle hinzufügen, Table3 wird zur linken Tabelle und Table4 ist der richtige Tisch. Aber es endet nicht dort. Wir können eine andere Tabelle mit der Tabelle1 verbinden . Hier ist ein Beispiel:

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

Tabelle1 ist die linke Tabelle und Table5 ist der richtige Tisch. Das Gleiche können Sie auch mit den anderen Tabellen machen.

Okay, gehen wir zurück zur Liste der erwarteten Ausgaben oben. Daraus können wir auch die Outer-Join-Typen ableiten.

Arten von äußeren Verknüpfungen

Es gibt 3 Typen basierend auf den OUTER JOIN-Ausgaben.

LEFT OUTER JOIN (LEFT JOIN)

LEFT JOIN gibt innere Zeilen + Nicht-NULL-Werte von links zurück Tabelle mit den Null-Gegenstücken der rechten Tabelle. Daher ist es ein LEFT JOIN, da die linke Tabelle die dominante der beiden Tabellen innerhalb des Joins ist, die Werte ungleich Null haben.

LEFT OUTER JOIN BEISPIEL 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 

Im obigen Beispiel der Kunde ist die linke Tabelle und SalesOrderHeader ist der richtige Tisch. Das Ergebnis der Abfrage ist 32.166 Datensätze – es umfasst sowohl innere als auch äußere Reihen. Sie können einen Teil davon in Abbildung 1 sehen:

Angenommen, wir möchten nur die äußeren Zeilen oder die Kunden ohne Bestellungen zurückgeben. Fügen Sie dazu eine WHERE-Klausel hinzu, um nur Zeilen mit Nullen aus SalesOrderHeader einzuschließen .

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

Die Ergebnismenge, die ich erhalten habe, ist 701 Datensätze . Alle mögen das null OrderDate aus Abbildung 1.

Wenn ich nur die inneren Zeilen erhalte, ist das Ergebnis 31.465 Datensätze . Ich kann dies tun, indem ich die WHERE-Klausel so ändere, dass sie diese SalesOrderIDs enthält die nicht null sind. Oder ich kann den Join in einen INNER JOIN ändern und die WHERE-Klausel entfernen.

Um zu sehen, ob es aus der Ausgabe des ersten Beispiels ohne die WHERE-Klausel auscheckt, fassen wir die Datensätze zusammen.

Innere Zeilen Äußere Reihen Gesamtzeilen
31.465 Datensätze 701 Datensätze 32.166 Datensätze

Aus den Gesamtzeilen oben mit 32.166 Datensätzen können Sie sehen, dass es mit den ersten Beispielergebnissen übereinstimmt. Dies zeigt auch, wie LEFT OUTER JOIN funktioniert.

LEFT OUTER JOIN BEISPIEL 2

Diesmal ist das Beispiel ein Multi-Join. Beachten Sie auch, dass wir das Schlüsselwort OUTER weglassen.

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

Es wurden 19.996 Datensätze generiert. Sie können sich den Teil der Ausgabe in Abbildung 2 unten ansehen. Die Datensätze mit null AddressLine1 sind äußere Reihen. Darüber befinden sich innere Zeilen.

RIGHT OUTER JOIN (RIGHT JOIN)

RIGHT JOIN gibt innere Zeilen + Nicht-NULL-Werte von rechts zurück Tabelle mit den Null-Gegenstücken der linken Tabelle.

RIGHT OUTER JOIN BEISPIEL 1
-- 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 

Abbildung 3 zeigt 10 von 501 Datensätzen in der Ergebnismenge.

Im obigen Beispiel ProductReview ist die linke Tabelle und das Produkt ist der richtige Tisch. Da dies ein RIGHT OUTER JOIN ist, beabsichtigen wir, die Nicht-NULL-Werte aus der rechten Tabelle einzuschließen.

Die Wahl zwischen LEFT JOIN oder RIGHT JOIN hängt jedoch von Ihnen ab. Wieso den? Weil Sie die Abfrage ausdrücken können, ob LEFT oder RIGHT JOIN, und die gleichen Ergebnisse erhalten. Versuchen wir es mit einem LEFT JOIN.

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

Versuchen Sie, das obige auszuführen, und Sie erhalten das gleiche Ergebnis wie in Abbildung 3. Aber glauben Sie, dass der Abfrageoptimierer sie anders behandeln wird? Finden wir es im Ausführungsplan von beiden in Abbildung 4 heraus.

Wenn Sie neu dabei sind, gibt es einige Überraschungen im Ausführungsplan.

  1. Die Diagramme sehen gleich aus, und sie sind:Probieren Sie einen Showplan vergleichen aus , und Sie sehen denselben QueryPlanHash .
  2. Beachten Sie das obere Diagramm mit einem Merge-Join. Wir haben einen RIGHT OUTER JOIN verwendet, aber SQL Server hat ihn in LEFT OUTER JOIN geändert. Es vertauschte auch den linken und den rechten Tisch. Es macht es gleich der zweiten Abfrage mit dem LEFT JOIN.

Wie Sie jetzt sehen, sind die Ergebnisse die gleichen. Wählen Sie also, welcher der OUTER JOINs bequemer ist.

Warum hat SQL Server den RIGHT JOIN in LEFT JOIN geändert?

Die Datenbank-Engine muss nicht der Art und Weise folgen, wie Sie die logischen Joins ausdrücken. Solange es auf dem schnellsten Weg, den es für möglich hält, korrekte Ergebnisse liefern kann, wird es Änderungen vornehmen. Sogar Verknüpfungen.

Schließen Sie nicht, dass RGHT JOIN schlecht und LEFT JOIN gut ist.

RIGHT OUTER JOIN BEISPIEL 2

Sehen Sie sich das folgende Beispiel an:

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

Es gibt zwei Dinge, die Sie von dieser Abfrage erhalten können, wie Sie in Abbildung 5 unten sehen können:

Die Abfrageergebnisse zeigen Folgendes:

  1. Die nicht zugewiesenen Adressen – diese Datensätze sind diejenigen mit Nullnamen.
  2. Adresstypen ohne Adressen. Archiv-, Rechnungs- und primäre Adresstypen haben keine entsprechenden Adressen. Das sind die Datensätze 817 bis 819.

FULL OUTER JOIN (FULL JOIN)

FULL JOIN gibt eine Kombination aus inneren Zeilen und äußeren Zeilen, links und rechts, zurück.

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

Die Ergebnismenge umfasst 20.815 Datensätze. Wie erwartet handelt es sich um die Gesamtzahl der Datensätze aus der Ergebnismenge von INNER JOIN, LEFT JOIN und RIGHT JOIN.

LEFT und RIGHT JOIN enthalten eine WHERE-Klausel, um nur die Ergebnisse mit Nullen in linken oder rechten Tabellen anzuzeigen.

INNER JOIN LINKSVERBINDUNG
(WObei a.AddressID NULL ist)
RECHTSVERBINDUNG
(WObei P.BusinessEntityID NULL ist)
TOTAL (dasselbe wie FULL JOIN)
18.798 Datensätze 1.198 Datensätze 819 Datensätze 20.815 Datensätze

Beachten Sie, dass der FULL JOIN eine riesige Ergebnismenge aus großen Tabellen erzeugen kann. Verwenden Sie es also nur, wenn Sie es nur brauchen.

Praktische Anwendungen von OUTER JOIN

Wenn Sie immer noch zögern, wann Sie OUTER JOIN verwenden können und sollten, finden Sie hier einige Ideen.

Outer Joins, die sowohl innere als auch äußere Zeilen ausgeben

Beispiele können sein:

  • Alphabetische Liste bezahlter und unbezahlter Kundenbestellungen.
  • Alphabetische Liste der Mitarbeiter mit Verspätung oder ohne Verspätung.
  • Eine Liste der Versicherungsnehmer, die ihre letzten Versicherungspolicen verlängert und nicht verlängert haben.

Äußere Verknüpfungen, die nur äußere Zeilen ausgeben

Beispiele sind:

  • Alphabetische Liste der Mitarbeiter ohne Verspätungsnachweis für die Null-Verspätung-Prämie
  • Liste der Gebiete ohne Kunden
  • Liste von Handelsvertretern ohne Verkäufe eines bestimmten Produkts
  • Ergebnisse aus fehlenden Werten abrufen, z. B. Daten ohne Kundenaufträge in einem bestimmten Zeitraum (Beispiel unten)
  • Knoten ohne Kind in einer Eltern-Kind-Beziehung (Beispiel unten)

Ergebnisse aus fehlenden Werten abrufen

Angenommen, Sie müssen einen Bericht erstellen. Dieser Bericht muss für jeden Monat in einem bestimmten Zeitraum die Anzahl der Tage enthalten, an denen keine Bestellungen eingegangen sind. Der SalesOrderHeader in AdventureWorks enthält die Bestelldaten , aber sie haben keine Termine ohne Bestellungen. Was können Sie tun?

1. Erstellen Sie eine Tabelle aller Daten in einem Zeitraum

Ein Beispielskript unten erstellt eine Tabelle mit Daten für das gesamte Jahr 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. Verwenden Sie LEFT JOIN, um die Tage ohne Bestellungen auszugeben
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]

Der obige Code zählt die Anzahl der Tage, an denen keine Bestellungen getätigt wurden. SalesOrderHeader enthält die Termine mit Bestellungen. Daher zählen im Join zurückgegebene Nullen als Tage ohne Bestellungen.

Wenn Sie in der Zwischenzeit die genauen Daten wissen möchten, können Sie die Zählung und Gruppierung entfernen.

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

Oder wenn Sie Bestellungen in einem bestimmten Zeitraum zählen und sehen möchten, welches Datum keine Bestellungen aufweist, gehen Sie wie folgt vor:

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

Der obige Code zählt Bestellungen für Februar 2014. Siehe das Ergebnis:

Warum wird der 3. Februar 2014 hervorgehoben? In meiner Kopie von AdventureWorks gibt es für dieses Datum keine Verkaufsaufträge.

Beachten Sie nun COUNT(soh.OrderDate) im Code. Später klären wir, warum das so wichtig ist.

Kinderlose Knoten in Eltern-Kind-Beziehungen erhalten

Manchmal müssen wir die Knoten ohne Kind in einer Eltern-Kind-Beziehung kennen.

Lassen Sie uns die Datenbank verwenden, die ich in meinem Artikel über HierarchyID verwendet habe. Sie müssen Knoten ohne Kinder in einer Eltern-Kind-Beziehungstabelle mit einem Self-Join abrufen.

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 

Vorbehalte bei der Verwendung von OUTER JOIN

Da ein OUTER JOIN wie ein INNER JOIN innere Zeilen zurückgeben kann, kann er verwirren. Auch Leistungsprobleme können sich einschleichen. Beachte also die 3 Punkte unten (ich komme von Zeit zu Zeit darauf zurück – ich werde nicht jünger, also vergesse ich es auch).

Filtern der rechten Tabelle in einem LEFT JOIN mit einem Nicht-Null-Wert in der WHERE-Klausel

Es kann ein Problem sein, wenn Sie einen LEFT OUTER JOIN verwendet haben, aber die rechte Tabelle mit einem Wert ungleich Null in der WHERE-Klausel gefiltert haben. Der Grund dafür ist, dass es funktional einem INNER JOIN entspricht. Betrachten Sie das folgende Beispiel:

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 

Untersuchen wir anhand des obigen Codes die beiden Tabellen:Person und BusinessEntityAddress . Die Person ist die linke Tabelle und BusinessEntityAddress ist die richtige Tabelle.

LEFT JOIN wird verwendet, daher wird eine BusinessEntityID von Null angenommen irgendwo in BusinessEntityAddress . Beachten Sie hier die WHERE-Klausel. Es filtert die richtige Tabelle mit AddressTypeID =5. Es verwirft vollständig alle äußeren Zeilen in BusinessEntityAddress .

Dies kann einer der folgenden sein:

  • Der Entwickler testet etwas im Ergebnis, hat aber vergessen, es zu entfernen.
  • INNER JOIN war beabsichtigt, aber aus irgendeinem Grund wurde LEFT JOIN verwendet.
  • Der Entwickler versteht den Unterschied zwischen LEFT JOIN und INNER JOIN nicht. Er geht davon aus, dass eines der beiden funktionieren wird, und es spielt keine Rolle, da die Ergebnisse in diesem Fall dieselben sind.

Jeder der 3 oben genannten ist schlecht, aber der dritte Eintrag hat eine andere Implikation. Vergleichen wir den obigen Code mit dem INNER JOIN-Äquivalent:

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

Abgesehen vom Join-Typ ähnelt er dem vorherigen Code. Das Ergebnis ist auch dasselbe, aber Sie sollten die logischen Lesevorgänge in STATISTICS IO:

beachten

In Abbildung 7 stammen die ersten E/A-Statistiken aus der Verwendung von INNER JOIN. Die Gesamtzahl der logischen Lesevorgänge beträgt 177. Die zweiten Statistiken gelten jedoch für LEFT JOIN mit einem höheren Wert für logische Lesevorgänge von 223. Daher erfordert die falsche Verwendung von LEFT JOIN in diesem Beispiel mehr Seiten oder Ressourcen von SQL Server. Daher wird es langsamer ausgeführt.

Imbiss

Wenn Sie beabsichtigen, innere Zeilen auszugeben, verwenden Sie INNER JOIN. Andernfalls filtern Sie die rechte Tabelle in einem LEFT JOIN nicht mit einem Wert ungleich Null. In diesem Fall erhalten Sie eine langsamere Abfrage als bei Verwendung von INNER JOIN.

BONUS-TIPP :Diese Situation tritt auch bei einem RIGHT JOIN auf, wenn die linke Tabelle mit einem Nicht-Null-Wert gefiltert wird.

Unsachgemäße Verwendung von Join-Typen in einem Multi-Join

Angenommen, wir möchten alle abrufen die Lieferanten und die Anzahl der Produktbestellungen für jeden. Hier ist der Code:

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 

Der obige Code gibt sowohl die Lieferanten mit Bestellungen als auch die ohne Bestellungen zurück. Abbildung 8 zeigt den tatsächlichen Ausführungsplan des obigen Codes.

Wenn man bedenkt, dass jede Bestellung ein garantiertes Bestelldetail hat, wäre ein INNER JOIN besser. Aber ist es wirklich so?

Lassen Sie uns zuerst den modifizierten Code mit dem INNER JOIN haben.

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 

Denken Sie daran, dass die obige Anforderung „alle“ Anbieter besagt. Da wir den LEFT JOIN im vorherigen Code verwendet haben, erhalten wir Lieferanten ohne Bestellungen zurück. Das liegt an der null PurchaseOrderID .

Wenn Sie den Join in einen INNER JOIN ändern, werden alle leeren PurchaseOrderIDs. verworfen Außerdem werden alle VendorIDs mit Null gelöscht vom Anbieter Tisch. Tatsächlich wird es zu einem INNER JOIN.

Ist das eine richtige Annahme? Der Ausführungsplan wird die Antwort offenbaren:

Wie Sie sehen, wurden alle Tabellen mit INNER JOIN verarbeitet. Daher ist unsere Annahme richtig. Aber das Schlimmste ist, dass die Ergebnismenge jetzt falsch ist, weil die Lieferanten ohne Bestellungen nicht enthalten waren.

Imbiss

Wenn Sie wie im vorherigen Fall einen INNER JOIN beabsichtigen, verwenden Sie ihn. Aber Sie wissen, was zu tun ist, wenn Sie auf eine Situation wie die hier stoßen.

In diesem Fall verwirft ein INNER JOIN alle äußeren Zeilen bis zur obersten Tabelle in der Beziehung. Auch wenn Ihr anderer Join ein LEFT JOIN ist, spielt es keine Rolle. Das haben wir in den Ausführungsplänen bewiesen.

Falsche Verwendung von COUNT() in Outer Joins

Erinnern Sie sich an unseren Beispielcode, der die Anzahl der Bestellungen pro Datum und das Ergebnis in Abbildung 6 zählt?

Hier klären wir, warum der 03.02.2014 hervorgehoben ist und seine Beziehung zu COUNT(soh.OrderDate) .

Wenn Sie versuchen, COUNT(*) zu verwenden, wird die Anzahl der Bestellungen für dieses Datum zu 1, was falsch ist. An diesem Datum liegen keine Bestellungen vor. Wenn Sie also COUNT() mit einem OUTER JOIN verwenden, verwenden Sie die richtige Spalte zum Zählen.

In unserem Fall soh.OrderDate kann null sein oder nicht. Wenn es nicht null ist, schließt COUNT() die Zeile in die Zählung ein. COUNT(*) lässt alles zählen, einschließlich der Nullen. Und am Ende falsche Ergebnisse.

Die OUTER JOIN-Takeaways

Fassen wir die Punkte zusammen:

  • OUTER JOIN kann sowohl innere als auch äußere Zeilen zurückgeben. Innere Zeilen sind das Ergebnis, das dem Ergebnis von INNER JOIN ähnelt. Äußere Zeilen sind die Nicht-Null-Werte mit ihren Null-Gegenstücken basierend auf der Join-Bedingung.
  • OUTER JOIN kann LEFT, RIGHT oder FULL sein. Wir hatten Beispiele für jeden.
  • Die von OUTER JOIN zurückgegebenen äußeren Zeilen können auf verschiedene praktische Weise verwendet werden. Wir hatten Ideen, wann Sie dieses Zeug verwenden können.
  • Wir hatten auch Vorbehalte bei der Verwendung von OUTER JOIN. Beachten Sie die 3 oben genannten Punkte, um Fehler und Leistungsprobleme zu vermeiden.

Der letzte Teil dieser Serie behandelt CROSS JOIN. Also, bis dahin. Und wenn Ihnen dieser Beitrag gefällt, teilen Sie etwas Liebe, indem Sie auf die Schaltflächen der sozialen Medien klicken. Viel Spaß beim Programmieren!