【问题标题】:Powershell - SQL query result to variable with propertiesPowershell - SQL查询结果到具有属性的变量
【发布时间】:2018-08-23 09:32:56
【问题描述】:

为什么 SQLCMD 的存储输出只有Length 属性而不是column names?。不能用其属性存储sqlcmd 输出吗?

Invoke-sqlcmd 正确存储它,但Invoke-SQLcmd 需要更长的时间来处理,所以我试图让它与 SQLcmd 一起工作,因为这个方法将是计划每分钟运行一次的不同脚本的一部分,每小时一次等等,

知道这是否可行或问题是什么?

存储输出并回显 $var:

     PS C:> $var=(SQLCMD -S 'x.x.x.x' -U 'user' -P 'password' -i "C:\query.sql" -W -m 1) 

     PS C:> $var
     job_id name
     ------ ----
     12345-aaaa-1234-5678-000000000000000 Clear DB entries
     12345-bbbb-1234-5678-000000000000000 TempLog DB

Echo $var[0,1,2] 不显示属性名称。

     PS C:> $var[0]
     job_id name
     PS C:> $var[1]
     ------ ----
     PS C:> $var[2]
     12345-aaaa-1234-5678-000000000000000 Clear DB entries

显示 $var 属性

     PS C:> $var | select *
     Length
     ------
     11
     53

显示 $var 类型

     PS C:> $var.GetType()

     IsPublic IsSerial Name                                     BaseType
     -------- -------- ----                                     --------
     True     True     Object[]                                 System.Array

【问题讨论】:

  • 我从未使用过 SQLCMD,但根据您显示的内容,它会返回一个字符串数组。不是行对象。 $var[0] 应该告诉您属性名称,然后您可以根据需要解析其余行以创建自己的自定义对象。
  • 您应该将您的 SQL 查询代码 (C:\query.sql) 添加到此帖子中,以便我们可以看到您要完成的工作。
  • 代码无关紧要,但它是select job_id, name from table;
  • @EBGreen 你能告诉我如何解析它的其余部分来创建自定义对象吗?我正在研究。如果我们可以流式传输到sqlcmd 输出,单行将很酷。
  • 不,使用 cmdlet 来获取实际的行对象会很酷。如何解析它在很大程度上取决于数据的样子。如果 SQLCMD 让您指定分隔符,那么我想我会首先尝试使用逗号作为分隔符,然后将其视为 CSV 并使用 Import-CSV 来获取对象数组。如果您的数据中断,那么您将不得不自己解析每一行。无论如何,您需要尝试自己编写代码,然后针对您编写的代码遇到的具体问题提出具体问题。

标签: powershell sqlcmd invoke-sqlcmd


【解决方案1】:
$var=(SQLCMD -S 'x.x.x.x' -U 'user' -P 'password' -i "C:\query.sql" -W -m 1) 

您正在调用sqlcmd.exe,它不知道 .Net 对象是什么,更不用说如何将它们传递给 PowerShell。就 PowerShell 而言,该命令输出字符串。您需要自己将字符串转换为对象。

如果你必须使用sqlcmd.exe,我会建议这样:

$Delimiter = "`t"
$var = SQLCMD -S 'x.x.x.x' -U 'user' -P 'password' -i "C:\query.sql" -W -m 1 -s $Delimiter |
    ConvertFrom-Csv -Delimiter $Delimiter |
    Select-Object -Skip 1

我使用制表符作为字段分隔符。如果您的数据包含制表符,您将需要不同的分隔符。如果您的数据包含双引号,您也可能会遇到问题。 Select-Object -Skip 1 是跳过sqlcmd 始终在标题下方创建的下划线行。

另外请注意,您应该在sqlcmd 上使用-w 参数,以防止任何不正确的包装。另请注意,空值始终作为文字字符串 NULL 输出。

也就是说,我可能仍然会坚持使用Invoke-Sqlcmd。它更不容易出错并且更可预测。如果我真的需要性能,我可能会使用直接的 .Net 方法或 SSIS。

【讨论】:

  • 谢谢,它按预期工作。以为sqlcmd -s switch 不接受 $Delimiter 变量,所以我为两者手动定义了它。
  • @User 好吧,sqlcmd 本身不接受它。命令行解析器在将变量作为参数传递给可执行文件之前对其进行扩展。这相当于同一件事,但这里有一个中间人。
【解决方案2】:

我为此目的编写了一个函数...尚未完全充实...希望对您有所帮助

    function Invoke-MSSqlCommand
    {
      [CmdletBinding()]
      param
      (
        [Parameter(Position=0, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Query,

        [Parameter(Position=1, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ConnectionString,

        [Switch]
        $NoOutput
      )
      try {
        $connection = New-Object -TypeName System.Data.SqlClient.SqlConnection
        $connection.ConnectionString = $ConnectionString
        $null = $connection.Open()
      }
      catch {
        Throw "$connectionstring could not be contacted"
      }
      $command = New-Object -TypeName System.Data.SqlClient.SqlCommand
      $command.CommandText = $query
      $command.Connection = $connection


      if ($NoOutput) {
        $null = $command.ExecuteNonQuery()
      }
      else {

        if ($dataset.Tables[0].Rows[0] -eq $null) {
          write-verbose -Message 'no record'
          $connection.Close()
          return $null
        }

        $dataset.Tables[0].Rows
        $connection.close()
      }
    }

【讨论】:

  • 感谢脚本。我会好好利用的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多