Sql 在PowerShell中处理System.DBNull

Sql 在PowerShell中处理System.DBNull,sql,powershell,dbnull,Sql,Powershell,Dbnull,编辑:从PowerShell 7预览版2开始,-not[System.DBNull]::Value计算为$true,这要感谢via 花费更多时间在PowerShell中提取SQL数据。[System.DBNull]::值以及PowerShell在比较期间如何处理该值时遇到问题 下面是我看到的一个行为示例,以及解决方法 #DBNull values don't evaluate like Null... if([System.DBNull]::Value){"I would no

编辑:从PowerShell 7预览版2开始,
-not[System.DBNull]::Value
计算为
$true
,这要感谢via

花费更多时间在PowerShell中提取SQL数据。[System.DBNull]::值以及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比较

我提交了一个临时文件,将datarows转换为PSObject,将dbnulls转换为nulls,但这是一个临时文件。考虑到PowerShell现有的“松散”行为,似乎应该在幕后进行处理


有什么建议吗,或者我已经用尽了我的选择吗?

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

PS C:> ([DBNull]::Value).Equals(23)
False
PS C:> ([DBNull]::Value).Equals([DBNull]::Value)
True
psc:>([DBNull]::值)。等于(23)
假的
PS C:>([DBNull]::值)。等于([DBNull]::值)

真的
我通常会这样做:

[String]::IsNullOrWhiteSpace($Val.ToString())
或者这个:

[String]::IsNullOrEmpty($Val.ToString())
$Val.ToString() -eq [String]::Empty
或者这个:

[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,那么在PS中处理SQL数据时,请使用
[DBNull]::value.Equals($value)

在需要时包括此函数并调用:

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"
}

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


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

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

你也可以使用另一个网站
有些命令| where FieldOfInterest-不为DBNull

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

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

因此,通常方便的PowerShell类似:

If( $SrcObject.Property ) { $TargObject.Property = $SrcObject.Property }
这不适用于[DBNull]

通常,我会花时间查看/dev,然后使用最快的代码,而不考虑需要或复杂性,但我必须尽快发布rev1。在我意识到[DBNull]问题之前,我使用一个简单的
| Select$Props

$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成员不返回其他属性,如RowError、RowState等。。。但只要您不介意将[DBNull]中的值转换为空字符串,这就行了。而且,Get成员的可重用性更强,无需键入道具

显然,这与前面提到的一些casting没有太大的不同,但我可能不是唯一一个想在helper函数中加入一些复杂性的人,所以“main”看起来更干净一些。此外,空字符串应该满足以后的大多数比较,特别是考虑到后台的类型转换内容


我知道这是一个评论,不是一个问题,但如果我有任何错误,请让我知道。我在一个活跃的项目中偶然发现了这一点。谢谢

在使用sql db进行编码时,我遇到了这个“特例”。我的解决方案只是检查它是否($val-ne[DBNull]::Value){},但这并不能解决比较问题。我对你的连接条目投了更高的票。Ansgar-我完全同意你的观点!问题是PowerShell不是纯粹主义者的语言。它需要在幕后执行许多操作,以提供系统管理员所期望的行为。当“、0、$null和来自其他类型的数据按预期进行比较,但来自SQL的数据不进行比较时,Joe Schmoe admin是否应该深入研究MSDN文档?我一直在处理这个问题,直到现在,因为我是观众。下周我将演示一个来自SQL的迷你DSL——观众不会想到“MSDN完美地解释了它!”他们会想,‘为什么这么复杂!’@CookieMonster Null不是零,尤其是在数据库中。习惯这个事实,同意!DBNull也不是Null。只是想在PowerShell松散的“让我来帮你”行为中寻找一致性。示例:
trcm{if(0){“Y}}-N类型转换-PSH
trcm{if($null){“Y”}}-N类型转换-PSH
trcm{if(“”{“Y”}}-N类型转换-PSH
trcm{if([System.DBNull]::Value){“Y”}-N TypeConversion-PSH
trcm{if(“-gt 5){“Y”}-N类型转换-PSH<