【问题标题】:Inserting a date into SQL在 SQL 中插入日期
【发布时间】:2018-05-29 10:30:03
【问题描述】:

我指定了以下日期时间:

$dateChanged = Get-Date -Format ("yyyy-MM-dd hh:mm:ss.fff")

我想使用以下 PowerShell 将其插入 SQL 日期时间字段:

INSERT INTO myTable (name, dateChanged) VALUES ($name, $dateChanged);

我收到以下错误:

使用“0”参数调用“ExecuteNonQuery”的异常:“'11' 附近的语法不正确。”

注意:这里的当前时间是 11:28。

我已尝试重新格式化 dateChanged 变量,但无济于事。

【问题讨论】:

  • 您能否也分享您的 PowerShell 代码。
  • 如您所见,这行不通。 T-SQL 只是一种与 PowerShell 不同的语言。请提供一个重现问题的最小工作示例(至少提供更多代码/上下文)。
  • 您想为该语句使用(键入的)参数,而不是简单的字符串替换。这将避免将值完全正确格式化为字符串的问题(包括NULL 值之类的东西)。不幸的是,微软的优秀人员并没有试图让这一切变得简单,但SqlCommand.Parameters 仍然可用,因为它在任何其他 .NET 语言中都是可用的。如果没有参数,您会遇到两个错误:hh 应该是 HH(24 小时,而不是 12 小时)并且您的字符串值和日期/时间常量需要用单引号括起来 ('$dateChanged')。
  • @JeroenMostert 谢谢你,我已经按照你的建议进行了修改,它有效。如果您作为答案发布,我会将其标记为正确。
  • 我会做得更好,并发布我希望人们在从 PowerShell 执行 SQL 时使用的代码。即使这对你的情况来说可能有点矫枉过正。

标签: powershell


【解决方案1】:

您完全可以通过简单的字符串替换在 PowerShell 中执行 SQL,例如您可以传递给 Invoke-Sqlcmd 的“参数”。我建议你不要:它让你容易注入,你必须特别注意格式化日期、NULL 值、浮点值、字符串......这里有两个函数可以帮助你以 .NET 方式进行操作:

function ConvertFrom-DataReader($datareader) {
    $values = New-Object Object[] $datareader.FieldCount
    $names = New-Object string[] $datareader.FieldCount
    $anyNameEmpty = $false
    for ($i = 0; $i -lt $values.Length; $i++) {
        $names[$i] = $datareader.GetName($i)
        if (-not $names[$i]) { $anyNameEmpty = $true }
    }
    while ($datareader.Read()) {
        $v = $datareader.GetValues($values)
        if ($anyNameEmpty) {
            Write-Output $values
        } else {
            $result = New-Object psobject
            for ($i = 0; $i -lt $v; $i++) {
                Add-Member `
                    -InputObject $result `
                    -MemberType NoteProperty `
                    -Name $names[$i] `
                    -Value $values[$i]
            }
            Write-Output $result
        }
    }
}

function Invoke-SqlCommand(
    [string] $ConnectionString, 
    [string] $CommandText, 
    [hashtable] $Parameters = @{}
) {
    $connection = New-Object System.Data.SqlClient.SqlConnection($ConnectionString)
    try {
        $connection.Open()
        $command = New-Object System.Data.SqlClient.SqlCommand
        $command.Connection = $connection
        $command.CommandText = $commandText
        $command.CommandType = [System.Data.CommandType]::Text
        foreach ($Name in $Parameters.Keys) {
            $command.Parameters.AddWithValue($Name, $Parameters[$Name]) | Out-Null
        }
        ConvertFrom-DataReader $command.ExecuteReader()
    } finally {
        $connection.Close()
    }
}

使用示例:

Invoke-SqlCommand `
    -ConnectionString "Data Source=(localdb)\mssqllocaldb" `
    -CommandText "DECLARE @myTable TABLE(name VARCHAR(100), dateChanged DATETIME); 
        INSERT INTO @myTable (name, dateChanged) VALUES (@name, @dateChanged);
        SELECT * FROM @myTable" `
    -Parameters @{
        name = "Winston"
        dateChanged = Get-Date
    }

这并不完美(您可以使用正确的 cmdlet,AddWithValue has issues),您可能会认为它对于一次性查询来说太过分了,但它仍然比文本替换要好得多。

【讨论】:

    猜你喜欢
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多