Como retornar um nulo de uma marca XML vazia no SQL server usando apenas o Xpath?

8

Eu tenho um aplicativo que armazena vários pontos de dados definidos pelo usuário sobre um registro em uma coluna XML. Não tenho controle sobre como eles são armazenados ou atualizados.

Quando consulta uma coluna, ela pode retornar 1 de 3 valores:

  1. O valor que
  2. Nulo
  3. Uma string vazia

Questão $ 64 Gostaria de retornar as cadeias vazias como nulos usando xpath.

Eu encontrei muitas respostas sobre retornar o nulo como uma picada vazia, mas nada dessa maneira.

Eles acabam assim quando alguém exclui o valor e, em vez de excluir a tag, ela a deixa em branco <value />. Os nulos ocorrem quando o valor nunca foi definido. Eles não incluíram xsi: nil.

Eu fiz isso com uma declaração de caso:

    select
    so.SalesOrderId,
    Case
        when sopc.value('(Value)[1]','smalldatetime') IS null then Null
        when sopc.value('(Value)[1]','smalldatetime') ='' then Null
        Else sopc.value('(Value)[1]','smalldatetime')
    End as sopc
    From
    SalesOrders so
    Outer apply so.CustomColumns.nodes('/CustomColumnsCollection/CustomColumn[Name="ProjCompleted"]') sopc(sopc)

mas isso parece ineficiente e não é a única coluna, tornando o código longo e difícil de manter.

Editar para incluir dados de amostra

SalesOrderId    CustomColumns
SO 1            "<CustomColumnsCollection>
                   <CustomColumn>
                     <Name>ProjCompleted</Name>
                     <DataType>1</DataType>
                     <Value />
                   </CustomColumn>
                 </CustomColumnsCollection>"
SO 2           "<CustomColumnsCollection>
                  <CustomColumn>
                     <Name>ProjCompleted</Name>
                     <DataType>1</DataType>
                     <Value>'2017-11-21'</Value>
                  </CustomColumn>
                </CustomColumnsCollection>"
SO 3           "<CustomColumnsCollection>
                </CustomColumnsCollection>"

**Output**
Current      Desired
''           null
2017-11-21   2017-11-21
null         null

Desde já, obrigado.

TimNewman
fonte
Obrigado Scott - como você pode ver, é a minha primeira pergunta, existe um formato preferido?
TimNewman
Atualize sua pergunta com um bloco de código (semelhante ao código que você já postou) que possui a amostra XML e inclua outro bloco de código dos resultados esperados. Veja como criar um exemplo mínimo, completo e verificável
Scott Hodgin
Obrigado - Aceitei uma resposta, mas continuarei editando a pergunta para torná-la útil para qualquer pessoa que a encontrar.
precisa saber é o seguinte

Respostas:

11

Especifique o text()nó dentro do Valueelemento. Esse nó está ausente quando você tem uma tag vazia.

Tente o seguinte:

declare @X xml;
set @X = '<Value/>';

select @X.value('(Value/text())[1]', 'smalldatetime'),
       @X.value('(Value/text())[1]', 'varchar(max)'),
       @X.value('(Value/text())[1]', 'int'),
       @X.value('(Value)[1]', 'smalldatetime'),
       @X.value('(Value)[1]', 'varchar(max)'),
       @X.value('(Value)[1]', 'int');

Resultado:

------------------- ---------- ----------- ----------------------- ---------- -----------
NULL                NULL       NULL        1900-01-01 00:00:00                0

Geralmente, é bom especificar sempre o text()nó. O plano de consulta é mais simples e mais eficiente.

insira a descrição da imagem aqui

Mikael Eriksson
fonte