【问题标题】:Dealing with System.DBNull in PowerShell在 PowerShell 中处理 System.DBNull
【发布时间】:2016-07-18 13:04:41
【问题描述】:

编辑:从 PowerShell 7 Preview 2 开始,-not [System.DBNull]::Value 的计算结果为 $true,感谢 Joel Sallow 通过pull request 9794

花更多时间在 PowerShell 中提取 SQL 数据。在比较过程中遇到 [System.DBNull]::Value 问题以及 PowerShell 如何处理此问题。

这是我看到的行为示例以及解决方法

#DBNull values don't evaluate like Null...
    if([System.DBNull]::Value){"I would not expect this to display"}
    # The text displays.
    if([string][System.DBNull]::Value){"This won't display, but is not intuitive"}
    # The text does not display.

#DBNull does not let you use certain comparison operators
    10 -gt [System.DBNull]::Value 
    # Could not compare "10" to "". Error: "Cannot convert value "" to type "System.Int32". Error: "Object cannot be cast from DBNull to other types.""

    [System.DBNull]::Value -gt 10
    # Cannot compare "" because it is not IComparable.

    #No real workaround.  Must use test for null workaround in conjunction to avoid comparison altogether:
    [string][System.DBNull]::Value -and [System.DBNull]::Value -gt 10

#Example scenario with a function that uses Invoke-Sqlcmd2 to pull data
    Get-XXXXServer | Where-Object{$_.VCNumCPUs -gt 8}
    #Error for every line where VCNumCPU has DBNull value

    #workaround
    Get-XXXXServer | Where-Object{[string]$_.VCNumCPUs -and $_.VCNumCPUs -gt 8}

我是否遗漏了什么,或者没有“简单”的解决方法可以让经验不足的人按预期使用 PowerShell 比较?

我提交了 a suggestion on Connect 并有一个临时的 workaround from Dave Wyatt 将数据行转换为 psobjects 并将 dbnulls 转换为空值,但是这个 adds a bit of overhead。考虑到 PowerShell 现有的“松散”行为,似乎应该在幕后处理一些事情?

任何提示,或者我现在已经用尽我的选择了吗?

【问题讨论】:

  • 我在进行一些编码以使用 sql db 时遇到了这个“特殊情况”。我的解决方案只是检查它 if ($val -ne [DBNull]::Value){} 但这并不能解决比较问题。我赞成您的连接条目。

标签: sql powershell dbnull


【解决方案1】:

我认为您在这里采取了错误的方法。正如documentedDBNull 类代表一个不存在的值,所以像-gt-lt 这样的比较没有任何意义。不存在的值既不大于也不小于任何给定值。不过,Value 字段有一个Equals() 方法,它允许您检查一个值是否为DBNull

PS C:> ([DBNull]::Value).Equals(23)
False
PS C:> ([DBNull]::Value).Equals([DBNull]::Value)
True

【讨论】:

  • Ansgar - 从纯粹主义者的角度来看,我完全同意!问题是 PowerShell 不是纯粹主义者的语言。它需要在幕后采取许多行动来提供系统管理员所期望的行为。当“”、0、$null 和来自其他类型的数据按预期进行比较时,Joe-Schmoe 管理员是否应该深入研究 MSDN 文档,但来自 SQL 的数据没有?直到现在我一直在处理这个问题,因为我是观众。下周我将演示一个从 SQL 中提取的迷你 DSL——观众不会认为“MSDN 完美地解释了它!”他们会想“为什么这么复杂!”
  • @CookieMonster Null 不为零,尤其是在涉及数据库时。习惯这个事实。
  • 同意! DBNull 也不是 Null。只是在 PowerShell 松散的“让我帮助你”行为中寻找一致性。例如:trcm { if(0){"Y"} } -N TypeConversion -PSH;trcm { if($null){"Y"} } -N TypeConversion -PSH;trcm { if(""){"Y"} } -N TypeConversion -PSH;trcm { if([System.DBNull]::Value){"Y"} } -N TypeConversion -PSH;trcm { if("" -gt 5){"Y"} } -N TypeConversion -PSH;trcm { if($null -gt 5){"Y"} } -N TypeConversion -PSH;trcm { if([System.DBNull]::Value -gt 5){"Y"} } -N TypeConversion -PSH;无论如何!您的帖子很有帮助,请投票 - 干杯!
  • 我同意@AnsgarWiechers,你需要编写有效的代码,所以如果你需要编写 if ([DBNull]::Value).Equals($var)) { " Y" } 那么它不是纯粹主义或非纯粹主义的方法是一种工作或不工作的方法......
【解决方案2】:

最简单的方法是$var -isnot [DBNull]

我已经在自己的脚本中对此进行了测试,它可以按预期工作。

【讨论】:

  • 这是一种直接的比较方法,要求输入类类型而不是值。 $var -is [DBNull]$var -isnot [DBNull] 取决于你想要什么。
  • 谢谢。这有效: $element 包含来自数据库的结果集。 $est_end_date=$element['Est_End_Date'] if ($est_end_date -isnot [DBNull]) { $est_end_date=$element['Est_End_Date']+' 00:00:00Z'}
  • 我尝试比较 $est_end_date -eq $null 并失败抛出错误 DBNull is missing。所以感谢您解决我的问题 [DBNull] 工作
【解决方案3】:

我通常最终会这样做:

[String]::IsNullOrWhiteSpace($Val.ToString())

或者这个:

[String]::IsNullOrEmpty($Val.ToString())

或者这个:

$Val.ToString() -eq [String]::Empty

这通常工作得很好,因为[System.DBNull]::Value.ToString() 返回一个空字符串,所以[String]::IsNullOrWhiteSpace([System.DBNull]::Value)[System.DBNull]::Value.ToString() -eq [String]::Empty 都评估为True。

显然,这些在逻辑上是等效的,因为您的数据可能合法地包含空字符串,或者可能是一种作为空字符串没有意义的数据类型(例如整数)。但是,由于您经常希望将 DBNulls 视为与空字符串和纯空格字符串完全相同的方式,因此如果您对数据足够了解,它会很有用。

如果您确实想知道该值是否为 DBNull,当然,请使用[DBNull]::Value.Equals($Value)

【讨论】:

    【解决方案4】:
    if( %youfunctetc%.GetType().Name -eq 'DBNull')
    {}
    else {}
    

    【讨论】:

      【解决方案5】:

      在 PS 中处理 SQL 数据时,我包含此函数并在需要时调用:

      function Check-IsNullWithSQLDBNullSupport ($var) {
          if ($var -eq [System.DBNull]::Value -or $var -eq $null) {
              return $true
          } else {
              return $false
          }
      }
      

      可以这样使用:

      if (Check-IsNullWithSQLDBNullSupport -var $VarToBeTested) {
          write-output "Is Null"
      }
      

      【讨论】:

        【解决方案6】:

        一些命令 |其中 FieldOfInterest -是 DBNull 似乎对我有用。 DBNull 是一个“类型”,-is 运算符正在检查左边的值是否属于给定的“类型”。

        您也可以使用相反的网站 一些命令 |其中 FieldOfInterest -isnot DBNull

        【讨论】:

          【解决方案7】:

          似乎我只对旧帖子发表评论,但我认为与 Dave Wyatt 讨论的链接在上面被破坏了,通过重新谷歌搜索我找到了它here

          我目前正在处理的代码对性能不敏感,但我确实需要比较返回数据以重置另一个不同类型目标对象的属性。

          通常很方便的 PowerShell,例如:

          If( $SrcObject.Property ) { $TargObject.Property = $SrcObject.Property }
          

          这不适用于 [DBNull]

          通常我会花时间查看/开发,然后使用最快的代码,无论需要或复杂性如何,但我必须尽快获得 rev1。在我意识到 [DBNull] 问题之前,我使用简单的| Select $Props 将对象翻转到 [PSCustomObject]

          $Props 是一个输入的列名数组。但这不会改变子属性的类型,所以比较仍然失败!

          鉴于我已经走上了戴夫建议的道路,所以我走得更远了。

          $Props = ( $SQLData.Tables[0].Rows[0] | Get-Member -MemberType Properties ).Name
          $Rows  = $SQLData.Tables[0].Rows | Select $Props
          
          ForEach( $RowObject in $Rows )
          {
              ForEach($Prop in $Props )
              {
                  # Maybe: [String]::Empty below?
                  If( $RowObject.$Prop -is [DBNull] ) { $RowObject.$Prop = "" }
              } #End Inner Loop.
          } #End Outer Loop.
          

          注意:这有点假,因为 prod 代码将行隐藏在字典中,但它应该足以传达方法。此外,以上内容并未经过全面测试,因为它是从工作代码翻译而来的。

          我不知道为什么 Get-Member 不返回 RowError、RowState 等其他属性……但只要您不介意将 [DBNull] 转换为空字符串,这确实有效。而且,Get-Member 更可重用,无需输入道具...

          显然,这与前面提到的一些强制转换并没有太大不同,但我可能不是唯一一个想在辅助函数中保留一些复杂性的人,所以“main”看起来更简洁一些。此外,一个空字符串应该满足以后的大多数比较,特别是考虑到后台进行的类型转换。

          我知道这是评论而不是问题,但如果我有任何问题,请告诉我。我在做一个活跃的项目时确实偶然发现了这一点。谢谢!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-06-16
            • 1970-01-01
            • 2020-05-30
            • 2019-10-17
            • 2023-03-18
            • 1970-01-01
            相关资源
            最近更新 更多