【问题标题】:sqlcmd. How to pass in a variable that includes a colon and a space?sqlcmd。如何传入包含冒号和空格的变量?
【发布时间】:2025-12-06 01:45:01
【问题描述】:

我已经为此苦苦挣扎了一段时间。我正在尝试调用一个 sql 脚本并使用 sqlcmd 将两个变量传递给它。我在 PowerShell 中完成所有这些工作。

这是我得到的:

$time = '12:00 AM'
$date = '06/20/2014'
$result = sqlcmd -U username -P password -i "c:\path\to\script.sql" -v date=$date -v time=$time

此操作失败并显示以下错误消息:

sqlcmd : Sqlcmd: 'time=12:00 AM': Invalid argument. Enter -? for help.

经过一些实验,我发现问题在于 $time 中的冒号和空格。如果我删除冒号和空格$time = '1200AM',命令执行没有任何错误。

不幸的是,我正在执行的脚本需要精确的格式“12:00 AM”。

我尝试过但不起作用的方法:

$time="12\:00\ AM"
$time="12\\:00\\ AM"
$time="12"+":00"+" AM"
$time="12"+":00"
$time="12"+":"+"00"

这些都以类似的Invalid argument 失败响应。最后几次尝试是来自this similar post 的解决方案。它们不起作用。

我也尝试将字符串值直接放在 sqlcmd 调用中,如下所示:

$result = sqlcmd -U username -P password -i "c:\path\to\script.sql" -v date=$date -v time="12\:00\ AM". 

没有骰子,无论如何,我需要从其他地方读取时间,所以我需要 $time 变量。

【问题讨论】:

  • 不确定这是否是您正在寻找的答案:*.com/questions/17041145/…。认为您需要将百分比翻倍。其他字符有不同的escapes
  • @Matt 嘿,我很感激你的努力,但这似乎并不相关。冒号和空格不需要转义,至少对于普通的批处理文件是这样。 Here 是需要转义的字符列表。
  • 好的...我们链接了同一篇文章。是的,似乎没有提到冒号。我的错。 -v "date=""$date""" 怎么样?这应该允许在传递给 sqlcmd 时有时间加上引号?

标签: powershell sqlcmd


【解决方案1】:

我(终于)从 Powershell 脚本中找到了适用于 sqlcmd 的解决方案。 (使用 invoke-sqlcmd 对我来说不是一个选项)

我需要在变量中传递包含冒号的绝对路径(例如,C:\rootdir\subdir)。这在常规命令提示符下工作,但我无法从 Powershell 脚本中工作。我想出了一个丑陋的组合,将冒号前后的部分传递给两个变量,然后在 SQL 脚本中重新组装。

但是当路径包含空格(例如,C:\root dir\subdir)时它失败了。

所以我终于找到了一个同时修复冒号和空格的解决方案。它涉及将路径文本括在双引号中,然后将双引号路径文本括在一组外部单引号中。在变量中构建完整的 sqlcmd 后,它看起来像这样:

SQLCMD <other args>  -v RootPath='"C:\root dir\subdir"'

(这是一组外单引号(')和一组内双引号("))。

如果路径没有冒号,这也有效,例如,\\nodename\root dir\subdir。当我试图围绕假定的冒号分割路径时,这一直是个问题。我仍然不确定为什么外部单引号和内部双引号都是必需的,但这是唯一适合我的版本。

附录:这仅适用于 Powershell 5,并且在我的脚本从 Powershell 4 运行时中断。为了使其在两者上都能正常工作,我发现我需要用单引号将内部空格括起来,例如,

SQLCMD <other args>  -v RootPath='"C:\root' 'dir\subdir"'

【讨论】:

    【解决方案2】:

    我通过在每个变量赋值运算符前后添加空格来稍微修改您的 PowerShell 脚本,如下所示:

    $time = '12:00 AM'
    $date = '06/20/2014'
    $result = sqlcmd -U username -P password -i "c:\path\to\script.sql" -v date = $date -v time = $time
    

    它对我有用(在 PowerShell 2.0 上测试)。

    【讨论】:

    • 似乎括号也可以:$result = sqlcmd -U username -P password -i "c:\path\to\script.sql" -v date=($date) -v time=($time)
    【解决方案3】:

    好的,我想出了一个解决方案。希望它对未来某个地方的其他人有用。

    我从 sqlcmd 切换到 Powershell 的 Invoke-Sqlcmd。这仍然给我带来了问题,所以我不得不稍微摆弄一下。这是我的最终结果。

    # import Invoke-Sqlcmd
    Add-PSSnapin SqlServerCmdletSnapin100
    Add-PSSnapin SqlServerProviderSnapin100
    
    $time = "12:01 AM"
    $date = "07/22/2014"
    $datetime = "time='$time'", "date='$date'" # save to $datetime as an array
    $result = Invoke-Sqlcmd -Username username -Password password -InputFile "c:\path\to\sql\script.sql" -Variable $datetime
    

    请注意,以下内容不起作用:

    $datetime = "time='"+$time+"'", "date='"+$date+"'"
    

    这是我尝试的第一件事,它导致了无效参数异常。

    【讨论】:

      【解决方案4】:

      首先,我会尝试-v "date=$date" -v "time=$time"

      如果这不起作用,我会试试这个:

      $time = '12:00 AM'
      $date = '06/20/2014'
      $time = 'time=' + $time
      $date = 'date=' + $date
      $result = sqlcmd -U username -P password -i "c:\path\to\script.sql" -v $date -v $time
      

      当 PowerShell 执行程序时,它会解析该行,解析其中的任何 PowerShell,然后尝试执行该字符串。最终感觉你需要一个额外的抽象层,而这在传统的 shell 脚本或批处理脚本中是看不到的。

      【讨论】:

      • 不幸的是,这些都不起作用。还是)感谢你的建议。这是我在这里真正的脑筋急转弯。我试过 Invoke-Sqlcmd,它给了我几乎同样的问题!
      • @Benjamin Hm。 $time = 'time="' + $time + '"' 之类的呢?通常我所做的是在行的开头放一个Write-Output 以查看命令行的实际外观,然后尝试从那里向后工作以使字符串正确显示。我的意思是,当您从cmd.exe 运行命令时,正确运行是什么样子的?如果您想使用Invoke-Sqlcmd,请仔细检查the syntax 是否传递变量。
      • 我试过了,但没有用。同样的错误。使用 Write-Output 很有用,因为它向我展示了我的命令已按照我想要的方式格式化。不过,Sqlcmd 仍然不接受它。最后,我想出了一种使用 Invoke-Sqlcmd 的方法。我在这个页面上给出了解决方案。