我有这个powershell脚本,如果我的DEST表只有从我的SOURCE服务器中选择列中列出的列,但是DEST表有更多,那么它将起作用。我无法找到任何提供如何指定我要插入的dest表中的列的示例的内容。请注意,SourceServer和DestServer不是链接服务器。
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;
它给出了错误:
无法转换参数“1”,其值为: “[System.Data.SqlClient.SqlBulkCopyOptions] :: KeepIdentity”,for “SqlBulkCopy”键入“System.Data.SqlClient.SqlBulkCopyOptions”: “无法转换价值 键入“[System.Data.SqlClient.SqlBulkCopyOptions] :: KeepIdentity” “System.Data.SqlClient.SqlBulkCopyOptions”。错误:“无法匹配 标识符名称 [System.Data.SqlClient.SqlBulkCopyOptions] :: KeepIdentity为有效 枚举器名称。指定以下枚举器名称之一并尝试 再次:默认,KeepIdentity,CheckConstraints,TableLock,KeepNulls, FireTriggers,UseInternalTransaction, AllowEncryptedValueModifications “”
所以相反我把它改成了这一切,一切正常:
$bulkCopy = New-Object Data.SqlClient.SqlBulkCopy($DestSqlConnection, [System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity,$DestSqlTransaction)
答案 0 :(得分: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');
但是,您的脚本存在许多其他问题。
您的连接字符串身份验证部分是无意义的:
`Integrated Security=True; User ID=$UID; Password=$PWD;`
Integrated Security=True
说,"对当前登录的用户使用直通Windows身份验证。" 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)
我可能错了,但我很确定你在这里尝试将两个变量作为一个参数传递。与您的ConnectionString
功能一样,我也不认为您不想在这里使用括号。无论如何,它在语法上都令人困惑。这样做:
$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或链接服务器。