Inre sammanfogning, yttre sammanfogning, tvärfogning? Vad ger?
Det är en giltig fråga. Jag såg en gång en Visual Basic-kod med T-SQL-koder inbäddade i den. VB-koden hämtar tabellposter med flera SELECT-satser, en SELECT* per tabell. Sedan kombinerar den flera resultatuppsättningar till en rekorduppsättning. Absurt?
För de unga utvecklarna som gjorde det var det inte det. Men när de bad mig att utvärdera varför systemet var långsamt, var det problemet det första som fångade min uppmärksamhet. Det är rätt. De har aldrig hört talas om SQL-anslutningar. I rättvisans namn var de ärliga och öppna för förslag.
Hur beskriver du SQL-anslutningar? Kanske kommer du ihåg en låt – Imagine av John Lennon:
Du kan säga att jag är en drömmare, men jag är inte den enda.
Jag hoppas att du en dag kommer att ansluta sig till oss, och att världen kommer att vara som en.
I låtens sammanhang är sammanfogning att förena. I en SQL-databas, att kombinera poster med 2 eller flera tabeller till en resultatuppsättning bildar en sammanfogning .
Den här artikeln är början på en serie i tre delar som talar om SQL-anslutningar:
- INRE JOIN
- OUTTER JOIN, som inkluderar LEFT, RIGHT och FULL
- KORS-GÅ MED
Men innan vi börjar diskutera INNER JOIN, låt oss beskriva anslutningar i allmänhet.
Mer om SQL JOIN
Joins visas direkt efter FROM-satsen. I sin enklaste form ser det ut som att använda SQL-92-standarden:
FROM <table source> [<alias1>]
<join type> JOIN <table source> [<alias2>] [ON <join condition>]
[<join type> JOIN <table source> [<alias3>] [ON <join condition>]
<join type> JOIN <table source> [<aliasN>] [ON <join condition>]]
[WHERE <condition>]
Låt oss beskriva de vardagliga sakerna kring JOIN.
Tabellkällor
Du kan lägga till upp till 256 tabellkällor, enligt Microsoft. Naturligtvis beror det på dina serverresurser. Jag har aldrig gått med i mer än 10 bord i mitt liv, för att inte tala om 256. Hur som helst, tabellkällor kan vara något av följande:
- Tabell
- Visa
- Synonym för tabell eller vy
- Tabellvariabel
- Tabellvärderad funktion
- Härledd tabell
Tabellalias
Ett alias är valfritt, men det förkortar din kod och minimerar skrivning. Det hjälper dig också att undvika fel när ett kolumnnamn finns i två eller flera tabeller som används i en SELECT, UPDATE, INSERT eller DELETE. Det ger också klarhet till din kod. Det är valfritt, men jag rekommenderar att du använder alias. (Om du inte älskar att skriva tabellkällor efter namn.)
Anslutningsvillkor
Nyckelordet ON föregår kopplingsvillkoret som kan vara en enkel koppling eller kolumner med 2 nyckel från de 2 sammanfogade tabellerna. Eller det kan vara en sammansatt koppling med fler än 2 nyckelkolumner. Den definierar hur tabeller är relaterade.
Däremot använder vi sammanfogningsvillkoret endast för INNER och OUTER sammanfogningar. Att använda det på en CROSS JOIN kommer att utlösa ett fel.
Eftersom anslutningsvillkoren definierar relationerna behöver de operatörer.
Den vanligaste operatorn för joinvillkor är likhetsoperator (=). Andra operatörer som> eller
De flesta anslutningar kan skrivas om som delfrågor och vice versa. Kolla in den här artikeln för att lära dig mer om delfrågor jämfört med anslutningar.
Att använda härledda tabeller i en join ser ut så här:
Det går med från resultatet av en annan SELECT-sats, och den är helt giltig.
Du kommer att ha fler exempel, men låt oss ta itu med en sista sak om SQL JOINS. Det är hur SQL Servers Query Optimizer-processer ansluts.
För att förstå hur processen fungerar måste du känna till de två typerna av operationer som är involverade:
Ett ord:Prestanda.
En sak är att veta hur man skapar frågor med kopplingar för att ge korrekta resultat. En annan är att få den att gå så fort som möjligt. Du måste vara extra mån om detta om du vill ha ett gott rykte hos dina användare.
Så vad behöver du hålla utkik efter i exekveringsplanen för dessa logiska operationer?
Join-tips är nya i SQL Server 2019. När du använder det i dina joins säger det till frågeoptimeraren att sluta bestämma vad som är bäst för frågan. Du är chefen när det kommer till den fysiska anslutningen att använda.
Sluta nu, där. Sanningen är att frågeoptimeraren vanligtvis väljer den bästa fysiska kopplingen för din fråga. Om du inte vet vad du gör, använd inte anslutningstips.
De möjliga tipsen du kan ange är LOOP, MERGE, HASH eller REMOTE.
Jag har inte använt anslutningstips, men här är syntaxen:
INNER JOIN returnerar raderna med matchande poster i båda tabellerna, baserat på ett villkor. Det är också standardanslutningen om du inte anger sökordet INNER:
Som du ser, matchande rader från Tabell1 och Tabell2 returneras med Key1 som sammanfogningsvillkor. Tabell1 post med Nyckel1 ='C' exkluderas eftersom det inte finns några matchande poster i Tabell2 .
När jag ställer en fråga är mitt första val INNER JOIN. OUTTER JOIN kommer bara när kraven dikterar det.
Det finns två INNER JOIN-syntaxer som stöds i T-SQL:SQL-92 och SQL-89.
Den första joinsyntaxen jag lärde mig var SQL-89. När SQL-92 äntligen kom, tyckte jag att det var för långt. Jag tänkte också eftersom resultatet var detsamma, varför bry sig om att skriva fler sökord? En grafisk frågedesigner hade den genererade koden SQL-92, och jag ändrade tillbaka den till SQL-89. Men idag föredrar jag SQL-92 även om jag måste skriva mer. Här är anledningen:
Skälen ovan är mina. Du kanske har dina skäl till varför du föredrar SQL-92 eller varför du hatar det. Jag undrar vad dessa skäl är. Låt mig veta i kommentarsektionen nedan.
Men vi kan inte avsluta den här artikeln utan exempel och förklaringar.
Här är ett exempel på två tabeller sammanfogade med INNER JOIN i SQL-92-syntax.
Du anger bara de kolumner som du behöver. I exemplet ovan anges 4 kolumner. Jag vet att den är för lång än SELECT * men kom ihåg detta:det är bästa praxis.
Lägg även märke till användningen av tabellalias. Både Produkten och ProductSubcategory tabeller har en kolumn som heter [Namn ]. Om du inte anger aliaset kommer ett fel att utlösas.
Under tiden, här är motsvarande SQL-89-syntax:
De är desamma förutom joinvillkoret blandat i WHERE-satsen med ett AND-nyckelord. Men under huven, är de verkligen likadana? Låt oss inspektera resultatuppsättningen, STATISTICS IO och exekveringsplanen.
Se resultatuppsättningen med 9 poster:
Det är inte bara resultaten, utan resurserna som krävs av SQL Server är också desamma.
Se den logiska läsningen:
Slutligen avslöjar exekveringsplanen samma frågeplan för båda frågorna när deras QueryPlanHashes är jämlika. Lägg även märke till de markerade operationerna i diagrammet:
Baserat på resultaten är SQL Server-frågebehandlingen densamma, oavsett om det är SQL-92 eller SQL-89. Men som sagt, tydligheten i SQL-92 är mycket bättre för mig.
Figur 7 visar också en kapslad loopkoppling som används i planen. Varför? Resultatuppsättningen är liten.
Kolla in frågan nedan med tre sammanfogade tabeller.
Du kan också ansluta 2 bord med 2 nycklar för att relatera det. Kolla in provet nedan. Den använder 2 anslutningsvillkor med en AND-operator.
I exemplet nedan, Produkten bordet har 9 poster – en liten uppsättning. Den sammanfogade tabellen är SalesOrderDetail – ett stort set. Query Optimizer kommer att använda en Nested Loop Join, som visas i figur 8.
I exemplet nedan används en Merge Join eftersom båda inmatningstabellerna är sorterade efter SalesOrderID.
Följande exempel kommer att använda en Hash Join:
I exemplet nedan, Säljare tabellen har ett icke-klustrat ColumnStore-index på TerritoryID kolumn. Frågeoptimeraren bestämde sig för en kapslad loopkoppling, som visas i figur 11.
Betrakta detta påstående med en kapslad underfråga:
Samma resultat kan komma ut om du ändrar den till en INNER JOIN, enligt nedan:
Ett annat sätt att skriva om det är att använda en härledd tabell som en tabellkälla för INNER JOIN:
Alla tre frågorna matar ut samma 48 poster.
Följande fråga använder en kapslad loop:
Om du vill tvinga den till en Hash-join, är detta vad som händer:
Observera dock att STATISTICS IO visar att prestandan blir dålig när du tvingar den till en Hash-join.
Samtidigt använder frågan nedan en Merge Join:
Så här blir det när du tvingar den till en kapslad loop:
När du kontrollerar STATISTICS IO för båda och tvingar den till en kapslad loop kräver mer resurser för att bearbeta frågan:
Att använda anslutningstips bör därför vara din sista utväg när du finjusterar för prestanda. Låt din SQL Server hantera det åt dig.
Du kan också använda INNER JOIN i ett UPDATE-uttalande. Här är ett exempel:
Eftersom det är möjligt att använda en join i en UPPDATERING, varför inte prova det med DELETE och INSERT?
Så, vad är grejen med SQL-anslutning?
Samtidigt visade det här inlägget 10 exempel på INNER JOINs. Det är inte bara exempelkoder. Några av dem innehåller också en inspektion av hur koden fungerar inifrån och ut. Det är inte bara för att hjälpa dig koda utan för att hjälpa dig att vara uppmärksam på prestanda. I slutet av dagen ska resultaten inte bara vara korrekta utan också levereras snabbt.
Vi är inte klara än. Nästa artikel kommer att behandla OUTER JOINS. Håll utkik.
SQL Joins låter dig hämta och kombinera data från mer än en tabell. Titta på den här videon för att lära dig mer om SQL Joins.SQL JOIN vs. Subqueries
Joins och härledda tabeller
FROM table1 a
INNER JOIN (SELECT y.column3 from table2 x
INNER JOIN table3 y on x.column1 = y.column1) b ON a.col1 = b.col2
Hur SQL Server Processer ansluter
Varför behöver vi bry oss om detta?
Gå med tips
<join type> <join hint> JOIN <table source> [<alias>] ON <join condition>
Allt om INNER JOIN
INNER JOIN Syntax
SQL-92 INNER JOIN
FROM <table source1> [<alias1>]
INNER JOIN <table source2> [<alias2>] ON <join condition1>
[INNER JOIN <table source3> [<alias3>] ON <join condition2>
INNER JOIN <table sourceN> [<aliasN>] ON <join conditionN>]
[WHERE <condition>]
SQL-89 INNER JOIN
FROM <table source1> [alias1], <table source2> [alias2] [, <table source3> [alias3], <table sourceN> [aliasN]]
WHERE (<join condition1>)
[AND (<join condition2>)
AND (<join condition3>)
AND (<join conditionN>)]
Vilken INNER JOIN-syntax är bättre?
10 INNER JOIN-exempel
1. Sammanfoga 2 tabeller
-- Display Vests, Helmets, and Light products
USE AdventureWorks
GO
SELECT
p.ProductID
,P.Name AS [Product]
,ps.ProductSubcategoryID
,ps.Name AS [ProductSubCategory]
FROM Production.Product p
INNER JOIN Production.ProductSubcategory ps ON P.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE P.ProductSubcategoryID IN (25, 31, 33); -- for vest, helmet, and light
-- product subcategories
-- Display Vests, Helmets, and Light products
USE AdventureWorks
GO
SELECT
p.ProductID
,P.Name AS [Product]
,ps.ProductSubcategoryID
,ps.Name AS [ProductSubCategory]
FROM Production.Product p, Production.ProductSubcategory ps
WHERE P.ProductSubcategoryID = ps.ProductSubcategoryID
AND P.ProductSubcategoryID IN (25, 31, 33);
2. Sammanfoga flera tabeller
-- Get the total number of orders per Product Category
USE AdventureWorks
GO
SELECT
ps.Name AS ProductSubcategory
,SUM(sod.OrderQty) AS TotalOrders
FROM Production.Product p
INNER JOIN Sales.SalesOrderDetail sod ON P.ProductID = sod.ProductID
INNER JOIN Sales.SalesOrderHeader soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE soh.OrderDate BETWEEN '1/1/2014' AND '12/31/2014'
AND p.ProductSubcategoryID IN (1,2)
GROUP BY ps.Name
HAVING ps.Name IN ('Mountain Bikes', 'Road Bikes')
3. Composite Join
SELECT
a.column1
,b.column1
,b.column2
FROM Table1 a
INNER JOIN Table2 b ON a.column1 = b.column1 AND a.column2 = b.column2
4. INNER JOIN Använda en kapslad loop Fysisk Join
USE AdventureWorks
GO
SELECT
sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);
5. INNER JOIN Använda en Merge Physical Join
SELECT
soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID
6. INNER JOIN med hjälp av en Hash Physical Join
SELECT
s.Name AS Store
,SUM(soh.TotalDue) AS TotalSales
FROM Sales.SalesOrderHeader soh
INNER JOIN Sales.Store s ON soh.SalesPersonID = s.SalesPersonID
GROUP BY s.Name
7. INNER JOIN Använder Adaptive Physical Join
SELECT
sp.BusinessEntityID
,sp.SalesQuota
,st.Name AS Territory
FROM Sales.SalesPerson sp
INNER JOIN Sales.SalesTerritory st ON sp.TerritoryID = st.TerritoryID
WHERE sp.TerritoryID BETWEEN 1 AND 5
8. Två sätt att skriva om en underfråga till en INNER JOIN
SELECT [SalesOrderID], [OrderDate], [ShipDate], [CustomerID]
FROM Sales.SalesOrderHeader
WHERE [CustomerID] IN (SELECT [CustomerID] FROM Sales.Customer
WHERE PersonID IN (SELECT BusinessEntityID FROM Person.Person
WHERE lastname LIKE N'I%' AND PersonType='SC'))
SELECT o.[SalesOrderID], o.[OrderDate], o.[ShipDate], o.[CustomerID]
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.Customer c on o.CustomerID = c.CustomerID
INNER JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE p.PersonType = 'SC'
AND p.lastname LIKE N'I%'
SELECT o.[SalesOrderID], o.[OrderDate], o.[ShipDate], o.[CustomerID]
FROM Sales.SalesOrderHeader o
INNER JOIN (SELECT c.CustomerID, P.PersonType, P.LastName
FROM Sales.Customer c
INNER JOIN Person.Person p ON c.PersonID = P.BusinessEntityID
WHERE p.PersonType = 'SC'
AND p.LastName LIKE N'I%') AS q ON o.CustomerID = q.CustomerID
9. Använda anslutningstips
SELECT
sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);
SELECT
sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER HASH JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);
SELECT
soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID
SELECT
soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER LOOP JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID
10. Använder INNER JOIN i UPDATE
UPDATE Sales.SalesOrderHeader
SET ShipDate = getdate()
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.Customer c on o.CustomerID = c.CustomerID
INNER JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE p.PersonType = 'SC'
SQL Join och INNER JOIN Takeaways
Se även