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

PowerShell中向SQL查询IN语句传递多个值的实现问题

现有代码问题排查
  • 直接字符串拼接IN子句的尝试存在两个核心错误:一是拼接的IN值列表缺少外层包裹的(),生成的SQL语法为keycode IN 'val1','val2',不符合SQL语法要求;二是代码存在变量名混用问题:定义SQL文本时用的变量是$sql,创建SqlCommand时传入的是未赋值的$sqlCmd,连接对象也混用了$TargetConnection和$SourceConnection,运行时会直接抛出变量未定义错误。另外这种直接拼接用户值的写法存在SQL注入风险,值中包含单引号时也会触发语法错误,生产环境禁止使用。
  • 参数化查询的尝试存在认知错误:SQL Server原生不支持将单个参数直接展开为IN子句的多值集合,你传入拼接后的单引号包裹字符串时,数据库会将其识别为单个完整字符串值,等价于查询keycode = 'val1'',''val2',完全无法匹配预期结果。此外你将参数长度设置为4,传入的拼接字符串长度超过4时会被强制截断,进一步导致查询异常。
标准实现方案(全SQL Server版本兼容,无注入风险)

采用动态生成对应数量参数占位符的方式实现,是该场景的通用标准方案:

# 初始化数据库连接
$TargetServer = 'server name'
$TargetDatabase = 'db name'
$ConnectionString = "Server=$TargetServer;Database=$TargetDatabase;Trusted_Connection=$true;"
$TargetConnection = New-Object System.Data.SqlClient.SqlConnection($ConnectionString)
$TargetConnection.Open()

# 替换为你实际的待查询keycode集合
$keycodeList = $said.Saidkeycode
# 为每个值生成独立的参数占位符,例如3个值时生成@SAID0,@SAID1,@SAID2
$paramHolders = for ($i = 0; $i -lt $keycodeList.Count; $i++) { "@SAID$i" }
$inSection = $paramHolders -join ','

# 构造SQL语句
$sql = @"
SELECT
    incidentid AS EVENT_LIFECYCLE_VALUE,
    Priority AS Priority_Code,
    keycode AS ASSET_KEY,
    Description AS EVENT_DATA,
    CreatedDateTime AS [Opened],
    ClosedDateTime AS [Closed]
FROM incident
WHERE keycode IN ($inSection)
AND Priority IN (1, 2)
AND CONVERT(date, CreatedDateTime) <= DATEADD(DAY, -2, CONVERT(date, GETDATE()))
AND CreatedDateTime >= DATEADD(DAY, -90, GETDATE())
ORDER BY EVENT_LIFECYCLE_VALUE
"@

$command = New-Object System.Data.SqlClient.SqlCommand($sql, $TargetConnection)
# 逐个绑定参数值,VarChar长度请匹配你表中keycode字段的实际定义长度
for ($i = 0; $i -lt $keycodeList.Count; $i++) {
    [void]$command.Parameters.Add("@SAID$i", [Data.SqlDbType]::VarChar, 50)
    $command.Parameters["@SAID$i"].Value = $keycodeList[$i]
}

# 读取查询结果
$reader = $command.ExecuteReader()
$incidents = @()
while ($reader.Read())
{
    $row = @{}
    for ($j = 0; $j -lt $reader.FieldCount; $j++)
    {
        $row[$reader.GetName($j)] = $reader.GetValue($j)
    }
    $incidents += [pscustomobject]$row            
}
$reader.Close()
$TargetConnection.Close()

可选简化方案(仅支持SQL Server 2016及以上版本)

如果你的数据库版本支持内置STRING_SPLIT函数,可以不用动态生成参数,直接传入单个分隔字符串即可,代码更简洁:

# SQL语句修改为以下写法
$sql = @"
SELECT
    incidentid AS EVENT_LIFECYCLE_VALUE,
    Priority AS Priority_Code,
    keycode AS ASSET_KEY,
    Description AS EVENT_DATA,
    CreatedDateTime AS [Opened],
    ClosedDateTime AS [Closed]
FROM incident
WHERE keycode IN (SELECT value FROM STRING_SPLIT(@SAID, ','))
AND Priority IN (1, 2)
AND CONVERT(date, CreatedDateTime) <= DATEADD(DAY, -2, CONVERT(date, GETDATE()))
AND CreatedDateTime >= DATEADD(DAY, -90, GETDATE())
ORDER BY EVENT_LIFECYCLE_VALUE
"@

$command = New-Object System.Data.SqlClient.SqlCommand($sql, $TargetConnection)
# 直接绑定逗号分隔的原值字符串,不需要额外拼接单引号
[void]$command.Parameters.Add("@SAID", [Data.SqlDbType]::VarChar, -1)
$command.Parameters["@SAID"].Value = $said.Saidkeycode -join ','

# 后续结果读取逻辑和上述标准方案完全一致

注意:该方案要求待传入的keycode值本身不能包含英文逗号,否则会出现拆分错误。

如果你使用DataAdapter+DataSet的方式获取结果,在调用Fill($dataSet)方法后,直接访问$dataSet.Tables[0]即可拿到查询返回的结果表,可直接遍历或转换为PowerShell自定义对象使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 13:00:53