sql >> Databasteknik >  >> RDS >> Sqlserver

SQL Server Inner Join Basics med exempel

Introduktion

T-SQL tillåter oss att kombinera poster från mer än en tabell och returnera dem som en enda resultatuppsättning. Detta uppnås genom konceptet joins i SQL Server.

Denna möjlighet är ofta nödvändig eftersom data i relationsdatabaser vanligtvis är normaliserade. Vi har till exempel personaldata spridda över två eller flera tabeller. Den första tabellen skulle vara grundläggande kunddata och kallas anställd. Den andra tabellen skulle vara avdelningen .

Datakonsistensen kräver korrekt relation mellan kunden och avdelningen. Att returnera fullständiga data för en uppsättning anställda och deras avdelningar kräver att man går med i båda tabellerna.

SQL-kopplingsoperationerna kan också inkludera fler än två tabeller.

Ett annat fall av sådana främmande nyckelrelationer mellan tabeller är för sammanfattning och detaljer tabeller.

Personer som arbetade med exempeldatabaserna AdventureWorks eller WideWorldImporters är bekanta med Sales.Orders och Sales.OrderDetails-tabeller. I det här fallet innehåller den senare informationen om varje beställning som registrerats i Sales.Orders tabell. Två tabeller har en relation baserat på ordningen. Således kan vi hämta data från båda tabellerna som en enda resultatuppsättning med JOINS.

Typer av SQL Server JOINs

T-SQL tillåter följande typer av joins:

  1. Inre Join returnerar alla poster som är gemensamma för alla tabeller som är involverade i frågan.
  2. Vänster (yttre) gå med returnerar alla poster från vänster tabellen och alla poster från höger tabell som också förekommer i den vänstra tabellen. Termerna vänster och höger hänvisa till tabellens position i förhållande till JOIN-satsen.
  3. Höger (yttre) gå med returnerar alla poster från höger tabellen och alla poster från vänster tabell som också förekommer i den vänstra tabellen. Termerna liknar det tidigare fallet.
  4. Fullständig yttre sammanfogning returnerar alla poster som är gemensamma för båda tabellerna, plus alla andra poster från båda tabellerna. Kolumner som inte har motsvarande rader i den andra tabellen returnerar NULL
  5. Gå med i kors , även kallad Cartesian Join , returnerar den kartesiska produkten av data från båda tabellerna. Därför kommer slutresultatet för varje rad i tabell A att innehålla en mappning av alla rader i tabell B och vice versa.

Den här artikeln kommer att fokusera på SQL INNER JOINs.

Exempeltabeller

För att demonstrera konceptet med inre sammanfogningar använder vi tre relaterade tabeller från databasen TSQLV4 byggd av Itzik Ben-Gan.

Följande listor visar strukturen för dessa tabeller.

-- Listing 1: Structure of the Sales.Customers Table

CREATE TABLE [Sales].[Customers](
	[custid] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
	[companyname] [nvarchar](40) NOT NULL,
	[contactname] [nvarchar](30) NOT NULL,
	[contacttitle] [nvarchar](30) NOT NULL,
	[address] [nvarchar](60) NOT NULL,
	[city] [nvarchar](15) NOT NULL,
	[region] [nvarchar](15) NULL,
	[postalcode] [nvarchar](10) NULL,
	[country] [nvarchar](15) NOT NULL,
	[phone] [nvarchar](24) NOT NULL,
	[fax] [nvarchar](24) NULL,
 CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED 
(
	[custid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

Notera den främmande nyckelrelationen mellan custid-kolumnen i Sales.Orders och kolumnen anpassad i Sales.Customers .

För att utföra JOINs måste vi ange en sådan gemensam kolumn som JOIN-basen.

Det kräver inte strikt en främmande nyckelrelation för att exekvera JOIN-frågor, men kolumnerna som bestämmer resultatuppsättningen måste vara jämförbara.

Främmande nycklar kan också hjälpa till att förbättra JOIN-frågor, särskilt om kolumnen för främmande nyckel är indexerad.

-- Listing 2: Structure of the Sales.Orders Table

CREATE TABLE [Sales].[Orders](
	[orderid] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
	[custid] [int] NULL,
	[empid] [int] NOT NULL,
	[orderdate] [date] NOT NULL,
	[requireddate] [date] NOT NULL,
	[shippeddate] [date] NULL,
	[shipperid] [int] NOT NULL,
	[freight] [money] NOT NULL,
	[shipname] [nvarchar](40) NOT NULL,
	[shipaddress] [nvarchar](60) NOT NULL,
	[shipcity] [nvarchar](15) NOT NULL,
	[shipregion] [nvarchar](15) NULL,
	[shippostalcode] [nvarchar](10) NULL,
	[shipcountry] [nvarchar](15) NOT NULL,
 CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED 
(
	[orderid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [Sales].[Orders] ADD  CONSTRAINT [DFT_Orders_freight]  DEFAULT ((0)) FOR [freight]
GO
ALTER TABLE [Sales].[Orders]  WITH CHECK ADD  CONSTRAINT [FK_Orders_Customers] FOREIGN KEY([custid])
REFERENCES [Sales].[Customers] ([custid])
GO
ALTER TABLE [Sales].[Orders] CHECK CONSTRAINT [FK_Orders_Customers]
GO
ALTER TABLE [Sales].[Orders]  WITH CHECK ADD  CONSTRAINT [FK_Orders_Employees] FOREIGN KEY([empid])
REFERENCES [HR].[Employees] ([empid])
GO
ALTER TABLE [Sales].[Orders] CHECK CONSTRAINT [FK_Orders_Employees]
GO
ALTER TABLE [Sales].[Orders]  WITH CHECK ADD  CONSTRAINT [FK_Orders_Shippers] FOREIGN KEY([shipperid])
REFERENCES [Sales].[Shippers] ([shipperid])
GO
ALTER TABLE [Sales].[Orders] CHECK CONSTRAINT [FK_Orders_Shippers]
GO
-- Listing 3: Structure of the Sales.OrderDetails Table

CREATE TABLE [Sales].[OrderDetails](
	[orderid] [int] NOT NULL,
	[productid] [int] NOT NULL,
	[unitprice] [money] NOT NULL,
	[qty] [smallint] NOT NULL,
	[discount] [numeric](4, 3) NOT NULL,
 CONSTRAINT [PK_OrderDetails] PRIMARY KEY CLUSTERED 
(
	[orderid] ASC,
	[productid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [Sales].[OrderDetails] ADD  CONSTRAINT [DFT_OrderDetails_unitprice]  DEFAULT ((0)) FOR [unitprice]
GO
ALTER TABLE [Sales].[OrderDetails] ADD  CONSTRAINT [DFT_OrderDetails_qty]  DEFAULT ((1)) FOR [qty]
GO
ALTER TABLE [Sales].[OrderDetails] ADD  CONSTRAINT [DFT_OrderDetails_discount]  DEFAULT ((0)) FOR [discount]
GO
ALTER TABLE [Sales].[OrderDetails]  WITH CHECK ADD  CONSTRAINT [FK_OrderDetails_Orders] FOREIGN KEY([orderid])
REFERENCES [Sales].[Orders] ([orderid])
GO
ALTER TABLE [Sales].[OrderDetails] CHECK CONSTRAINT [FK_OrderDetails_Orders]
GO
ALTER TABLE [Sales].[OrderDetails]  WITH CHECK ADD  CONSTRAINT [FK_OrderDetails_Products] FOREIGN KEY([productid])
REFERENCES [Production].[Products] ([productid])
GO
ALTER TABLE [Sales].[OrderDetails] CHECK CONSTRAINT [FK_OrderDetails_Products]
GO
ALTER TABLE [Sales].[OrderDetails]  WITH CHECK ADD  CONSTRAINT [CHK_discount] CHECK  (([discount]>=(0) AND [discount]<=(1)))
GO
ALTER TABLE [Sales].[OrderDetails] CHECK CONSTRAINT [CHK_discount]
GO
ALTER TABLE [Sales].[OrderDetails]  WITH CHECK ADD  CONSTRAINT [CHK_qty] CHECK  (([qty]>(0)))
GO
ALTER TABLE [Sales].[OrderDetails] CHECK CONSTRAINT [CHK_qty]
GO
ALTER TABLE [Sales].[OrderDetails]  WITH CHECK ADD  CONSTRAINT [CHK_unitprice] CHECK  (([unitprice]>=(0)))
GO
ALTER TABLE [Sales].[OrderDetails] CHECK CONSTRAINT [CHK_unitprice]
GO

Exempel på frågor med SQL INNER JOIN

Låt oss köra några exempelfrågor med en SQL INNER JOIN.

I lista 4 kör vi en fråga som hämtar ALLA rader som är gemensamma för tabellen Sales.Customers och Sales.Orders. Vi använder custid-kolumnen som villkor för sammanfogningen.

Lägg märke till att ON-satsen är ett filter mycket likt en WHERE-sats. Vi har också använt alias för att skilja tabellerna åt.

-- Listing 4: Customer Orders

use TSQLV4
go
select * from Sales.Customers sc
inner join Sales.Orders so
on sc.custid=so.custid;

I lista 5 begränsar vi frågan till specifika kolumner till Sälj.Kunder tabellen och Sales.Orders tabell. Vi använder custid kolumn som villkor för sammanfogningen.

Observera att ON-satsen är ett filter mycket likt en WHERE-sats. Vi har också använt alias för att skilja tabellerna åt.

-- Listing 5: Customer Orders with specific Rows
use TSQLV4
go
select
contactname
, contacttitle
, address
, orderid
, orderdate
, shipaddress
, shipcountry
from Sales.Customers sc
inner join Sales.Orders so
on sc.custid=so.custid;

I listning 6 utökar vi tanken genom att introducera en WHERE-klausul som filtrerar data för en enskild kund. Vi har även lagt till alias till kolumnlistan.

Även om det inte är nödvändigt i det här exemplet, finns det fall där du behöver projicera kolumner med samma namn från båda tabellerna. Då kommer kolumnerna att behöva ett uttryck som tvådelade namn, med tabellalias eller namn.

-- Listing 6: Customer Orders for a Single Customer
use TSQLV4
go
select 
sc.contactname
, sc.contacttitle
, sc.address
, so.orderid
, so.orderdate
, so.shipaddress
, so.shipcountry
from Sales.Customers sc
inner join Sales.Orders so
on sc.custid=so.custid
where sc.contactname='Allen, Michael';

I lista 7 introducerar vi custid-kolumnen. Vi kan särskilja kolumnerna med hjälp av aliaset, men vi kan inte särskilja de två custid kolumner i utgången (se figur 4). Vi kan fixa detta genom att använda alias:

-- Listing 7: Customer Orders for a Single Customer with Common Column
use TSQLV4
go
select 
sc.custid
, sc.contactname
, sc.contacttitle
, sc.address
, so.custid
, so.orderid
, so.orderdate
, so.shipaddress
, so.shipcountry
from Sales.Customers sc
inner join Sales.Orders so
on sc.custid=so.custid
where sc.contactname='Allen, Michael';
-- Listing 8: Customer Orders for a Single Customer with Aliased Column
use TSQLV4
go
select 
sc.custid customer_custid
, sc.contactname
, sc.contacttitle
, sc.address
, so.custid order_custid
, so.orderid
, so.orderdate
, so.shipaddress
, so.shipcountry
from Sales.Customers sc
inner join Sales.Orders so
on sc.custid=so.custid
where sc.contactname='Allen, Michael';

I listning 9 lägger vi till tabellen Sales.OrderDetails till mixen. När du sammanfogar fler än två tabeller blir resultatuppsättningen från de två första tabellerna JOIN till vänster bord för nästa bord. Tabellordningen i en JOIN-fråga påverkar dock inte den slutliga utdata.

Observera att vi använder ett jokertecken för att hämta ALLA kolumner från tabellen Sales.OrderDetails.

-- Listing 9: Inner Join with Three Tables

use TSQLV4
go
select 
sc.custid customer_custid
, sc.contactname
, sc.contacttitle
, sc.address
, so.custid order_custid
, so.orderid
, so.orderdate
, so.shipaddress
, so.shipcountry
, sod.*
from Sales.Customers sc
inner join Sales.Orders so
on sc.custid=so.custid
inner join Sales.OrderDetails sod
on so.orderid=sod.orderid
where sc.contactname='Allen, Michael';

Lista 10 introducerar Production.Product-tabellen som visar oss produktdetaljerna som är kopplade till beställningen.

-- Listing 10: Inner Join with Four Tables

use TSQLV4
go
select 
sc.custid customer_custid
, sc.contactname
, sc.contacttitle
, sc.address
, so.custid order_custid
, so.orderid
, so.orderdate
, so.shipaddress
, so.shipcountry
, sod.*
, pp.productname
, pp.unitprice
from Sales.Customers sc
inner join Sales.Orders so
on sc.custid=so.custid
inner join Sales.OrderDetails sod
on so.orderid=sod.orderid
inner join Production.Products pp
on sod.productid=pp.productid
where sc.contactname='Allen, Michael';

Icke-Equi JOINs

Eftersom ON-satsen är ett filter kan vi använda andra operatorer än operatorn "=". JOINs stöder i allmänhet användningen av ojämlikheter som <,>, !=, = i ON-satsen. Lista 11 visar detta.

Att köra dessa frågor kommer att returnera olika resultatuppsättningar.

-- Listing 11: Non-Equi JOINs, "Equal to"
use TSQLV4
go
select
contactname
, contacttitle
, address
, orderid
, orderdate
, shipaddress
, shipcountry
from Sales.Customers sc
inner join Sales.Orders so
on sc.custid=so.custid;
-- Listing 12: Non-Equi JOINs, "Not Equal to"
use TSQLV4
go
select
contactname
, contacttitle
, address
, orderid
, orderdate
, shipaddress
, shipcountry
from Sales.Customers sc
inner join Sales.Orders so
on sc.custid<>so.custid;
-- Listing 13: Non-Equi JOINs, "Less than OR Equal to"
use TSQLV4
go
select
contactname
, contacttitle
, address
, orderid
, orderdate
, shipaddress
, shipcountry
from Sales.Customers sc
inner join Sales.Orders so
on sc.custid<=so.custid;

Slutsats

Den här artikeln diskuterade SQL INNER JOINs och presenterade exempel på dess användning. Den täckte scenarier med två, tre och fyra tabeller i samma fråga.

Med hjälp av relaterade tabeller har vi också illustrerat hur vi kan variera frågestrukturen för att visa utdata enligt våra krav. Vi har också lagt till korta exempel på Non-Equi JOINs.


  1. MySQL High Availability Framework förklaras – Del II:Semisynkron replikering

  2. Får NoClassDefFoundError när jag försöker använda Proguard och SQLcipher i Android

  3. Hur LN() fungerar i MariaDB

  4. Hur man skickar parametrar till mysql query callback i nodejs