2017-10-26 10 views
1

私のDESTテーブルには自分のSOURCEサーバからの選択に列挙されているが、DESTテーブルにはより多くの列がある場合に動作するPowerShellスクリプトがあります。私が挿入したいdestテーブルから列を指定する方法の例を示すものは何も見つかりませんでした。 SourceServerとDestServerはリンクサーバーではありません。Powershellで異なるSQLソースとdest接続を持つリストに挿入を指定します。

Param ( 
    #[parameter(Mandatory = $true)] 
    [string] $SrcServer = "SourceServer", 
    [parameter(Mandatory = $true)] 
    [string] $SrcDatabase = "SourceDb", 
    #[parameter(Mandatory = $true)] 
    [string] $SrcTable = "stage.InternalNotes", 
    #[parameter(Mandatory = $true)] 
    [string] $DestServer = "DestServer", 
    #[parameter(Mandatory = $true)] 
    [string] $DestDatabase = "DestDb", 
    [parameter(Mandatory = $true)] 
    [string] $DestTable = "dbo.InternalNotes", 
) 

Function ConnectionString([string] $ServerName, [string] $DbName) 
{ 
    "Data Source=$ServerName;Initial Catalog=$DbName;Integrated Security=True;User ID=$UID;Password=$PWD;" 
} 

$SrcConnStr = ConnectionString $SrcServer $SrcDatabase 
$SrcConn = New-Object System.Data.SqlClient.SQLConnection($SrcConnStr) 
$CmdText = "SELECT 
    ino.UserId 
    ,ino.StoreId 
    ,ino.PostedById 
    ,ino.DatePosted 
    ,ino.NoteSubject 
    ,ino.NoteText 
    ,ino.NoteType 
    ,ino.Classify 
    ,ino.CreatedBy 
    ,ino.CreatedUtc 
    ,IsReadOnly = 0 
FROM 
    stage.InternalNotes AS ino 
" 
$SqlCommand = New-Object system.Data.SqlClient.SqlCommand($CmdText, $SrcConn) 
$SrcConn.Open() 
[System.Data.SqlClient.SqlDataReader] $SqlReader = $SqlCommand.ExecuteReader() 

Try 
{ 
    $DestConnStr = ConnectionString $DestServer $DestDatabase 
    $bulkCopy = New-Object Data.SqlClient.SqlBulkCopy($DestConnStr, [System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity) 
    $bulkCopy.DestinationTableName = $DestTable 
    $bulkCopy.WriteToServer($sqlReader) 
} 
Catch [System.Exception] 
{ 
    $ex = $_.Exception 
    Write-Host $ex.Message 
} 
Finally 
{ 
    Write-Host "Table $SrcTable in $SrcDatabase database on $SrcServer has been copied to table $DestTable in $DestDatabase database on $DestServer" 
    $SqlReader.close() 
    $SrcConn.Close() 
    $SrcConn.Dispose() 
    $bulkCopy.Close() 
} 

基本的に、私はこれを行うことができるようする必要があります:それは好きではなかったいくつかの理由について

:すべては受け入れ答えに基づいて動作するようになった後

INSERT INTO dbo.InternalNotes --DEST Server table 
    (
    userID 
    ,StoreID 
    ,PostedByID 
    ,DatePosted 
    ,NoteSubject 
    ,NoteText 
    ,NoteType 
    ,Classify 
    ,CreatedBy 
    ,CreatedDateUTC 
    ,IsReadOnly 
    ) 
SELECT 
    ino.UserId 
    ,ino.StoreId 
    ,ino.PostedById 
    ,ino.DatePosted 
    ,ino.NoteSubject 
    ,ino.NoteText 
    ,ino.NoteType 
    ,ino.Classify 
    ,ino.CreatedBy 
    ,ino.CreatedUtc 
    ,IsReadOnly = 0 
FROM 
    stage.InternalNotes AS ino --SOURCE Server table 

編集をライン:

$bulkCopy = New-Object -TypeName Data.SqlClient.SqlBulkCopy -ArgumentList $DestSqlConnection, [System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity, $DestSqlTransaction; 

それがエラーを与えた:

Cannot convert argument "1", with value: "[System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity", for "SqlBulkCopy" to type "System.Data.SqlClient.SqlBulkCopyOptions": "Cannot convert value "[System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity" to type "System.Data.SqlClient.SqlBulkCopyOptions". Error: "Unable to match the identifier name [System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity to a valid enumerator name. Specify one of the following enumerator names and try again: Default, KeepIdentity, CheckConstraints, TableLock, KeepNulls, FireTriggers, UseInternalTransaction, AllowEncryptedValueModifications""

だから代わりに、私はこれにそれを変更し、すべてが働いた:

$bulkCopy = New-Object Data.SqlClient.SqlBulkCopy($DestSqlConnection, [System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity,$DestSqlTransaction) 

答えて

1

は、you need to populate SqlBulkCopy.ColumnMappingsを手動列マッピングを行うには。マッピングを指定しない場合は、SqlBulkCopyが選択リストの最初の列を引き継ぐか、DataRowが宛先テーブルの最初の序数列に入ります。例えば

$bulkCopy.DestinationTableName = $DestTable; 
$bulkCopy.ColumnMappings.Add('sourceColumn1','destinationColumn1'); 
$bulkCopy.ColumnMappings.Add('sourceColumn2','destinationColumn2'); 
$bulkCopy.ColumnMappings.Add('sourceColumn3','destinationColumn3'); 
$bulkCopy.ColumnMappings.Add('sourceColumn4','destinationColumn4'); 
$bulkCopy.ColumnMappings.Add('sourceColumn5','destinationColumn5'); 

しかし、あなたのスクリプトと他の多くの問題があります。 、「現在ログオンしているユーザーで使用パススルーWindows認証。」

`Integrated Security=True; User ID=$UID; Password=$PWD;` 

Integrated Security=Trueは言う:

あなたの接続文字列認証部はナンセンスですUser ID=$UID; Password=$PWD;には、「指定したユーザー名とパスワードでSQL認証を使用する」と記載されています。両方を行うことはできません。 どちらか一方のみを指定してください。

$SqlCommand = New-Object system.Data.SqlClient.SqlCommand($CmdText, $SrcConn) 
[...] 
$bulkCopy = New-Object Data.SqlClient.SqlBulkCopy($DestConnStr, [System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity) 

私は間違っているかもしれませんが、ここでは2つの変数を1つの引数として渡そうとしています。 ConnectionStringの機能と同じように、私はここにカッコが欲しくないとは思いません。いずれにせよ、それは構文的に混乱している。代わりに、次の操作を行います。その最後の1の

$SqlCommand = New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList $CmdText, $SrcConn 
[...] 
$bulkCopy = New-Object -TypeName Data.SqlClient.SqlBulkCopy -ArgumentList $DestConnStr, [System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity 

いえば、私はそれで別の問題があります。 SqlBulkCopyは強力ですが、実際にはそれを保持する必要があります。既定では、SqlBulkCopyはトランザクションの利点とともに実行されません。つまり、途中でエラーが発生した場合は、データが部分的に更新されていることを意味します。内部トランザクションを有効にすることはできますが、挿入の最新のバッチのみがロールバックされます。あなたは本当にすべての結果を得るために自分のトランザクションを管理する必要があります。

ですから、このようなものになってしまいます:

Try { 
    $DestConnStr = ConnectionString $DestServer $DestDatabase 

    # We have to open the connection before we can create the transaction 
    $DestSqlConnection = New-Object -TypeName System.Data.SqlClient.SqlConnection -ArgumentList $DestConnStr; 
    $DestSqlConnection.Open(); 
    $DestSqlTransaction = $DestSqlConnection.BeginTransaction(); 
    $bulkCopy = New-Object -TypeName Data.SqlClient.SqlBulkCopy -ArgumentList $DestSqlConnection, [System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity, $DestSqlTransaction; 
    $bulkCopy.DestinationTableName = $DestTable 
    $bulkCopy.ColumnMappings.Add('sourceColumn1','destinationColumn1'); 
    $bulkCopy.ColumnMappings.Add('sourceColumn2','destinationColumn2'); 
    $bulkCopy.ColumnMappings.Add('sourceColumn3','destinationColumn3'); 
    $bulkCopy.ColumnMappings.Add('sourceColumn4','destinationColumn4'); 
    $bulkCopy.ColumnMappings.Add('sourceColumn5','destinationColumn5'); 

    Try { 
     $bulkCopy.WriteToServer($sqlReader) 
     # Commit on success 
     $DestSqlTransaction.Commit(); 
    } 
    Catch { 
     # Rollback on error 
     $DestSqlTransaction.Rollback(); 
     # Rethrow the error to the outer catch block 
     throw ($_); 
    } 
} 
Catch [System.Exception] { 
    $ex = $_.Exception 
    Write-Host $ex.Message 
} 
Finally { 
    [...] 
} 

私はネストされたtryブロックを好きではないので、私はおそらく上記より書き換えると思いますが、迅速かつ汚いリライトのために、これは動作します。私はあなたがこれを行う分散トランザクションの問題で任意の問題に遭遇するとは思わないが、私は間違っている可能性があります。私はこの種のデータポンプが必要なときにSSISまたはリンクサーバーを使用する傾向があります。

+0

詳細な回答ありがとうございます!私のPowershellでの私の唯一の経験は、私のGoogle検索で見つけられるものです。このスクリプトは、ほとんどがhttps://blogs.technet.microsoft.com/heyscriptingguy/2011/05/06/use-powershell-to-copy-a-table-between-two-sql-server-instances/に基づいていました。これらのタイプのプロジェクトはSSISでセットアップされていますが、私たちのサーバーはかなり古くなっています(2012年は私が信じています)、私のプロジェクトはすべて2015年です。下位バージョンでパッケージを再作成するより簡単な方法を探しています。私は来週あなたの提案を試してみましょう! – Doolius

+0

カップルで微調整して、魅力的に機能しています! (変更されたものに関するコメントを追加するために私の質問を編集する)もう一度ありがとう! – Doolius

関連する問題