在SQL Server中从XML中选择空值

时间:2010-07-08 21:37:09

标签: sql-server xml null xml-nil

我正在尝试从具有null作为其中一个属性的XML中进行选择。它不返回null,而是返回0.我做错了什么? 请参阅下面的代码以复制:

declare @a xml
select @a = '<TestSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instace">
  <Element>
    <Property1>1</Property1>
    <Property2>1</Property2>
  </Element>
  <Element>
    <Property1 xsi:nil="true" />
    <Property2>2</Property2>
  </Element>
  <Element>
    <Property1>3</Property1>
    <Property2>3</Property2>
  </Element>
</TestSet>'

 select ParamValues.TaskChainerTask.query('Property1').value('.','int') as Property1,
        ParamValues.TaskChainerTask.query('Property2').value('.','int') as Property2
   from @a.nodes('(/TestSet/Element)') as ParamValues(TaskChainerTask)

返回:

Property1   Property2
1           1
0           2
3           3

这会返回相同的内容:

declare @a xml
select @a = '<TestSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instace">
  <Element>
    <Property1>1</Property1>
    <Property2>1</Property2>
  </Element>
  <Element>
    <Property1 xsi:nil="true" />
    <Property2>2</Property2>
  </Element>
  <Element>
    <Property1>3</Property1>
    <Property2>3</Property2>
  </Element>
</TestSet>'

 select ParamValues.TaskChainerTask.query('Property1').value('.','int') as Property1,
        ParamValues.TaskChainerTask.query('Property2').value('.','int') as Property2
   from @a.nodes('(/TestSet/Element)') as ParamValues(TaskChainerTask)

提前致谢。

8 个答案:

答案 0 :(得分:11)

我认为如果你使用number()函数,你将按预期得到null。这仅适用于数字类型:

select 
   ParamValues.TaskChainerTask.query('Property1').value('number(.)','int') as Property1,         
   ParamValues.TaskChainerTask.query('Property2').value('number(.)','int') as Property2
from @a.nodes('(/TestSet/Element)') as ParamValues(TaskChainerTask) 

答案 1 :(得分:10)

http://go4answers.webhost4life.com/Example/including-null-columns-empty-elements-125474.aspx

[not(@xsi:nil = "true")]

这将选择null。顺便提一下,作者代码有一个拼写错误

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instace"

实例拼写为instace

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

作者代码的工作版本

declare @a xml
            select @a = '<TestSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
              <Element>
                <Property1>1</Property1>
                <Property2>1</Property2>
              </Element>
              <Element>
                <Property1 xsi:nil="true" />
                <Property2>2</Property2>
              </Element>
              <Element>
                <Property1>3</Property1>
                <Property2>3</Property2>
              </Element>
            </TestSet>'

             select ParamValues.TaskChainerTask.value('./Property1[1][not(@xsi:nil = "true")]','int') as Property1,
                    ParamValues.TaskChainerTask.value('./Property2[1][not(@xsi:nil = "true")]','int') as Property2
               from @a.nodes('(/TestSet/Element)') as ParamValues(TaskChainerTask)

答案 2 :(得分:5)

因为您将字段设置为INT,所以您遇到的问题是xsi:nil =“true”字段和值0将最终为0,因为INT的默认值为0。

您可以首先转换为VARCHAR以检测包含xsi:nil =“true”的字符串字段生成的空字符串(''),然后将结果转换为INT。

此SELECT将为您提供您的答案

SELECT  CONVERT(INT,NULLIF(ParamValues.TaskChainerTask.query('Property1').value('.', 'varchar(5)'),'')) AS Property1
      , CONVERT(INT,NULLIF(ParamValues.TaskChainerTask.query('Property2').value('.', 'varchar(5)'),'')) AS Property2
FROM    @a.nodes('(/TestSet/Element)') AS ParamValues (TaskChainerTask) 

结果给你:

Property1   Property2
1           1
NULL        2
3           3

答案 3 :(得分:2)

我只是根据需要使用NULLIF将空字符串转换为NULL。

您现在可以使用nil生成FOR XML,但我从来没有弄清楚如何解析它抱歉......

答案 4 :(得分:1)

我会采用这种方法:

DECLARE @a XML = '<TestSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instace">
  <Element>
    <Property1>1</Property1>
    <Property2>1</Property2>
  </Element>
  <Element>
    <Property1 xsi:nil="true" />
    <Property2>2</Property2>
  </Element>
  <Element>
    <Property1>3</Property1>
    <Property2>3</Property2>
  </Element>
</TestSet>'

SELECT
    ParamValues.TaskChainerTask
        .value('./Property1[not(./@*[local-name()="nil"] = "true")][1]', 'int') as Property1,
    ParamValues.TaskChainerTask
        .value('./Property2[not(./@*[local-name()="nil"] = "true")][1]', 'int') as Property2
FROM @a.nodes('//Element') ParamValues(TaskChainerTask)

答案 5 :(得分:1)

这样做的一种聪明方法是从需要空值的XML中删除Property1节点。那么你想要在结果集中为null的节点只是不将它添加到XML中。这样您就不必添加xsi:nill属性了。

所以下面也会产生一个null:

declare @a xml
select @a = '<TestSet>
  <Element>
    <Property1>1</Property1>
    <Property2>1</Property2>
  </Element>
  <Element>
     //I have removed the property1 node and this will result in a null value
    <Property2>2</Property2>
  </Element>
  <Element>
    <Property1>3</Property1>
    <Property2>3</Property2>
  </Element>
</TestSet>'

 select ParamValues.TaskChainerTask.value('./Property1[1]','int') as Property1,
        ParamValues.TaskChainerTask.value('./Property2[1]','int') as Property2
   from @a.nodes('(/TestSet/Element)') as ParamValues(TaskChainerTask)

在上面的例子中可以看出,没有Property1节点,因此它将导致空值

答案 6 :(得分:0)

我不确定您的特定情况是否要求您首先对节点进行子查询,但如果不是,您可以请求.value并提供xPath。由于Property1节点存在,您想要评估Property1节点的text()而不是节点本身:

 select  ParamValues.TaskChainerTask.value('Property1[1]/text()[1]','int') as Property1,
        ParamValues.TaskChainerTask.value('Property2[1]/text()[1]','int') as Property2

   from @a.nodes('(/TestSet/Element)') as ParamValues(TaskChainerTask)

除了确保在其他情况下这样做之外,您还可以在@ a.nodes xPath语句中提供最详细的元素路径,并使用“../”向上走,而不是查询节点结果。

答案 7 :(得分:0)

就我而言,我使用的是布尔类型数据,因此此处的所有答案均不适用于我。如果您使用的是布尔数据类型,则可以尝试以下一种方法:

myXML.value('Property1[1] cast as xs:boolean?','BIT') AS Property1,

我添加了以下代码:

cast as xs:boolean?','BIT'

如果布尔值为null,则强制转换,如果为null,则将返回null,否则将返回1或0。