为何SQLCMD存储的输出仅含Length属性无列名?能否保留属性?
SQLCMD输出仅含Length属性的原因及解决方案
这个问题我刚好碰到过,来给你拆解一下:
首先,为什么SQLCMD的输出只有Length属性?
因为sqlcmd.exe是原生的命令行工具,默认输出的是纯文本字符串数组,而不是像Invoke-Sqlcmd那样返回带列名的PowerShell自定义对象(PSObject)。你存储到变量里的其实是一堆普通字符串,自然只有字符串自带的Length属性,看不到SQL查询的列名。
那能不能让SQLCMD保留列属性?当然可以!关键是让SQLCMD输出结构化格式,再转换成PowerShell可识别的对象,这样既保留SQLCMD的性能优势,又能拿到带列名的结果。
下面给你两种实用的实现方式:
方式1:输出XML格式并转换为PSObject
XML是SQLCMD支持的结构化输出格式,转换后能完整保留列名和值:
# 用SQLCMD执行查询并输出XML文件 sqlcmd -S "你的服务器名" -d "你的数据库名" -Q "SELECT * FROM 你的表名" -o "temp_output.xml" -y 0 -XML # 读取XML并转换为带列名的PSObject $results = [xml](Get-Content "temp_output.xml") | Select-Xml -XPath "/root/row" | ForEach-Object { $rowObj = [PSCustomObject]@{} # 遍历XML节点的属性(对应SQL列名和值) $_.Node.Attributes | ForEach-Object { $rowObj | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value } $rowObj } # 现在可以直接访问列名了 $results | Select-Object 列名1, 列名2
参数说明:-y 0表示不截断长字符串,-XML指定输出XML格式。
方式2:输出CSV格式并导入为对象
如果更习惯CSV格式,也可以用这种方式:
# 用SQLCMD输出CSV(-h -1会禁用默认列头,我们后续手动添加) sqlcmd -S "你的服务器名" -d "你的数据库名" -Q "SELECT * FROM 你的表名" -o "temp_output.csv" -s "," -W -h -1 # 单独获取列名(用一次轻量的TOP 0查询,几乎无性能开销) $columnNames = Invoke-Sqlcmd -ServerInstance "你的服务器名" -Database "你的数据库名" -Query "SELECT TOP 0 * FROM 你的表名" | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name # 导入CSV并绑定列名 $results = Import-Csv "temp_output.csv" -Header $columnNames
参数说明:-s ","指定逗号为分隔符,-W去掉输出中的多余空格,-h -1避免输出重复的列头。
关于你提到的echo问题
你用echo $var或echo $var[0,1,2]看不到属性,是因为此时$var是字符串数组,echo只是输出字符串内容。转换成PSObject后,你可以用$results | Get-Member看到所有列属性,或者直接通过$results[0].列名访问具体值。
这种方式完全适合每分钟/每小时执行的定时脚本,既保留了SQLCMD的高性能,又解决了结构化输出的需求。
内容的提问来源于stack exchange,提问作者user630702




