在PowerShell中处理System.DBNull

Coo*_*ter 10 sql powershell dbnull

花费更多时间在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}
Run Code Online (Sandbox Code Playgroud)

我是否遗漏了任何内容,或者没有"简单"的解决方法可以让那些经验不足的人按预期使用PowerShell比较?

我提交了一个关于Connect的建议,并有一个Dave Wyatt的临时解决方法,它将数据行转换为psobjects,并将dbnulls转换为null,但这会增加一些开销.考虑到PowerShell现有的"松散"行为,似乎应该在封面下处理一些事情?

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

谢谢!

Ans*_*ers 18

我想你在这里采取了错误的做法.如文档所述,DBNull该类表示不存在的值,因此比较喜欢-gt-lt没有任何意义.不存在的值既不大于也不小于任何给定值.但是,该Value字段有一个Equals()方法,允许您检查值是否为DBNull:

PS C:> ([DBNull]::Value).Equals(23)
False
PS C:> ([DBNull]::Value).Equals([DBNull]::Value)
True
Run Code Online (Sandbox Code Playgroud)

  • 安斯加 - 我从纯粹的立场完全赞同!问题是PowerShell不是纯粹主义者的语言.需要采取许多措施来提供系统管理员期望的行为.当",",0,$ null和其他类型的数据按预期进行比较时,Joe-Schmoe管理员是否应该深入研究MSDN文档,但是来自SQL的数据不是?我一直在处理这个问题,因为我是观众.下周我将演示一个从SQL中获取的迷你DSL - 观众不会想到'MSDN完美地解释它!' 他们会想'为什么这么复杂!' (3认同)
  • @CookieMonster Null不为零,特别是涉及数据库时.习惯这个事实. (3认同)

小智 9

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

我已经在自己的脚本中对此进行了测试,并且可以正常工作。


Bac*_*its 6

我通常最终做的是这样的:

[String]::IsNullOrWhiteSpace($Val.ToString())
Run Code Online (Sandbox Code Playgroud)

或这个:

[String]::IsNullOrEmpty($Val.ToString())
Run Code Online (Sandbox Code Playgroud)

或这个:

$Val.ToString() -eq [String]::Empty
Run Code Online (Sandbox Code Playgroud)

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

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

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