Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

SQL Server Inner Join Basics avec des exemples

Présentation

T-SQL nous permet de combiner des enregistrements de plusieurs tables et de les renvoyer sous la forme d'un ensemble de résultats unique. Ceci est réalisé grâce au concept de jointures dans SQL Server.

Cette opportunité est souvent nécessaire car les données des bases de données relationnelles sont généralement normalisées. Par exemple, nous avons des données sur les employés réparties sur deux tables ou plus. La première table serait les données client de base et appelée employé. La deuxième table serait le département .

La cohérence des données nécessite la bonne relation entre le client et le service. Renvoyer les données complètes pour un ensemble d'employés et leurs départements nécessite de joindre les deux tables.

Les opérations de jointure SQL peuvent également inclure plus de deux tables.

Un autre cas d'existence de telles relations de clé étrangère entre les tables est pour résumé et détail tableaux.

Les personnes qui ont travaillé avec les exemples de bases de données AdventureWorks ou WideWorldImporters connaissent les Sales.Orders et les tables Sales.OrderDetails. Dans ce cas, ce dernier contient le détail de chaque commande enregistrée dans le fichier Sales.Orders table. Deux tables ont une relation basée sur l'ordre. Ainsi, nous pouvons récupérer les données des deux tables sous la forme d'un ensemble de résultats unique à l'aide de JOINS.

Types de jointures SQL Server

T-SQL autorise les types de jointures suivants :

  1. Jointure interne renvoie tous les enregistrements communs à toutes les tables impliquées dans la requête.
  2. Jointure gauche (externe) renvoie tous les enregistrements depuis la gauche table et tous les enregistrements de la droite table qui apparaissent également dans la table de gauche. Les termes gauche et juste faire référence à la position de la table par rapport à la clause JOIN.
  3. Joindre à droite (externe) renvoie tous les enregistrements depuis la droite table et tous les enregistrements de la gauche table qui apparaissent également dans la table de gauche. Les termes sont similaires au cas précédent.
  4. Jointure externe complète renvoie tous les enregistrements communs aux deux tables, ainsi que tous les autres enregistrements des deux tables. Les colonnes qui n'ont pas de lignes correspondantes dans l'autre table renvoient NULL
  5. Jointure croisée , également appelé jointure cartésienne , renvoie le produit cartésien des données des deux tables. Par conséquent, le jeu de résultats final pour chaque ligne de la table A contiendra un mappage de toutes les lignes de la table B, et vice versa.

Cet article se concentrera sur SQL INNER JOINs.

Exemples de tableaux

Pour démontrer le concept de jointures internes, nous utilisons trois tables liées de la base de données TSQLV4 construite par Itzik Ben-Gan.

Les listes suivantes montrent la structure de ces tables.

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

Notez la relation de clé étrangère entre la colonne custid dans Sales.Orders et la colonne custid dans Sales.Customers .

Pour effectuer des JOIN, nous devons spécifier une telle colonne commune comme base JOIN.

Il ne nécessite pas strictement une relation de clé étrangère pour exécuter des requêtes JOIN, mais les colonnes qui déterminent le jeu de résultats doivent être comparables.

Les clés étrangères peuvent également aider à améliorer les requêtes JOIN, en particulier si la colonne de clé étrangère est indexée.

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

Exemples de requêtes avec SQL INNER JOIN

Exécutons quelques exemples de requêtes à l'aide d'un SQL INNER JOIN.

Dans le Listing 4, nous exécutons une requête qui récupère TOUTES les lignes communes à la table Sales.Customers et à la table Sales.Orders. Nous utilisons la colonne custid comme condition pour la jointure.

Notez que la clause ON est un filtre très semblable à une clause WHERE. Nous avons également utilisé des alias pour distinguer les tables.

-- Listing 4: Customer Orders

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

Dans le Listing 5, nous limitons la requête à des colonnes spécifiques à Sales.Customers table et les Sales.Orders table. Nous utilisons le custid colonne comme condition de la jointure.

Notez que la clause ON est un filtre très semblable à une clause WHERE. Nous avons également utilisé des alias pour distinguer les tables.

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

Dans le Listing 6, nous étendons la pensée en introduisant une clause WHERE qui filtre les données pour un seul client. Nous avons également ajouté des alias à la liste des colonnes.

Bien que cela ne soit pas nécessaire dans cet exemple, il existe des cas où vous devez projeter des colonnes portant le même nom à partir des deux tables. Ensuite, les colonnes auront besoin d'une expression sous forme de noms en deux parties, en utilisant les alias ou les noms de table.

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

Dans le listing 7, nous introduisons la colonne custid. On peut distinguer les colonnes en utilisant l'alias, mais on ne peut pas distinguer les deux custid colonnes dans la sortie (voir la figure 4). Nous pouvons résoudre ce problème en utilisant des 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';

Dans le Listing 9, nous ajoutons la table Sales.OrderDetails au mélange. Lorsque vous joignez plus de deux tables, le jeu de résultats des deux premières tables JOIN devient le gauche tableau pour le tableau suivant. Cependant, l'ordre des tables dans une requête JOIN n'affecte pas la sortie finale.

Notez que nous utilisons un caractère générique pour récupérer TOUTES les colonnes de la table 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';

Le Listing 10 présente la table Production.Product qui nous montre les détails du produit associés à la commande.

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

JOIN non Equi

Puisque la clause ON est un filtre, nous pouvons utiliser des opérateurs autres que l'opérateur "=". Les JOIN prennent généralement en charge l'utilisation d'inégalités telles que <,>, !=, = dans la clause ON. Le Listing 11 le démontre.

L'exécution de ces requêtes renverra différents ensembles de résultats.

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

Conclusion

Cet article traite des SQL INNER JOIN et présente des exemples de son utilisation. Il couvrait des scénarios avec deux, trois et quatre tables dans la même requête.

À l'aide de tables associées, nous avons également illustré comment nous pourrions modifier la structure de la requête pour afficher la sortie en fonction de nos besoins. Nous avons également ajouté de brefs exemples de non-Equi JOIN.