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

MERGE:別々のサーバーにあるソーステーブルとターゲットテーブルを更新する

    MERGEステートメントとは何ですか?

    MERGEステートメントを使用すると、ソーステーブルのデータに基づいてターゲットテーブルのデータを変更できます。これを使用して、単一のクエリブロック内のターゲットテーブルに対してINSERT、UPDATE、およびDELETEを実行できます。主キーのように両方のテーブルに共通の列を使用して両方のテーブルを結合します。列データの一致に基づいて、ターゲットテーブルのデータに変更が適用されます。次の画像は、「MERGE」がどのように機能するかを示しています。

    MERGEを使用すると、3つの操作すべてが(INSERT、UPDATE、およびDELETE )であるため、パフォーマンスが向上します。 )は1回のパスで実行されます。ターゲットテーブルの変更を更新するために個別のステートメントを記述する必要はありません。

    マージステートメントはSourceTableを使用します およびDestinationtable。 DestinationTableを変更します SourceTableのデータに基づく 。両方のテーブルは、Mergeステートメントで定義された条件を使用して比較されます。この条件は、SourceTableが宛先テーブルとどのように一致するかを決定します。これは、行を照合するために使用される結合条件のようなものです。

    通常、照合は、主キーなどの一意の識別子を照合することによって実行する必要があります。たとえば、ソーステーブルは NewProduct 宛先はProductmasterで、主キーは ProductID です の場合、マージ条件は次のようになります。

    NewProduct.ProductID=ProductMaster.ProdID

    MERGEステートメントの形式は次のとおりです。

    MERGE target t
    Using source s
    ON joinCondition
    WHEN MATCHED
    THEN updateQuery
    WHEN NOT MATCHED BY TARGET
    THEN insertQuery
    WHEN NOT MATCHED BY SOURCE
    THEN deleteQuery

    ターゲットテーブルのデータを変更するために、MERGEは次のT-SQL句をサポートしています。

    1. 一致した場合
    2. [ターゲットによって]一致しない場合
    3. [ソース別]が一致しない場合

    「WHENMATCHED」句

    この句は、宛先テーブルのレコードを更新または削除する場合に使用されます。ここで、結合された列内のデータが同じである場合、レコードは一致すると見なされます。

    「[ターゲットによって]一致しない場合」句

    レコードがソーステーブルに存在するがターゲットテーブルには存在しない場合、この句は新しいレコードをターゲットテーブルに挿入するために使用されます。

    「[ソースによって]一致しない場合」句

    この句は、ターゲットテーブルの行と一致しないソーステーブルのレコードを削除または更新する場合に使用されます。

    ソースとターゲットが別々のサーバー上にある場合はMERGEを使用します

    この記事では、ソーステーブルとターゲットテーブルが別々のサーバーにある場合に、MERGEを使用して挿入、更新、および削除操作を実行する方法を示します。たとえば、製薬会社は在庫管理ソフトウェアを使用しています。ソフトウェアのマスターデータベースとソフトウェアのトランザクションデータベースは、別々のデータベースサーバー上にあります。設定は次のとおりです。

    同社は注文したいくつかの製品を追加しました。製品の在庫を更新しながら、いくつかのクリーンアッププロセスを実行したいと思います。以下は、実行する必要のあるタスクのリストです。

    1. 商品が在庫にあり、同じ商品が注文された場合は、更新してから在庫を更新します。
    2. 商品が在庫に存在せず、商品の追加が注文された場合は、在庫のある商品を追加します。
    3. 商品が在庫に存在するが注文されていない場合、さらに商品の在庫は、在庫から商品を削除するよりも1年以上更新されません。

    上記のタスクを実行するには、次の手順を実行します。

    1. ## Source_Trn_Tablという名前のグローバル一時テーブルを作成します e。 「TrnOrder」からデータを入力します 」(ソーステーブル) OPENROWSETを使用 コマンドを実行し、データを ## Source_Trn_Tableに保存します 。
    2. MstStock でINSERT、UPDATE、およびDELETE操作を実行します MERGE を使用したテーブル(ターゲットテーブル) 次の条件に基づくキーワード:
      • Product_IDの値の場合 列は##Source_Trn_Tableに存在します と在庫 テーブルを作成し、 MstStockの現在の在庫を更新します テーブル。
      • Product_IDの値の場合 列は##Source_Trn_Tableに存在します ただし、 MstStockには存在しません テーブルに移動し、 MstStockに商品を追加します テーブル。
      • Product_IDの値の場合 列はMstStockに存在します ただし、 ## Source_Trn_Tablには存在しません e、さらに last_stock_update_dateの列の値 1年を超える場合は、 product_idを削除してください MstStockから テーブル。

    フローチャートは次のとおりです。

    デモンストレーション

    まず、 MstStockという名前のターゲットテーブルを作成します およびMstProduct Product_Master TTI412-VM2にあるデータベース サーバ。次のクエリを実行します:

    USE [Product_Master]
    GO
    CREATE TABLE [dbo].[MstProduct](
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Product_ID] [varchar](15) NULL,
    	[Product_Name] [varchar](500) NOT NULL,
    PRIMARY KEY CLUSTERED 
    (
    	[ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
    UNIQUE NONCLUSTERED 
    (
    	[Product_ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    CREATE TABLE [dbo].[MstStock](
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Product_ID] [varchar](5) NOT NULL,
    	[Current_Stock] [int] NULL,
    	[Last_Stock_Update_Date] [datetime] NULL,
    PRIMARY KEY CLUSTERED 
    (
    	[ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
    UNIQUE NONCLUSTERED 
    (
    	[Product_ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO

    次に、両方のテーブルにデータを追加します。

    次のクエリを実行して、 MstProductにデータを追加します テーブル:

    SET IDENTITY_INSERT dbo.MstProduct ON
    GO
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (28, 'MED141', 'Alfimaxin')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (29, 'MED142', 'Zylasonmuc')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (30, 'MED143', 'Rythmoxabid')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (31, 'MED144', 'Omedrozol')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (32, 'MED145', 'Reducurzol')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (33, 'MED146', 'Losapuritriol')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (34, 'MED147', 'Pipepapren')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (35, 'MED148', 'Miraperahex')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (36, 'MED149', 'Durachloridevant')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (37, 'MED151', 'Renachloridenide')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (38, 'MED152', 'Ecopurimuc')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (39, 'MED153', 'Aerocarpambid')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (40, 'MED154', 'Afsitec')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (41, 'MED155', 'Aprozovant')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (42, 'MED156', 'Levopafen')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (43, 'MED157', 'Medrotraxel')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (44, 'MED158', 'Doxxaliq')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (45, 'MED159', 'Betatasine')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (46, 'MED161', 'Ciclopatex')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (47, 'MED162', 'Acadipiphane')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (48, 'MED163', 'Septomapin')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (49, 'MED164', 'Acioxenal')
    INSERT dbo.MstProduct(ID, Product_ID, Product_Name) VALUES (50, 'MED165', 'Natadrolol')
    GO
    SET IDENTITY_INSERT dbo.MstProduct OFF
    GO

    次のクエリを実行して、 MstStockにデータを追加します テーブル:

    insert into MstStock (Product_ID,Current_Stock,Last_Stock_Update_Date) values ('MED145',15,'2018-10-14'),('MED146',20,'2018-10-13'),('MED147',5,'2018-09-10'),('MED150',5,'2018-08-01'),('MED158',0,'2017-10-14'),('MED159',0,'2017-10-14')

    次の「選択」クエリを実行して、テーブルの出力を確認します。

    クエリ:

    Use Product_Master
    Go
    Select * from MstProduct

    出力:

    クエリ:

    Use Product_Master
    Go
    Select * from MstStock

    出力:

    次に、 TrnOrderという名前のソーステーブルを作成します Inventory_Details TTI412-VM1にあるデータベース サーバ。次のクエリを実行します:

    USE [Inventory_Details]
    GO
    CREATE TABLE [dbo].[TrnOrder](
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Product_ID] [varchar](15) NOT NULL,
    	[Ordered_Qty] [int] NULL,
    	[Ordered_Date] [datetime] NULL,
    	[Last_Ordered_Date] [datetime] NULL,
    PRIMARY KEY CLUSTERED 
    (
    	[ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
    UNIQUE NONCLUSTERED 
    (
    	[Product_ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO

    次のクエリを実行して、 MstStockにデータを追加します テーブル:

    insert into TrnOrder (Product_ID,Ordered_Qty,Ordered_Date,Last_Ordered_Date)
    values 
    ('MED145',10,convert(date,getdate()),'2018-10-14'),('MED146',5,convert(date,getdate()),'2018-10-13'),
    ('MED147',15,convert(date,getdate()),'2018-09-10'),('MED150',200,convert(date,getdate()),'2018-08-01') 
    ,('MED169',50,convert(date,getdate()),'2018-10-14'),('MED170',100,convert(date,getdate()),'2018-10-14')

    次の「選択」クエリを実行して、テーブルの出力を確認します。

    クエリ:

    Use Inventory_Details
    Go
    Select * from TrnOrder

    出力:

    リモートSQLServerインスタンスに接続してデータを入力します

    前述したように、「リモートサーバー上に作成されたテーブル」の値を更新したいと思います。次の方法を使用して、リモートデータベースサーバーからデータにアクセスできます。

    1. SQLServerリンクサーバー :リンクサーバーは、リモートSQLServerインスタンスにリンクされているOLEDBデータソースでコマンドを実行するために使用されます。リンクサーバーを使用して、Oracleなどの別のデータベース製品にクエリを実行することもできます。 OLEDBソースは、リンクサーバーとしてMicrosoftAccessおよびExcelにアクセスするように構成できます。
    2. SQLServerのOPENROWSET関数 :OPENROWSET関数を使用すると、リモートOLEDBデータソースでアドホッククエリを実行できます。

    この記事では、 OPENROWSETを使用します リモートテーブルのデータにアクセスする方法。 OPENROWSET関数を使用してリモートサーバーにクエリを実行するには、アドホック分散クエリを有効にする必要があります。 構成パラメーター。

    「アドホック分散クエリ」は高度なオプションであるため、最初に[高度なオプションを表示]を有効にする必要があります。 構成パラメーター。これを行うには、SQL ServerManagementStudioのクエリウィンドウで次のコマンドを実行します。

    exec sp_configure 'show advanced options',1
    reconfigure with override
    Go

    詳細オプションを表示 パラメータが有効になっている場合は、次のクエリを実行してアドホック分散クエリを有効にします :

    sp_configure 'Ad Hoc Distributed Queries', 1;
    RECONFIGURE WITH OVERRIDE;
    GO

    「OPENROWSET」機能を使用して、リモートサーバーのデータを使用してMERGE操作を実行することはできません。これを行うには、最初にリモートサーバーからデータをインポートし、グローバル一時テーブルに保存する必要があります。その後、グローバル一時テーブル内にあるデータを使用して、ターゲットテーブルを更新できます。

    前述したように、最初にリモートテーブルからデータをインポートする必要があります。これを行うには、一時テーブルを作成し、OPENROWSET関数を使用してデータをインポートします。
    次のクエリは、グローバル一時テーブルを作成します。

    use Product_Master
    go
    CREATE TABLE ##Source_Trn_Order
    (
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Product_ID] [varchar](15) NOT NULL,
    	[Ordered_Qty] [int] NULL,
    	[Ordered_Date] [datetime] NULL,
    	[Last_Ordered_Date] [datetime] NULL
    )

    一時テーブルが作成されたら、リモートサーバーにあるソーステーブルからデータをロードしましょう。これを行うには、次のクエリを実行します。

    insert into ##Source_Trn_Order select [Product_ID],[Ordered_Qty],[Ordered_Date],[Last_Ordered_Date]  from 
    OPENROWSET('SQLNCLI', 'Server=TTI609-VM1;Trusted_Connection=yes;',
    'SELECT Product_ID, Ordered_Qty, Ordered_Date,Last_Ordered_Date FROM Inventory_Details.dbo.TrnOrder') AS a;

    ステップ1:商品がMstStock(ターゲットテーブル)とTrnOrder(ソーステーブル)に存在する場合は、MstStockの現在の数量を更新します

    これを行うには、一致した場合を使用します 句。この句は、両方のテーブルの共通の列でソーステーブルとターゲットテーブルを結合します。 Product_ID 列はMstStock間で共通です および##Source_Trn_Table、 したがって、両方のテーブルを結合するために使用します。

    次のコードを実行します:

     MERGE MstStock target_Stock
    USING ##Source_Trn_Order Source_Order
    ON target_Stock.Product_Id = Source_Order.Product_Id 
    WHEN MATCHED THEN
      UPDATE
      SET target_Stock.Current_Stock = Source_Order.Ordered_Qty + target_Stock.Current_Stock, 
    Last_Stock_Update_Date=getdate();

    4つの製品のCurrent_Stock列の値を更新する必要があります。次のクエリを実行して、出力を確認します。

    select b.Product_ID,b.Product_Name,a.Current_Stock,a.Last_Stock_Update_Date from MstStock a inner join MstProduct b on a.Product_ID=b.Product_ID and a.Current_Stock>0

    出力は次のとおりです。

    ステップ2:製品がMstStock(ターゲットテーブル)に存在しない場合は、MstStock(ターゲットテーブル)に追加します

    薬局はいくつかの商品を注文していました。これらの製品はMstProductテーブルに追加されましたが、MstStockテーブルには追加されませんでした。これらの製品をMstStockに追加するには テーブルでは、WHEN NOTMATCHED[TARGET]句を使用します。この句は、共通の列を使用してソーステーブルとターゲットテーブルを結合します。一致する行がターゲットテーブルに見つからない場合は、ソーステーブルから行を挿入します。

    MstStockに商品を追加するには MERGEを使用する テーブルで、次のコードを実行します:

    MERGE mststock target_Stock
    using ##source_trn_order Source_Order
    ON target_Stock.product_id = source_order.product_id
    WHEN matched THEN
      UPDATE SET target_Stock.current_stock = Source_Order.ordered_qty
                                              + target_Stock.current_stock,
                 last_stock_update_date = Getdate()
    WHEN NOT matched BY target THEN
      INSERT (product_id,
              current_stock,
              last_stock_update_date)
      VALUES (Source_Order.product_id,
              Source_Order.ordered_qty,
              Getdate());

    2つの製品ID、 MED169 およびMED170、 追加する必要があります。次のクエリを実行して、出力を確認します。

    select b.Product_ID,b.Product_Name,a.Current_Stock,a.Last_Stock_Update_Date from MstStock a inner join MstProduct b on a.Product_ID=b.Product_ID and a.Current_Stock>0

    以下が出力されます:

    ステップ3:MstStock(ターゲットテーブル)の現在の在庫がゼロで、製品が## Source_Trn_Order(ソーステーブル)にない場合は、MstStock(ターゲットテーブル)からアイテムを削除します

    在庫では、1年以上注文されていないため削除が必要な商品はほとんどありません。したがって、 MstStockからそれらを削除する必要があります テーブルとMstProductsテーブル。これらの製品をMstStockから削除するには 表では、一致しない場合[ソース]を使用できます 。

    一致しない場合[ソース] 句は、共通の列を使用してソーステーブルとターゲットテーブルを結合します。ソーステーブルに一致する行が見つからない場合は、ターゲットテーブルから行が削除されます。

    MstStockから製品を削除するには テーブルで、次のコードを実行します:

    MERGE mststock target_Stock
    using ##source_trn_order Source_Order
    ON target_Stock.product_id = source_order.product_id
    WHEN matched THEN
      UPDATE SET target_Stock.current_stock = Source_Order.ordered_qty
                                              + target_Stock.current_stock,
                 last_stock_update_date = Getdate()
    WHEN NOT matched BY target THEN
      INSERT (product_id,
              current_stock,
              last_stock_update_date)
      VALUES (Source_Order.product_id,
              Source_Order.ordered_qty,
              Getdate())  
    WHEN NOT matched BY SOURCE THEN
      DELETE;

    2つの製品ID、 MED158 およびMED159 追加する必要があります。次のクエリを実行して、出力を確認します。

    select b.Product_ID,b.Product_Name,a.Current_Stock,a.Last_Stock_Update_Date from MstStock a inner join MstProduct b on a.Product_ID=b.Product_ID and a.Current_Stock>0

    以下が出力されます:

    概要

    この記事では、次のように説明しました。

    1. MERGEキーワードとは何ですか?
    2. ソーステーブルとターゲットテーブルを更新するためにMERGEで使用されるさまざまな句。
    3. データベースが異なるサーバー上にある場合にMERGEキーワードを使用してデータを変更する方法。

    便利なツール:

    dbForge Data Compare for SQL Server –ビッグデータを処理できる強力なSQL比較ツール。


    1. アセンブリ'Microsoft.SqlServer.Types'バージョン10以降が見つかりませんでした

    2. T-SQLを使用して「サーバーがRPC用に構成されていない」メッセージ7411を修正する方法

    3. Oracle正規表現。危険な範囲

    4. ユーザーアカウントの管理、役割、権限、認証PHPおよびMySQL