Łączenie danych z wielu tabel
Łączenie danych w MS SQL, czyli operacja JOIN, pozwala na łączenie wierszy z różnych tabel na podstawie określonych kryteriów. W SQL istnieją różne rodzaje JOIN, które określają, jakie wiersze zostaną uwzględnione w wynikowym zbiorze danych.
- JOIN (INNER JOIN): Zwraca wiersze, które mają pasujące wartości w obu tabelach.
- LEFT JOIN (LEFT OUTER JOIN): Zwraca wszystkie wiersze z lewej tabeli (tabeli zdefiniowanej po lewej stronie zapytania JOIN), a także pasujące wiersze z prawej tabeli. Jeśli w prawej tabeli nie ma pasujących wartości, to dla tych wierszy zostaną zwrócone wartości NULL.
- RIGHT JOIN (RIGHT OUTER JOIN): Jest odwrotnością LEFT JOIN. Zwraca wszystkie wiersze z prawej tabeli (tabeli zdefiniowanej po prawej stronie zapytania JOIN), a także pasujące wiersze z lewej tabeli. Jeśli w lewej tabeli nie ma pasujących wartości, to dla tych wierszy zostaną zwrócone wartości NULL.
- FULL JOIN (FULL OUTER JOIN): Zwraca wiersze, które mają pasujące wartości w jednej z tabel. Wszystkie wiersze z obu tabel są zwracane, a jeśli nie ma pasujących wartości, to dla nich zostaną zwrócone wartości NULL.
Zobaczmy jakie rezultaty zwrócą zapytania wykorzystujące róźne typy JOIN'ów
SELECT *
FROM SalesLT.SalesOrderHeader AS soh
INNER JOIN SalesLT.Customer AS c ON soh.CustomerID = c.CustomerID;
SELECT *
FROM SalesLT.Customer AS c
LEFT JOIN SalesLT.CustomerAddress AS ca ON c.CustomerID = ca.CustomerID;
SELECT *
FROM SalesLT.CustomerAddress AS ca
RIGHT JOIN SalesLT.Address AS a ON ca.AddressID = a.AddressID;
SELECT *
FROM SalesLT.Customer AS c
FULL JOIN SalesLT.CustomerAddress AS ca ON c.CustomerID = ca.CustomerID;
W każdym z tych zapytań wybieramy różne zestawy kolumn z różnych tabel i łączymy je za pomocą różnych rodzajów JOIN, aby uzyskać różne zestawy wyników w zależności od potrzeb.
Aliasy
Aliasy w JOIN to nadane krótkie nazwy tabelom w zapytaniach SQL. Pozwalają one na zwięzłe odwoływanie się do tych elementów wewnątrz zapytania, co ułatwia czytelność kodu i redukuje powtarzalność.
W przypadku klauzuli JOIN, aliasy są szczególnie użyteczne, gdy łączymy wiele tabel, ponieważ pozwala to uniknąć długich nazw tabel i sprawia, że zapytanie jest bardziej czytelne.
Na przykład, zamiast używać pełnych nazw tabel, możemy nadawać im aliasy i odwoływać się do nich za pomocą tych aliasów. Przykładowo:
SELECT soh.SalesOrderID, soh.OrderDate, sod.LineTotal
FROM SalesLT.SalesOrderHeader soh
JOIN SalesLT.SalesOrderDetail as [sod] on sod.SalesOrderID = soh.SalesOrderID
W tym przykładzie używamy aliasów do skrócenia długich nazw tabel i ułatwienia odwoływania się do kolumn w zapytaniu.
-
SalesLT.SalesOrderHeader soh: Nadajemy tabeliSalesOrderHeaderaliassoh. Dzięki temu możemy odwoływać się do kolumn z tej tabeli używając krótszego aliasusoh, na przykładsoh.SalesOrderIDisoh.OrderDate. -
SalesLT.SalesOrderDetail sod: Nadajemy tabeliSalesOrderDetailaliassod. Podobnie jak powyżej, używamy tego aliasu, aby odwoływać się do kolumn z tabeliSalesOrderDetail, takich jaksod.LineTotal. -
W klauzuli JOIN używamy aliasów w warunku łączenia tabel (
sod.SalesOrderID = soh.SalesOrderID). Dzięki temu wiadomo, które kolumny są z których tabel, nawet jeśli używamy krótszych aliasów.
Wpływ typu relacji na wynik klauzuli JOIN
W relacyjnych bazach danych, możemy definiować relacje pomiędzy tabelami w stosunku:
-
jeden do jednego
-
jeden do wielu
-
wiele do wielu
W zależności od typu relacji, wynik klauzuli JOIN może być różny. W przypadku relacji jeden do jednego, wynik klauzuli JOIN będzie zawierał tylko jedno połączenie pomiędzy tabelami. W przypadku relacji jeden do wielu, jak i wiele do wielu, wynik klauzuli JOIN będzie zawierał wiele połączeń pomiędzy tabelami.
Przykładowo w relacji jeden do jeden, między tabelami SalesLT.SalesOrderHeader, a SalesLT.Address istnieje tylko jedno połączenie - każde zamówienie ma przypisany jeden adres dostawy BillToAddressID.
SELECT sod.SalesOrderNumber, a.*
FROM SalesLT.SalesOrderHeader sod
JOIN SalesLT.Address a on sod.BillToAddressID = a.AddressID
W relacji jeden do wielu, między tabelami SalesLT.Product, a SalesLT.ProductModel istnieje wiele połączeń, jako że jeden model produktu, może mieć np. kilka róźnych rozmiarów.
SELECT p.ProductID, p.ProductModelID, pm.Name [ProductModelName], p.Name [ProductName]
FROM SalesLT.Product p
JOIN SalesLT.ProductModel pm on pm.ProductModelID = p.ProductModelID
W relacji wiele do wielu, potrzeba będzie dołączenia tzw. tabeli łączącej, która przechowuje informacje o powiązaniach wierszy z dwóch róźnych tabel
SELECT c.CustomerID, a.*
FROM SalesLT.Customer c
JOIN SalesLT.CustomerAddress ca on ca.CustomerID = c.CustomerID
JOIN SalesLT.Address a on a.AddressID = ca.AddressID
Łączenie wielu tabel
Klauzulą JOIN jesteśmy w stanie połączyć wiersze z dwóch lub więcej tabel na podstawie wspólnego klucza. W przypadku większej ilości tabel, klauzula JOIN może być wielokrotnie zagnieżdżana. W ten sposób możemy, albo dołączyć wiersze do głównej tabeli, albo do jednej z tabel dołączonych JOIN'em.
Przykładowo:
SELECT soh.SalesOrderID, sod.UnitPriceDiscount, p.Name AS ProductName, sod.OrderQty, sod.UnitPrice
FROM SalesLT.SalesOrderHeader AS soh
JOIN SalesLT.SalesOrderDetail AS sod ON soh.SalesOrderID = sod.SalesOrderID
JOIN SalesLT.Product AS p ON sod.ProductID = p.ProductID
WHERE sod.UnitPriceDiscount > 0
W tym przykładzie wykonujemy zapytanie, które łączy trzy tabele: SalesOrderHeader, SalesOrderDetail i Product, aby uzyskać informacje o zamówieniach, ich szczegółach i produktach.
-
W klauzuli SELECT wybieramy konkretne kolumny z każdej tabeli:
soh.SalesOrderID(identyfikator zamówienia),sod.UnitPriceDiscount(rabat na cenę jednostkową),p.Name AS ProductName(nazwa produktu),sod.OrderQty(ilość zamówionego produktu) orazsod.UnitPrice(cena jednostkowa produktu). -
W klauzuli FROM wskazujemy tabelę
SalesOrderHeaderjakosoh. -
Następnie używamy klauzuli JOIN, aby dołączyć tabelę
SalesOrderDetailjakosodna podstawie identyfikatora zamówienia (soh.SalesOrderID = sod.SalesOrderID). -
Kolejnym krokiem jest ponowne użycie klauzuli JOIN, aby dołączyć tabelę
Productjakopna podstawie identyfikatora produktu (sod.ProductID = p.ProductID). -
Klauzula WHERE służy do filtrowania wyników. Tutaj wybieramy tylko te wiersze, gdzie wartość
sod.UnitPriceDiscountjest większa od zera, co oznacza, że został zastosowany rabat na cenę jednostkową produktu.
Podsumowując, to zapytanie zwraca informacje o zamówieniach, które miały zastosowany rabat na cenę jednostkową produktu, wraz z szczegółowymi danymi dotyczącymi tych zamówień i zamówionych produktów.