sql >> Database teknologi >  >> RDS >> Sqlserver

SQL Server Inner Join Basics med eksempler

Introduktion

T-SQL giver os mulighed for at kombinere poster fra mere end én tabel og returnere dem som et enkelt resultatsæt. Dette opnås gennem konceptet joins i SQL Server.

Denne mulighed er ofte nødvendig, fordi data i relationelle databaser typisk er normaliseret. For eksempel har vi medarbejderdata spredt ud over to eller flere tabeller. Den første tabel ville være de grundlæggende kundedata og kaldet medarbejder. Den anden tabel ville være afdelingen .

Datakonsistensen kræver det korrekte forhold mellem kunden og afdelingen. Returnering af de komplette data for et sæt medarbejdere og deres afdelinger kræver, at du tilslutter begge tabeller.

SQL join-operationerne kan også omfatte mere end to tabeller.

Et andet tilfælde af sådanne fremmede nøglerelationer mellem tabeller er resumé og detaljer tabeller.

Personer, der arbejdede med prøvedatabaserne AdventureWorks eller WideWorldImporters, er bekendt med Sales.Orders og Sales.OrderDetails-tabeller. I dette tilfælde indeholder sidstnævnte detaljerne for hver ordre, der er registreret i Sales.Orders bord. To tabeller har en relation baseret på rækkefølgen. Således kan vi hente data fra begge tabeller som et enkelt resultatsæt ved hjælp af JOINS.

Typer af SQL Server JOINs

T-SQL tillader følgende typer joins:

  1. Indre deltagelse returnerer alle poster, der er fælles for alle tabeller, der er involveret i forespørgslen.
  2. Venstre (ydre) Deltag returnerer alle poster fra venstre tabel og alle poster fra højre tabel, der også forekommer i venstre tabel. Vilkårene tilbage og højre henvise til tabellens placering i forhold til JOIN-klausulen.
  3. Højre (ydre) deltagelse returnerer alle poster fra højre tabel og alle poster fra venstre tabel, der også forekommer i venstre tabel. Betingelserne ligner det tidligere tilfælde.
  4. Fuld ydre forbindelse returnerer alle poster, der er fælles for begge tabeller, plus alle andre poster fra begge tabeller. Kolonner, der ikke har tilsvarende rækker i den anden tabel, returnerer NULL
  5. Tilmeld dig på kryds og tværs , også kaldet Cartesian Join , returnerer det kartesiske produkt af dataene fra begge tabeller. Derfor vil det endelige resultatsæt for hver række i tabel A indeholde en mapping af alle rækker i tabel B og omvendt.

Denne artikel vil fokusere på SQL INNER JOINs.

Eksempeltabeller

For at demonstrere konceptet med indre sammenføjninger bruger vi tre relaterede tabeller fra TSQLV4-databasen bygget af Itzik Ben-Gan.

De følgende lister viser strukturen af ​​disse 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

Bemærk forholdet mellem udenlandsk nøgle mellem custid-kolonnen i Sales.Orders og custid-kolonnen i Sales.Customers .

For at udføre JOINs skal vi angive en sådan fælles kolonne som JOIN-grundlaget.

Det kræver strengt taget ikke et fremmednøgleforhold for at udføre JOIN-forespørgsler, men de kolonner, der bestemmer resultatsættet, skal være sammenlignelige.

Fremmednøgler kan også hjælpe med at forbedre JOIN-forespørgsler, især hvis fremmednøglekolonnen er indekseret.

-- 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

Eksempelforespørgsler med SQL INNER JOIN

Lad os udføre nogle eksempelforespørgsler ved hjælp af en SQL INNER JOIN.

I liste 4 udfører vi en forespørgsel, der henter ALLE rækker, der er fælles for tabellen Salg.Kunder og Salg.ordrer. Vi bruger custid-søjlen som betingelse for sammenføjningen.

Bemærk, at ON-klausulen er et filter meget ligesom en WHERE-klausul. Vi har også brugt aliaser til at skelne tabellerne.

-- Listing 4: Customer Orders

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

I liste 5 indsnævrer vi forespørgslen til specifikke kolonner til Salg.Kunder tabellen og Sales.Orders bord. Vi bruger custid kolonne som betingelse for sammenføjningen.

Bemærk, at ON-sætningen er et filter, der ligner en WHERE-sætning. Vi har også brugt aliaser til at skelne tabellerne.

-- 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 liste 6 udvider vi tanken ved at introducere en WHERE-klausul, der filtrerer data for en enkelt kunde. Vi har også tilføjet aliaser til kolonnelisten.

Selvom det ikke er nødvendigt i dette eksempel, er der tilfælde, hvor du skal projicere kolonner med samme navn fra begge tabeller. Derefter skal kolonnerne have et udtryk som todelte navne ved at bruge tabelaliasserne eller -navnene.

-- 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 liste 7 introducerer vi custid kolonnen. Vi kan skelne kolonnerne ved hjælp af aliaset, men vi kan ikke skelne de to custid kolonner i outputtet (se figur 4). Vi kan rette dette ved at bruge aliaser:

-- 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 liste 9 tilføjer vi Sales.OrderDetails-tabellen til blandingen. Når du forbinder mere end to tabeller, bliver resultatsættet fra de første to tabeller JOIN det venstre bord til næste bord. Rækkefølgen af ​​tabeller i en JOIN-forespørgsel påvirker dog ikke det endelige output.

Bemærk, at vi bruger et wild card til at hente ALLE kolonner fra 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'; 

Liste 10 introducerer Production.Product-tabellen, der viser os de produktdetaljer, der er knyttet til ordren.

-- 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';

Ikke-Equi JOINs

Da ON-sætningen er et filter, kan vi bruge andre operatorer end "="-operatoren. JOINs understøtter generelt brugen af ​​uligheder såsom <,>, !=, = i ON-sætningen. Liste 11 viser dette.

Kørsel af disse forespørgsler vil returnere forskellige resultatsæt.

-- 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; 

Konklusion

Denne artikel diskuterede SQL INNER JOINs og præsenterede eksempler på dets brug. Det dækkede scenarier med to, tre og fire tabeller i samme forespørgsel.

Ved hjælp af relaterede tabeller har vi også illustreret, hvordan vi kan variere forespørgselsstrukturen for at vise output i overensstemmelse med vores krav. Vi har også tilføjet korte eksempler på Non-Equi JOINs.


  1. PostgreSQL parametriseret rækkefølge efter / grænse i tabelfunktion

  2. Sådan fungerer LOG10() i MariaDB

  3. Skinner:Udrulning til Heroku, mange problemer

  4. MySQL-forbindelse virker ikke:2002 Ingen sådan fil eller mappe