You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

返回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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:02:50