web-dev-qa-db-ja.com

マージするスクリプト-2つのMDFデータベースファイルを複製しますか?

私はコンピューターとタブレットにプログラムを持っています。プログラムはSQLServer Expressを使用して、.MDFファイルからローカルデータベース(両方で同じ情報)と対話します。したがって、タブレットをPCに接続すると、同期する2つの.MDFファイルがあります。

両方のユーザーがデバイスのバージョンを変更できるようにしたいので、両方の.MDFファイルを取得して、それらをマージするスクリプトを実行します。

データベースにはGUID主キーと、最後に変更された日時のDateTimeがあるため、競合がある場合は、最新バージョンを使用します。

どうすればよいですか?

または、これを間違った方法で行っている場合は、インターネットに接続せずにこれら2台のマシンのデータベースを同期させる別の方法をお勧めしますか?

前もって感謝します。

1
Charles Clayton

Microsoft SyncやMerge-Replicationのような既存のツールのほとんどは、やり過ぎであり、価値があるよりも面倒であるように見えました。

これはデータベースを接続するための私のSQLスクリプトです

CREATE DATABASE LocalDatabase  
ON (Filename = 'C:\ProgramData\Clayton\Database.mdf')
   , (Filename = 'C:\ProgramData\Clayton\Database_log.ldf') 
FOR ATTACH;
GO

EXEC sp_addlinkedserver @server='Server'

次に、データベースを同期します

-- update the client from the master 
MERGE [LocalDatabase].[dbo].[tableName] trgt
using [Server].[ServerDatabase].[dbo].[tableName] src

ON trgt.id = src.id 

WHEN matched AND trgt.lastmodified <= src.lastmodified THEN 
  -- if the master has a row newer than the client
  -- update the client                       
  UPDATE SET trgt.[allColumns]      = src.[allColumns],
             trgt.[id]              = src.[id], 
             trgt.[lastmodified]    = src.[lastmodified] 

-- delete any rows added by a client 
WHEN NOT matched BY source 
THEN 
  DELETE 

-- insert any rows added by the master 
WHEN NOT matched BY target 
THEN 
  INSERT ( [allColumns], 
           [id], 
           [lastmodified]) 
  VALUES (src. [allColumns], 
          src.[id], 
          src.[lastmodified]); 


-- now we update the master from the client
-- Note:
-- because the serverDB is a linked server 
-- we can't use another MERGE statement, otherwise
-- we get the error: "The target of a MERGE statement 
-- cannot be a remote table, a remote view, or a view over remote tables."

UPDATE
    serverDB

SET 
    [allColumns]        = [localDB].[allColumns],
    [id]                = [localDB].[id], 
    [lastmodified]      = [localDB].[lastmodified] 

FROM 
     [Server].[ServerDatabase].[dbo].[tableName] serverDB

INNER JOIN
     [LocalDatabase].[dbo].[tableName] localDB

-- update where the id is the same but the client is newer than the master

ON serverDB.id = localDB.id 
       AND localDB.lastmodified >= serverDB.lastmodified
0
Charles Clayton

インターネット接続がなければ、マージまたはピアツーピアレプリケーションを検討することになります。どちらも簡単に実装することはできません(グーグル私はどこかで回避策を見たことを覚えているようです)Expressエディションであなたが望むように。標準版以上のエディションをお持ちの場合は、テーブルごとに追加の列を追加する必要がなく、マージのように競合の解決が含まれるため、個人的にピアツーピアを使用します。ただし、私の意見では、レプリケーションはかなり厄介なテクノロジーであり、効率的に実装およびトラブルシューティングするには中級のDBAスキルが必要であることに注意してください。また、レプリケーションが実装されると、サブスクライバーに配布されるまで、トランザクションログのバックアップまたはチェックポイント(リカバリモデルによって異なります)によってトランザクションをクリアできないことにも注意してください。同期間のコマンドの期間と数によっては、トランザクションログが大きくなり、ディスクがいっぱいになる可能性があります。明らかに、使用可能なディスク容量がいっぱいになると、DBに新しいトランザクションを書き込んだり更新したりすることはできません。

インターネット接続があれば、両方のデバイスが書き込み可能な単一のデータベースを提供するために、間違いなくAzureを検討します。

もちろん、PowerShell、SSIS、C#スクリプトを介してデータをプルしてマージしたり、RedGateデータの試用ライセンスを取得してWindowsのスケジュールされたタスク(SQL Serverエージェントはエクスプレスでは利用できません)を介して開始したりして、次のような作業を行うこともできます。レプリケーションはそのままで実行できます。

ちなみに、使用状況によっては、エンタープライズと同等の開発者版SQLServerライセンスを取得できる場合があります。

編集1:ピアツーピアは、標準で利用可能なマージとは異なり、少なくとも2008r2と2012ではエンタープライズのみの機能です

1
Pixelated

私はPowershellとVB T-SQLよりもはるかに優れていることを知っているので、これらの言語の1つを使用して、各データベースから新しいレコードをプルし、それらをループして、他のデータベースに挿入します。スクリプトは、各データベースの最後のレコードのタイムスタンプを含むファイルを保存し、次に実行したときにその日付より新しいレコードを取得するために使用します。..またはタイムスタンプまたはGUID。

「.mdfsのマージ」という用語は、ファイルを直接読み取って違いをマージしようとしないため、ここで人々を遠ざける可能性があります。各データベースで新しいレコードをクエリし、それらを他のデータベースに挿入するだけです。

他のさまざまな方法でこれにアプローチできます。これは1つにすぎません。

0
Tony Hinkle

既存のテクノロジーであるレプリケーションを見てください。

ドキュメント (強調を追加)によると:

レプリケーションは、データとデータベースオブジェクトをあるデータベースから別のデータベースにコピーして配布し、データベース間で同期して一貫性を維持するための一連のテクノロジです。レプリケーションを使用すると、さまざまな場所やリモートユーザーまたはモバイルユーザーにデータを配布できます。

0
vonPryz