Выбор нулевого значения из XML в SQL Server - PullRequest
11 голосов
/ 09 июля 2010

Я пытаюсь выбрать из XML, который имеет нулевое значение в качестве одного из атрибутов.Вместо того, чтобы возвращать ноль, он возвращает 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 ]

11 голосов
/ 29 января 2011

Я думаю, что если вы используете функцию number (), вы получите нулевое значение, как и ожидалось. Это работает только для числовых типов:

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) 
10 голосов
/ 24 мая 2012

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

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

Это выберет ноль. Кстати авторский код имеет опечатку

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)
5 голосов
/ 09 июля 2010

Поскольку вы устанавливаете для полей значение 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
2 голосов
/ 09 июля 2010

Я просто использовал NULLIF, чтобы при необходимости превращать пустые строки в NULL.

Вы можете сгенерировать nil сейчас, используя FOR XML, но я никогда не пытался разобрать его, извините ...

1 голос
/ 07 ноября 2014

Умный способ сделать это состоит в том, чтобы удалить узел Property1 из XML, где желательны нулевые значения.Итак, какой бы узел вы ни выбрали в своем наборе результатов, просто не добавляйте его в 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 нет, следовательно, он будет иметь нулевое значение

1 голос
/ 20 мая 2013

Я бы предложил этот подход:

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)
0 голосов
/ 29 марта 2019

В моем случае я использую тип данных логический, поэтому весь ответ здесь не относится ко мне. Если вы используете логический тип данных, вы можете попробовать это:

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

Я добавил этот код:

cast as xs:boolean?','BIT'

Что произойдет, если логическое значение равно нулю, если оно есть, оно вернет ноль или же вернет 1 или 0.

0 голосов
/ 08 мая 2013

Я не уверен, требует ли ваш конкретный случай сначала выполнить подзапрос узлов, но если нет, вы можете запросить .value и предоставить xPath. Поскольку узел Property1 существует, вы хотите оценить текст () узла Property1, а не сам узел:

 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)

Кроме того, чтобы убедиться, что это работает в других случаях, вы можете предоставить наиболее подробный путь к элементу в @P.nodes xPath и перейти к «../» вместо того, чтобы запрашивать результаты узла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...