Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 在Powershell中指定具有不同sql源和目标连接的插入列表_Sql Server_Powershell - Fatal编程技术网

Sql server 在Powershell中指定具有不同sql源和目标连接的插入列表

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)]

我有一个powershell脚本,如果我的DEST表中只有“从源服务器选择”中列出的列,但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”,用于 “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年。试图找到一种比在较低版本中重新创建包更简单的方法。下周我会试试你的建议!经过几次调整,它的工作就像一个魅力!(将编辑我的问题以添加对更改内容的评论)再次感谢!