鉴于这个简单的Access数据库表:
ID fruit count
-- ----- -----
1 apples 10
2 oranges 2
我的目标是编写一个Powershell cmdlet(我们称之为Set-FruitCount
),根据水果的名称,可以设置该水果的数量。例如,命令Set-FruitCount -Fruit Apples -Count 1
应更新ID为1的行以将计数设置为1.当然,我的用例更复杂,但我为了一个明确的问题尽可能地尝试简化问题。
但是,在尝试执行参数化更新查询时,它不起作用。但是,在几乎相同的查询中对特定值进行硬编码,只是参数化实际的WHERE子句而不是set子句,它确实有效。
这是我的计划:
$oConn = New-Object System.Data.OleDb.OleDbConnection "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\pvz\Documents\fruits.mdb"
$oConn.open()
function Get-Fruits {
$TextInfo = (Get-Culture).TextInfo
$oCmd = New-Object System.Data.OleDb.OleDbCommand("SELECT * FROM [fruits]", $oConn)
$oReader = $oCmd.ExecuteReader()
while ($oReader.Read()) {
$obj = New-Object PSObject
for ($i = 0; $i -lt $oReader.FieldCount; $i++) {
$Name = $TextInfo.ToTitleCase($oReader.GetName($i))
$Value = $oReader[$i]
$obj | Add-Member -Type NoteProperty -Name $Name -Value $Value
}
$obj
}
$oReader.Close()
}
function Set-FruitCount {
Param($Fruit, $Count)
$strQuery = "UPDATE [fruits] SET [count] = @COUNT WHERE [fruit] = @FRUIT"
$oCmd = New-Object System.Data.OleDb.OleDbCommand($strQuery, $oConn)
[void]$oCmd.Parameters.Add("@FRUIT", $Fruit)
[void]$oCmd.Parameters.Add("@COUNT", $Count)
$ret = $oCmd.ExecuteNonQuery()
Write-Host "Set-FruitCount affected $ret rows"
}
function Set-FruitCountToZero {
Param($Fruit)
$strQuery = "UPDATE [fruits] SET [count] = 0 WHERE [fruit] = @FRUIT"
$oCmd = New-Object System.Data.OleDb.OleDbCommand($strQuery, $oConn)
[void]$oCmd.Parameters.Add("@FRUIT", $Fruit)
$ret = $oCmd.ExecuteNonQuery()
Write-Host "Set-FruitCountToZero affected $ret rows"
}
Get-Fruits | Format-Table
Set-FruitCountToZero -Fruit "apples"
Get-Fruits | Format-Table
Set-FruitCount -Fruit "apples" -Count 1
Get-Fruits | Format-Table
$oConn.close()
这是输出:
PS C:\Users\pvz\desktop> .\fruits.ps1
ID Fruit Count
-- ----- -----
1 apples 10
2 oranges 2
Set-FruitCountToZero affected 1 rows
ID Fruit Count
-- ----- -----
1 apples 0
2 oranges 2
Set-FruitCount affected 0 rows
ID Fruit Count
-- ----- -----
1 apples 0
2 oranges 2
PS C:\Users\pvz\desktop>
正如我们所看到的,Set-FruitCountToZero
确实可以正常工作,将计数设置为零,并影响数据库中的一行。但是,Set-FruitCount
函数不起作用,尽管唯一的区别是为SET子句添加了一个参数。
我错过了什么?
(N.B.这个问题与参数化SQL查询有关,它与Powershell函数参数无关。)
正如@JacobH在评论中发布的那样,似乎OleDB对订单参数敏感。
因此,以下是确实有效的'Set-FruitCount`版本:
function Set-FruitCount {
Param($Fruit, $Count)
$strQuery = "UPDATE [fruits] SET [count] = @COUNT WHERE [fruit] = @FRUIT"
$oCmd = New-Object System.Data.OleDb.OleDbCommand($strQuery, $oConn)
[void]$oCmd.Parameters.Add("@COUNT", $Count)
[void]$oCmd.Parameters.Add("@FRUIT", $Fruit)
$ret = $oCmd.ExecuteNonQuery()
Write-Host "Set-FruitCount affected $ret rows"
}
请注意,@ COUNT和@FRUIT现在的显示顺序与SQL查询中的顺序相同。