返回Array而非Hashtable问题及PowerShell脚本技术咨询
解决PowerShell中Invoke-Sqlcmd返回数组而非哈希表的问题
嘿,我看到你在写PowerShell脚本调用SQL查询时,碰到了返回结果是数组而不是哈希表的问题。这其实是Invoke-Sqlcmd的默认行为导致的,咱们一步步来解决它。
为什么返回的是数组而非哈希表?
Invoke-Sqlcmd执行查询后,默认返回的是**DataRow对象的数组**——每个DataRow虽然能像哈希表那样通过列名取值(比如$result.ColumnName),但它本质上不是哈希表类型。如果你的代码逻辑需要严格的哈希表结构,就得手动做转换。
先补全你的脚本(针对截断部分的合理假设)
你提供的脚本最后截断了,我假设$queries对象里有个Queries属性存储要执行的查询列表,补全后的完整脚本如下:
$reportsFolder = $PSScriptRoot; $reportServerDbInstance = "localhost"; $dbName = "dbname"; function Execute-Query{ Param( [parameter(position=0)] $query, [parameter(position=1)] $execDb ) Invoke-Sqlcmd -Query $query -ServerInstance $reportServerDbInstance -Database $execDb -ErrorAction 'Stop' } function Test-ReportQuery($query, $execDb) { Execute-Query -query $query -execDb $execDb } function Test-ReportQueries($reportName, $queries) { foreach($q in $queries.Queries) { # 补全截断的查询遍历逻辑 $result = Test-ReportQuery -query $q.Text -execDb $dbName # 此时$result是DataRow数组,不是哈希表 Write-Host "当前结果类型: $($result.GetType().FullName)" } }
两种转换为哈希表的方案
根据你的查询返回行数,选对应的方法:
方案1:查询返回单行数据 → 转为单个哈希表
如果你的查询只会返回一行结果,直接把DataRow转成哈希表即可:
function Execute-Query{ Param( [parameter(position=0)] $query, [parameter(position=1)] $execDb ) $sqlResult = Invoke-Sqlcmd -Query $query -ServerInstance $reportServerDbInstance -Database $execDb -ErrorAction 'Stop' if ($sqlResult) { $hashTable = @{} # 遍历DataRow的所有列,存入哈希表 $sqlResult | Get-Member -MemberType NoteProperty | ForEach-Object { $hashTable[$_.Name] = $sqlResult.$($_.Name) } return $hashTable } return $null }
方案2:查询返回多行数据 → 转为哈希表数组
如果查询有多行结果,就把每一行都转成哈希表,最终返回哈希表的数组:
function Execute-Query{ Param( [parameter(position=0)] $query, [parameter(position=1)] $execDb ) $sqlResults = Invoke-Sqlcmd -Query $query -ServerInstance $reportServerDbInstance -Database $execDb -ErrorAction 'Stop' # 遍历每一行DataRow,转成哈希表 return $sqlResults | ForEach-Object { $rowHash = @{} $_ | Get-Member -MemberType NoteProperty | ForEach-Object { $rowHash[$_.Name] = $_."$($_.Name)" } $rowHash } }
简化版转换(PowerShell 7+适用)
如果你用的是PowerShell 7或更高版本,可以用内置的ConvertTo-Hashtable命令简化转换,同时排除DataRow自带的无关属性:
# 单行转换 $hashTable = $sqlResult | Select-Object -First 1 -Property * -ExcludeProperty RowError, RowState, Table, ItemArray, HasErrors | ConvertTo-Hashtable # 多行转换 $hashArray = $sqlResults | ForEach-Object { $_ | Select-Object -Property * -ExcludeProperty RowError, RowState, Table, ItemArray, HasErrors | ConvertTo-Hashtable }
如果你还在使用PowerShell 5.1,没有内置的
ConvertTo-Hashtable,可以自己实现一个:function ConvertTo-Hashtable { param( [Parameter(ValueFromPipeline)] [PSObject]$InputObject ) process { $hash = @{} $InputObject.PSObject.Properties | ForEach-Object { $hash[$_.Name] = $_.Value } return $hash } }
验证转换效果
修改Test-ReportQuery函数,打印转换后的类型,确认是否符合预期:
function Test-ReportQuery($query, $execDb) { $result = Execute-Query -query $query -execDb $execDb Write-Host "转换后结果类型: $($result.GetType().Name)" return $result }
单行结果会输出Hashtable,多行则输出Object[](数组内每个元素都是哈希表)。
内容的提问来源于stack exchange,提问作者Dmitrij Kultasev
相关产品推荐
相关产品推荐

