【问题标题】:How can I make bulkCopy map the same columns?如何使 bulkCopy 映射相同的列?
【发布时间】:2019-06-25 09:42:22
【问题描述】:

假设我有一个包含这些列的 SQL 表:

[服务器名称],[SESSION_ID],[SESSION_SPID]

我正在尝试将存储在数据表 ($dmvResult) 中的值复制到上面的 SQL 表 ($Table)

$dmvResult = DMV_Query 'SELECT [SESSION_ID]
      ,[SESSION_SPID]
FROM $SYSTEM.DISCOVER_SESSIONS';

$ConnectionString ='Data Source=$server; Database=$database; Trusted_Connection=True;'
$bulkCopy = new-object Data.SqlClient.SqlBulkCopy($ConnectionString)
$bulkCopy.DestinationTableName=$Table
$bulkCopy.WriteToServer($dmvResult)

虽然复制成功完成,但存在一个问题:它是按位置复制,而不是按列名匹配。换句话说,复制的列没有被映射并复制到相同的列。

[SESSION_ID] 被复制到 [server_name] 并且 [SESSION_SPID] 正在复制到 [SESSION_ID]

如何告诉 bulkCopy 匹配列并进行复制?

结果副本应该是 [server_name] 为空,因为它不是从 DMV 查询中选择的。

我在这个帖子中找到了一个巧妙的解决方案:

https://stackoverflow.com/a/20045505/8397835

但我不知道如何将其转换为我的 powershell 代码:

var meta = definition.Context.Mapping.GetMetaType(typeof(T));
        foreach (var col in meta.DataMembers)
        {
            copy.ColumnMappings.Add(col.Member.Name, col.MappedName);
        }

编辑:foreach column.ColumnName 输出

编辑2: 我试过这个:

$dmvResult.Columns |%{$_.Name}

它不输出任何东西。

在您说 $dmvResult 数据表必须为空之前,请解释一下这实际上如何工作并复制数据?

$bulkCopy.ColumnMappings.Add('SESSION_ID', 'SESSION_ID')
$bulkCopy.ColumnMappings.Add('SESSION_SPID', 'SESSION_SPID')
$bulkCopy.WriteToServer($dmvResult)

由于某种原因,它也将其输出到控制台:

所以数据表 $dmvResult 被清楚地填充了。

我希望不要像这样为每一列定义映射:

$bulkCopy.ColumnMappings.Add('SESSION_SPID', 'SESSION_SPID')

取而代之的是这样的自动选项:

foreach ($column in $dmvResult.Columns) { $bulkCopy.ColumnMappings.Add($column.ColumnName, $column.ColumnName)}

但这会引发异常:

使用“1”个参数调用“WriteToServer”的异常:“给定的 ColumnMapping 与源中的任何列都不匹配,或者 目的地。”

【问题讨论】:

  • 当然是建立一个列映射。这就像 bulkCopy 类中唯一的其他方法。 Here is how you would do it in C# 我不知道如何为你翻译成 PS。可能是$bulkCopy.ColumnMappings.Add($col1, $col2) 之类的?
  • @JacobH 该死,我希望有一个自动映射选项。但看来我必须明确定义列:/
  • @JacobH 我用我认为是自动映射的答案的链接更新了我的线程,尽管我不确定如何将它从 c# 转换为 powershell
  • 哦,有自动映射——它会自动按序号位置映射所有列。是的,这很愚蠢,它可以专门处理DataTable 的情况,但事实并非如此。 foreach ($column in $dmvResult.Columns) { $bulkCopy.ColumnMappings.Add($column.ColumnName, $column.ColumnName) } 应该这样做。 (免责声明:未经测试。)
  • 在循环中加入Write-Output $column.ColumnName 来调试它。列名可能不是您所期望的,特别是如果(我怀疑)这是一个从 SSAS 产生结果的查询,它有修饰列名的趋势。还要检查表是否正确,如果您的数据库使用区分大小写的排序规则,则大小写是否匹配。最后,请记住[name] 只是name 的转义版本——括号实际上不是列名的一部分,所以如果你的表实际上有[SESSION_SPID] 作为列名,那将是错误的。

标签: sql-server powershell dmv


【解决方案1】:

一个非常奇怪的解决方案,但我只需要在$dataset 之前添加一个逗号:

,$dataSet.Tables[0]

在 DMV_Query 函数中

然后我使用了这个 foreach 循环

foreach ($column in $dmvResult.Columns) { $bulkCopy.ColumnMappings.Add($column.ColumnName, $column.ColumnName) > $null }

它成功了!

它现在自动映射列!!

【讨论】:

  • 这个答案令人困惑,因为它与您的 DMV_Query 函数的内部有关,此处未发布。但是,它发布在您的this question 中。至于,的使用:,是PowerShell中的数组构造操作符,在表达式, $dataSet.Tables[0]中它把$dataSet.Tables[0]包裹在一个单元素数组中,这样可以保证$dataSet.Tables[0] - 本身就是一个集合,作为单个对象输出。
  • 没有前面的,,由于PowerShell自动枚举集合,输出的是$dataSet.Tables[0]rows个别.
  • 你刚刚救了我。谢谢!!
猜你喜欢
  • 1970-01-01
  • 2017-04-17
  • 2019-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-11
  • 2020-01-04
相关资源
最近更新 更多