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

PowerShell 5.1查询不同SP版SQL Server 2016返回类型差异原因

环境信息
  • PowerShell 5.1
  • SQL Server 2016 SP1
  • SQL Server 2016 SP3
问题描述

在分别运行SP1、SP3补丁的两个SQL Server 2016数据库上执行完全相同的select top 1查询时,返回结果的类型存在差异,具体测试代码如下:

$res = Invoke-Sqlcmd -Query "select top 1 * from customer" -ServerInstance "(localdb)\MSSQLLocalDB" -Database "Database1" -OutputAs DataTables
$res.GetType()
$res

实际执行结果:一个数据库返回DataTable类型结果,另一个返回DataRow类型结果。

参考执行结果截图:可直观看到两个环境下的类型输出差异。

原因说明

这个差异和SQL Server服务端的SP补丁版本没有直接关系,核心原因是两个环境安装的PowerShell SqlServer模块版本不一致:

  • 老版本SqlServer模块(随SQL Server 2016 RTM、SP1自带的版本,版本号低于21.0.17099)的Invoke-Sqlcmd存在逻辑bug:当指定-OutputAs DataTables参数时,如果查询结果集为0行或≥2行,会正常返回DataTable类型;如果结果集恰好只有1行,会自动拆包返回DataTable内的DataRow对象,和参数声明的返回类型不符。
  • 后续发布的SqlServer模块版本修复了这个逻辑问题,只要指定-OutputAs DataTables,无论结果集行数多少,都固定返回DataTable类型。你环境中返回DataTable的SP3机器,安装的就是修复后的新版模块,返回DataRow的SP1机器仍在使用带bug的老版本模块。

你可以在两个环境分别执行以下命令验证模块版本,就能看到明确的版本差:

Get-Module SqlServer -ListAvailable | Select-Object Version
兼容方案

不需要调整数据库端补丁版本,任选一种方式即可统一返回类型:

  • 把所有环境的SqlServer模块更新到统一的最新版本,从根源上消除行为差异
  • 在现有脚本中增加类型兼容判断,自动把拆包返回的DataRow转回DataTable,代码如下:
$res = Invoke-Sqlcmd -Query "select top 1 * from customer" -ServerInstance "(localdb)\MSSQLLocalDB" -Database "Database1" -OutputAs DataTables
# 兼容老模块单结果拆包问题
if ($res -is [System.Data.DataRow]) {
    $res = $res.Table
}

加完上述判断后,无论模块版本新旧,最终拿到的$res都是统一的DataTable类型,不会再出现类型不一致的问题。


内容的提问来源于stack exchange,提问作者Rod

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 16:03:34