JOIN Operacja JOIN jest najprawdopodobniej najczęściej używaną operacją w jakiejkolwiek bazie danych. Nie jest to niczym zaskakującym, ponieważ system został  stworzony w taki sposób ,aby wyrażać związki pomiędzy rekordami bez  dublowania informacji.

Nikt nie trzyma wszystkiego w jednej tabelce, gdzie pewne kolumny  przechowywałyby powtarzające się wartości.

Dosyć jednak tego wstępu . W tym wpisie opiszę wszystkie operację JOIN, jakie oferuje nam system bazo danowych. Wpis tyczy SQL Server-a ,ale tę wiedzę łatwo przelać do każdego innego systemu.

Standardowo utworzymy przykładowe tabelki i uzupełnimy je danymi.

CREATE TABLE [dbo].[Region](
	[RegionId] [int] NOT NULL,
	[Name] [varchar](50) NOT NULL,
 CONSTRAINT [PK_Region] PRIMARY KEY CLUSTERED 
(
	[RegionId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]

CREATE TABLE [dbo].[Country](
	[CountryId] [int] NOT NULL,
	[Name] [varchar](50) NOT NULL,
	[RegionId] [int] NULL,
 CONSTRAINT [PK_Country] PRIMARY KEY CLUSTERED 
(
	[CountryId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]


ALTER TABLE [dbo].[Country]  WITH CHECK ADD  CONSTRAINT [FK_Country_Region] FOREIGN KEY([RegionId])
REFERENCES [dbo].[Region] ([RegionId])
GO

ALTER TABLE [dbo].[Country] CHECK CONSTRAINT [FK_Country_Region]
GO

Tabelka Region zawiera tylko ID i nazwę regionu. W tej tabelce będą znajdować się kontynenty naszego świata.

Tabelka Country zawiera ID , nazwę kraju oraz id regionu, które jest kluczem obcym. Warto zaznaczyć ,że id regionu może być puste. Dany kraj może nie posiadać regionu.

image

Uzupełnimy obie tabelki danymi.

INSERT INTO [dbo].[Region]
           ([RegionId]
           ,[Name])
     VALUES
           (1,'Europe'),(2,'Asia'),(3,'Africa'),
           (4,'South America'),(5,'North America'),(6,'Australia')


INSERT INTO [dbo].[Country]
           ([CountryId]
           ,[Name]
           ,[RegionId])
     VALUES
           (1,'Poland',1),(2,'Japan',2),
           (3,'Algeria',3),(4,'Argentina',4),
           (5,'New Zealand',NULL),(6,'Federated States of Micronesia',NULL)

Na co warto zwrócić uwagę:

  • Regiony "5,North America" oraz "6,Australia" nie są powiązane z żadnym krajem.
  • Kraje “5,'New Zealand" i "6,'Federated States of Micronesia'" nie mają swojego regionu.

Ten Join zwraca  wiersze, w których  obie wartość  w obydwu tabelkach się zgodziły.kolka-01

Mówiąc łatwiej ten JOIN, zwraca część wspólną zbiorów danych, z którymi łączymy obie tabele.

SELECT t1.Name AS Country,t2.Name AS Region FROM dbo.Country AS t1
INNER JOIN dbo.Region AS t2 ON t2.RegionId = t1.RegionId

Wyniki tego zapytania powinien zwrócić tylko kraje  powiązane z regionami, jak i  regiony, które mają przypisane  kraje. Rekordy zostały powiązane po RegionId.

Kraje niemające RegionID zostały zignorowane. Podobny los trafił na regiony, które nie zostały przypisane do żadnego kraju.

image

Pisząc tylko JOIN wykonujemy operację “INNER JOIN”?

LEFT OUTER JOIN

OUTER JOIN ma ,aż trzy różne metody .Oto pierwsza z nich.

Ten JOIN zwraca wszystkie wiersze tabelki po lewej plus wiersze, które mają uzupełnienie z prawej tabelki.

kolka-02

Jeśli nie ma żadnych wartości odpowiadającej prawej tabelce, to jest zwracana wartość NULL.

SELECT t1.Name,t2.Name FROM dbo.Country AS t1
LEFT OUTER JOIN dbo.Region AS t2 ON t2.RegionId = t1.RegionId

Jak widać  zostały zwrócone wszystkie kraje ,a w przypadku braku powiązania występuje wartość NULL.

image

Lewa tabelka to ta, do której odwołujemy się w klauzurze FROM przy SELEC-ie.

RIGHT OUTER JOIN

Ten JOIN zwraca wszystkie wiersze z prawej tabelki plus wiersze powiązane z tabelką po lewej.

RIGHT OUTER JOIN

Analogicznie do poprzedniego przykładu, gdy nie ma powiązania wartości danej kolumny w jej miejscu, to wstępuje wartość NULL.

SELECT t1.Name AS Country,t2.Name AS Region FROM dbo.Country AS t1
RIGHT OUTER JOIN dbo.Region AS t2 ON t2.RegionId = t1.RegionId

W tym przypadku zostały zwrócone wszystkie regiony.

image

Prawa tabelka to ta, do której się odwołujemy w klauzurze JOIN.

FULL OUTER JOIN

Ten JOIN jest kombinacją lewego i prawego OUTER JOIN-a.

Zwraca ona wszystkie wiersze z obu tabel bez względu na to czy powiązanie wystąpiło, czy nie.

kolka-04

Gdy nie ma powiązania po któreś stronie w jego miejsce, to jest wstawiona wartość NULL.

SELECT t1.Name AS Country,t2.Name AS Region FROM dbo.Country AS t1
FULL OUTER JOIN dbo.Region AS t2 ON t2.RegionId = t1.RegionId

Jak widać, zostały zwrócone wszystkie kraje i wszystkie regiony.

image

CROSS JOIN

JOIN kartezjański nie potrzebuje żadnego warunku do powiązania. Rezultatem tego JOIN-a są wiersze pomnożone przez liczbę rekordów z obu tabel.

SELECT t1.Name AS Country,t2.Name AS Region FROM dbo.Country AS t1
CROSS JOIN dbo.Region AS t2

--Alternatywnie
SELECT t1.Name AS Country,t2.Name AS Region 
FROM dbo.Country AS t1, dbo.Region AS t2

Nie widzę praktycznego zastosowania tego JOIN-a.

image

image

Z NULL-em

To były wszystkie operację JOIN, jakie oferuję SQL.

Jedno nie są to  wszystkie kombinację zbiorów, jakie można uzyskać wyniku operacji JOIN.

Czasami programiści potrzebuje  wierszy niepowiązanych wcale.

kolka-05

Przykładowo, jeśli chce pobrać wszystkie kraje, które nie mają przypisanego regionu to robię to w ten sposób.

SELECT t1.Name AS Country,t2.Name AS Region FROM dbo.Country AS t1
LEFT OUTER JOIN dbo.Region AS t2 ON t2.RegionId = t1.RegionId
WHERE t2.RegionId IS NULL

image

Można zadać sobie pytanie, czy w takim wypadku JOIN w ogóle nam jest potrzebny. Zapytanie poniżej zwróci na te same rekordy.

SELECT [CountryId]
      ,[Name]
      ,[RegionId]
  FROM [dbo].[Country] WHERE RegionID IS NULL

Skoro i tak nas nie interesują powiązane wiersze to po co w ogóle JOIN-ujemy w takim wypadku. Po samym pustym ID regionu jesteśmy w stanie to ustalić.

Sprawa wygląda inaczej w RIGHT OUTER JOIN.

RIGHT.png

Teraz nie mam żadnej informacji o uzupełnieniu w samej tabelce Regiony . Muszę wykonać operację JOIN z tabelką Country, by to sprawdzić.

SELECT t1.Name AS Country,t2.Name AS Region FROM dbo.Country AS t1
RIGHT OUTER JOIN dbo.Region AS t2 ON t2.RegionId = t1.RegionId
WHERE t1.RegionId IS NULL

image

OPPOSITE INNER JOIN

W terminologii SQL nie ma definicji odwrotności INNER JOIN-a ,ale używając klauzury WHERE oraz FULL OUTER JOIN można uzyskać taki efekt.

To zapytanie zwróci wyniki z obu tabel, gdzie kolumny nie zostały ze sobą powiązane.

kolka-07

SELECT t1.Name AS Country,t2.Name AS Region FROM dbo.Country AS t1
FULL OUTER JOIN dbo.Region AS t2 ON t2.RegionId = t1.RegionId
WHERE t1.RegionId IS NULL OR t2.RegionId IS NULL

image