> For the complete documentation index, see [llms.txt](https://m105.ict-bz.ch/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://m105.ict-bz.ch/tag-2/join.md).

# DQL - Join

![](/files/-MF4cggHjQygGbb4vV0D)

## Tabellen miteinander verknüpfen

Verknüpfung von zwei Tabellen kann, muss aber nicht über die *Primär-/Fremdschlüssel-Beziehung* erfolgen. \
Die meisten Joins sind EQUI JOINS. Darin werden zwei Tabellen über übereinstimmende Spalten verknüpft. Als Join-Operator wird ein = verwendet. \
Beispiel: Rechnungs- und Kundentabelle werden über die Kundennummer, die in beiden Tabellen enthalten ist, verknüpft.

Die seltene Sonderform eines Joins ist der NONEQUI JOIN. Bei Nonequi Joins gibt es keine direkt aufeinander referenzierenden Spalten. Als Join-Operator wird kein = verwendet, sondern meist kommt ein BETWEEN … AND … zum Einsatz.

### ⚡️ Ausprobieren

Öffne diese Beispiel-Datenbank in einem neuen Fenster:\
<https://www.w3schools.com/sql/trysqlserver.asp?filename=trysql_func_sqlserver_concat>

Hier kannst du direkt im Browser SQL Statements ausprobieren. Probiere die Beispiele hier mit einem  \
⚡️-Symbol aus.

## Die JOIN Arten

Angenommen, du hast die folgenden zwei Tabellen, welche je eine Spalte haben:

```
A      B
-      -
1      3
2      4
3      5
4      6
```

Beachte, dass die Einträge 1 und 2 nur bei A, 5 und 6 nur bei B vorhanden sind. 3 und 4 gibt es bei beiden.\
Folgende Tabelle erklärt, wie die Ausgabe aussehen würde, wenn diese zwei Tabellen mit den verschiedenen JOIN Arten verknüpft werden:

| JOIN-Art           | Bild                                                                | Resultierende Tabelle |                                                       |                           |                           |                           |                           |                           |                 |
| ------------------ | ------------------------------------------------------------------- | --------------------- | ----------------------------------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | --------------- |
| `INNER JOIN`       | <img src="/files/-MF68BqaJSTG9RZ8riub" alt="" data-size="original"> | <p>   <code>a         | b</code>   <br><code>-----+-----</code><br>   <code>3 | 3</code> <br>   <code>4   | 4</code></p>              |                           |                           |                           |                 |
| `LEFT OUTER JOIN`  | <img src="/files/-MF68W6wYMHEV-Kius4C" alt="" data-size="original"> | <p>   <code>a         | b</code>   <br><code>-----+-----</code><br>   <code>1 | null</code><br>   <code>2 | null</code><br>   <code>3 | 3</code>   <br>   <code>4 | 4</code>   </p><p></p>    |                           |                 |
| `RIGHT OUTER JOIN` | <img src="/files/-MF68uLNE4B4Z-Qc4Xrn" alt="" data-size="original"> | <p>   <code>a         | b</code>  <br><code>-----+-----</code><br>   <code>3  | 3</code>  <br>   <code>4  | 4</code>  <br><code>null  | 5</code>  <br><code>null  | 6</code>  </p>            |                           |                 |
| `FULL OUTER JOIN`  | <img src="/files/-MF69He5lJOs9DBtUdQb" alt="" data-size="original"> | <p>   <code>a         | b</code>   <br><code>-----+-----</code><br>   <code>1 | null</code><br>   <code>2 | null</code><br>   <code>3 | 3</code>   <br>   <code>4 | 4</code>   <br><code>null | 6</code>   <br><code>null | 5</code>   </p> |

## INNER JOIN

* `JOIN`-Bedingung in eigener Klausel
* `WHERE`-Klausel wird reingehalten&#x20;
* `JOIN`-Typ widerspiegelt sich in JOIN-Ausdruck

```sql
SELECT tab1.spalte_1, tab2.spalte_2 
FROM tab1 
INNER JOIN tab2 ON tab1.spalte_x = tab2.spalte_y
WHERE . . .
```

#### ⚡️ Ausprobieren

{% tabs %}
{% tab title="Aufgabe" %}

1. Erstelle ein SQL-Statement, welches mittels `INNER JOIN` die Tabellen `Orders` und `Customers` über die `CustomerID` verknüpft. Gib dabei mindestens `OrderID`, `CustomerName` und `OrderDate` aus.
2. Gib Produktname, Preis und den Namen des Herstellers aus von allen Produkten, die teurer als 100$ sind.
   {% endtab %}

{% tab title="Lösung" %}

```sql
-- 1. Bestellung und dazugehöriger Kundenname
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders
INNER JOIN Customers ON Customers.CustomerID = Orders.CustomerID;

-- 2. Hersteller und Preis der teuersten Produkte
SELECT Products.ProductName, Products.Price, Suppliers.SupplierName
FROM Products 
INNER JOIN Suppliers ON Products.SupplierID = Suppliers.SupplierID
WHERE Price > 100;
```

{% endtab %}
{% endtabs %}

### JOIN über WHERE-Klausel

Es ist auch möglich, zwei Tabellen über eine einfache WHERE-Klausel zu verbinden. Dies ist aber weniger performant. Es wird vor allem bei ORACLE eingesetzt, da vor Version 9i nur diese Möglichkeit bestand.

```sql
SELECT tab1.spalte_1, tab2.spalte_2 
FROM tab1, tab2 
WHERE tab1.spalte_x = tab2.spalte_y;
```

Weitere Bedingungen werden mit AND ergänzt Tabellennamen müssen bei Namensgleichheit von Spalten angegeben werden. Tabellennamen sollten vor allen Spaltennamen stehen.

#### ⚡️ Ausprobieren

{% tabs %}
{% tab title="Aufgabe" %}
Löse die Aufgaben aus INNER JOIN mittels eines einfachen JOIN über WHERE-Klausel.
{% endtab %}

{% tab title="Lösung" %}

```sql
-- 1. Bestellung und dazugehöriger Kundenname
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders, Customers
WHERE Customers.CustomerID = Orders.CustomerID;

-- 2. Hersteller und Preis der teuersten Produkte
SELECT Products.ProductName, Products.Price, Suppliers.SupplierName
FROM Products, Suppliers
WHERE Products.SupplierID = Suppliers.SupplierID
AND Price > 100;
```

{% endtab %}
{% endtabs %}

## Tabellen-Alias

Wie du in den letzten zwei Beispielen sicher bemerkt hast, muss man so ziemlich viel schreiben. Um das etwas abzukürzen, kann man den Tabellen einen Alias geben, welcher dann in dieser Abfrage verwendet werden kann.

Dadurch kann man einfacher und schneller SQL-Statements schreiben, die übersichtlicher sind und dabei passieren auch noch weniger Schreibfehler.

```sql
SELECT a.spalte_1, b.spalte_2 
FROM tab1 AS a, tab2 AS b
WHERE a.spalte_x = b.spalte_y;

-- Variante ohne AS
SELECT a.spalte_1, b.spalte_2 
FROM tab1 a 
INNER JOIN tab2 b ON a.spalte_x = b.spalte_y;
```

#### ⚡️ Ausprobieren

Passe die vorigen ⚡️Ausprobieren Beispiele an und verwende Tabellen-Aliasse.

## OUTER JOIN

Syntaxmässig sind OUTER JOINs gleich wie INNER JOINs. Einfach, dass Statt `INNER` da `LEFT OUTER`, `RIGHT OUTER` oder `FULL OUTER` steht.

#### ⚡️ Ausprobieren

Passe die vorigen ⚡️Ausprobieren Beispiele an und verwende die verschiedenen `OUTER JOIN`-Arten.

## JOINS mit mehr als zwei Tabellen

#### ⚡️ Ausprobieren

{% tabs %}
{% tab title="Aufgabe" %}
Liste alle Angestellten (Vorname und Nachname) auf und dazu die Namen aller Kunden, für welche die Angestellten schon einmal eine Bestellung bearbeitet haben.
{% endtab %}

{% tab title="Lösung" %}

```sql
-- Lösung mit JOIN
SELECT DISTINCT Employees.FirstName, Employees.LastName, Customers.ContactName
FROM Employees 
    INNER JOIN (Orders 
        INNER JOIN Customers 
        ON Orders.CustomerID = Customers.CustomerID
    )
    ON Employees.EmployeeID = Orders.EmployeeID
ORDER BY Employees.FirstName, Employees.LastName, Customers.ContactName;


-- Alternative Lösung mit WHERE (KEIN LEFT/RIGHT JOIN möglich)
SELECT DISTINCT 
    Employees.FirstName, Employees.LastName, Customers.ContactName
FROM 
    Employees , Orders, Customers 
WHERE 
    Orders.CustomerID = Customers.CustomerID
    AND Employees.EmployeeID = Orders.EmployeeID
ORDER BY Employees.FirstName, Employees.LastName, Customers.ContactName;

```

{% endtab %}
{% endtabs %}

## Weitere JOIN Arten

* `CROSS JOIN`
  * Beim `CROSS JOIN` handelt es sich um ein **Kreuzprodukt (kartesisches Produkt)**
  * Es werden alle möglichen Kombinationen gebildet (jeder mit jedem)&#x20;
  * In der Regel ungewollt!&#x20;
  * Wird z.B. zum Generieren von Testdaten verwendet
* `SELF JOIN` (rekursiver `JOIN`)
  * `JOIN` einer Tabelle mit sich selbst&#x20;
  * Dient zur Abbildung von Hierarchien&#x20;
  * Dieselbe Tabelle zweimal mit unterschiedlichem Alias verwenden

#### ⚡️ Ausprobieren

{% tabs %}
{% tab title="Aufgabe" %}

1. Zeige mittels rekursivem `JOIN` alle Mitarbeitenden der Northwind-Datenbank an (ID, Vorname, Nachname) und zu jedem den Namen des Vorgesetzten (ReportsTo)
2. Finde den CEO (die Person, welche keinen weiteren Vorgesetzten hat).
   {% endtab %}

{% tab title="Lösung" %}

```sql
-- 1. Mitarbeitende mit Vorgesetzten
SELECT MA.EmployeeID, MA.FirstName, MA.LastName, 
       Chefs.FirstName + ' ' + Chefs.LastName AS Vorgesetzter 
FROM Employees AS MA, Employees AS Chefs 
WHERE MA.ReportsTo = Chefs.EmployeeID;
  
-- 2. Finde den CEO!
SELECT MA.FirstName + ' ' + MA.LastName AS CEO
FROM dbo.Employees AS MA 
LEFT JOIN dbo.Employees AS Chefs 
    ON MA.ReportsTo = Chefs.EmployeeID 
WHERE Chefs.EmployeeID IS NULL;
```

{% endtab %}
{% endtabs %}

## 💡 Eigene Aufgabe

* Überlege dir eine Aufgabe für eine Abfrage in der Northwind Datenbank.
* Gebe die Aufgabe (noch ungelöst) morgen deinem Instruktor ab.
* Die Aufgaben werden dann willkürlich zum lösen an die Klasse verteilt.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://m105.ict-bz.ch/tag-2/join.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
