Sql server 在Powershell中指定具有不同sql源和目标连接的插入列表
我有一个powershell脚本,如果我的DEST表中只有“从源服务器选择”中列出的列,但DEST表中有更多列,则该脚本可以工作。我还没有找到任何关于如何从dest表中指定要插入的列的示例。请注意,SourceServer和DestServer不是链接的服务器Sql server 在Powershell中指定具有不同sql源和目标连接的插入列表,sql-server,powershell,Sql Server,Powershell,我有一个powershell脚本,如果我的DEST表中只有“从源服务器选择”中列出的列,但DEST表中有更多列,则该脚本可以工作。我还没有找到任何关于如何从dest表中指定要插入的列的示例。请注意,SourceServer和DestServer不是链接的服务器 Param ( #[parameter(Mandatory = $true)] [string] $SrcServer = "SourceServer", [parameter(Mandatory = $true)]
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”,用于
“SqlBulkCopy”输入“System.Data.SqlClient.SqlBulkCopyOptions”:
“无法转换值
“[System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity”以键入
“System.Data.SqlClient.SqlBulkCopyOptions”。错误:“无法匹配”
标识符名称
[System.Data.SqlClient.SqlBulkCopyOptions]::将PidEntity保留为有效的
枚举器名称。请指定以下枚举数名称之一,然后重试
同样:Default、KeepIdentity、CheckConstraints、TableLock、KeepNulls、,
FireTriggers,UseInternalTransaction,
AllowEncryptedValueModifications“”
所以我改成了这个,一切都正常了:
$bulkCopy = New-Object Data.SqlClient.SqlBulkCopy($DestSqlConnection, [System.Data.SqlClient.SqlBulkCopyOptions]::KeepIdentity,$DestSqlTransaction)
要执行手动列映射。如果不指定映射,那么据我所知,
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;`
integratedsecurity=True
说,“对当前登录的用户使用passthrough Windows身份验证。”user ID=$UID;密码=$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
块,但是对于快速而肮脏的重写来说,这是可行的。我认为这样做不会遇到分布式事务问题,但我可能错了。当我需要这种类型的数据泵时,我倾向于使用SSI或链接服务器。谢谢您的详细回答!我对Powershell的唯一体验是我可以通过谷歌搜索找到的。这个脚本主要基于我通过SSIS设置的这些类型的项目,但是我们的服务器已经过时(我相信是2012年),我所有的项目都是在2015年。试图找到一种比在较低版本中重新创建包更简单的方法。下周我会试试你的建议!经过几次调整,它的工作就像一个魅力!(将编辑我的问题以添加对更改内容的评论)再次感谢!