sql >> データベース >  >> RDS >> Sqlserver

SQLServer内部結合の基本と例

    はじめに

    T-SQLを使用すると、複数のテーブルのレコードを組み合わせて、単一の結果セットとして返すことができます。これは、SQLServerの結合の概念によって実現されます。

    リレーショナルデータベースのデータは通常正規化されているため、この機会が必要になることがよくあります。たとえば、従業員データが2つ以上のテーブルに分散しているとします。最初のテーブルは基本的な顧客データであり、従業員と呼ばれます。 2番目のテーブルは部門になります 。

    データの一貫性には、顧客と部門の間の正しい関係が必要です。一連の従業員とその部門の完全なデータを返すには、両方のテーブルを結合する必要があります。

    SQL結合操作には、3つ以上のテーブルを含めることもできます。

    テーブル間にこのような外部キー関係が存在するもう1つのケースは、要約です。 および詳細 テーブル。

    AdventureWorksまたはWideWorldImportersサンプルデータベースを使用したことがある人は、 Sales.Ordersに精通しています。 およびSales.OrderDetailsテーブル。この場合、後者には Sales.Ordersに記録された各注文の詳細が含まれます テーブル。 2つのテーブルには、順序に基づいた関係があります。 したがって、JOINSを使用して、両方のテーブルから単一の結果セットとしてデータを取得できます。

    SQLServer結合の種類

    T-SQLでは、次の種類の結合が可能です。

    1. 内部参加 クエリに関係するすべてのテーブルに共通するすべてのレコードを返します。
    2. 左(外側)に参加 からすべてのレコードを返します テーブルとのすべてのレコード 左側のテーブルにもあるテーブル。 という用語 および正しい JOIN句に対するテーブルの位置を参照してください。
    3. 右(外部)参加 からすべてのレコードを返します テーブルとのすべてのレコード 左側のテーブルにもあるテーブル。用語は前のケースと同様です。
    4. 完全な外部参加 両方のテーブルに共通するすべてのレコードに加えて、両方のテーブルからの他のすべてのレコードを返します。他のテーブルに対応する行がない列は、 NULLを返します
    5. クロスジョイン デカルト結合とも呼ばれます 、両方のテーブルからのデータのデカルト積を返します。したがって、テーブルAの各行の最終結果セットには、テーブルBのすべての行のマッピングが含まれ、その逆も同様です。

    この記事では、SQL内部結合に焦点を当てます。

    サンプルテーブル

    内部結合の概念を示すために、ItzikBen-Ganによって構築されたTSQLV4データベースの3つの関連テーブルを使用します。

    次のリストは、これらのテーブルの構造を示しています。

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

    Sales.Ordersのcustid列間の外部キーの関係に注意してください。 およびSales.Customersのcustid列

    JOINを実行するには、JOINベースなどの共通列を指定する必要があります。

    JOINクエリを実行するために外部キーの関係を厳密に要求する必要はありませんが、結果セットを決定する列は比較可能である必要があります。

    外部キーは、特に外部キー列にインデックスが付けられている場合に、JOINクエリの改善にも役立ちます。

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

    サンプルクエリ SQLINNERJOINを使用

    SQLINNERJOINを使用していくつかのサンプルクエリを実行してみましょう。

    リスト4では、Sales.CustomersテーブルとSales.Ordersテーブルに共通するすべての行をフェッチするクエリを実行します。結合の条件としてcustid列を使用します。

    ON句はWHERE句に非常によく似たフィルタであることに注意してください。また、テーブルを区別するためにエイリアスを使用しました。

    -- Listing 4: Customer Orders
    
    use TSQLV4
    go
    select * from Sales.Customers sc
    inner join Sales.Orders so
    on sc.custid=so.custid;

    リスト5では、クエリを特定の列に絞り込み、 Sales.Customers テーブルとSales.Orders テーブル。 custidを使用します 結合の条件としての列。

    ON句がWHERE句と非常によく似たフィルタであることに注意してください。また、テーブルを区別するためにエイリアスを使用しました。

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

    リスト6では、単一の顧客のデータをフィルター処理するWHERE句を導入することで考え方を拡張しています。また、列リストにエイリアスを追加しました。

    この例では必要ありませんが、両方のテーブルから同じ名前の列を投影する必要がある場合があります。次に、テーブルのエイリアスまたは名前を使用して、列に2つの部分からなる名前としての式が必要になります。

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

    リスト7では、custid列を紹介します。エイリアスを使用して列を区別することはできますが、2つの custid を区別することはできません。 出力の列(図4を参照)。エイリアスを使用してこれを修正できます:

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

    リスト9では、Sales.OrderDetailsテーブルをミックスに追加しています。 3つ以上のテーブルを結合すると、最初の2つのテーブルJOINの結果セットがになります。 次のテーブルのテーブル。ただし、JOINクエリ内のテーブルの順序は、最終的な出力には影響しません。

    ワイルドカードを使用して、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';

    リスト10は、注文に関連付けられた製品の詳細を示すProduction.Productテーブルを示しています。

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

    非等価結合

    ON句はフィルターであるため、「=」演算子以外の演算子を使用できます。 JOINは通常、ON句での<、>、!=、=<、=>などの不等式の使用をサポートします。リスト11はこれを示しています。

    これらのクエリを実行すると、異なる結果セットが返されます。

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

    結論

    この記事では、SQL INNER JOINについて説明し、その使用例を示しました。同じクエリに2つ、3つ、および4つのテーブルがあるシナリオについて説明しました。

    関連するテーブルを使用して、要件に応じて出力を表示するためにクエリ構造を変更する方法も示しました。非等価JOINの簡単な例も追加しました。


    1. SQL Server(T-SQL)でデータベースの照合を設定する方法

    2. SQLServerのパフォーマンスのボトルネックについて話す

    3. SQL Server2014CTP1での優先度の低いロック待機オプションの調査

    4. SQL Server ManagementStudioおよびTransactSQLでのGOの使用は何ですか?