1

对于某些字符串和数字元素,我有一些包含 xsi:nil="true" 的 XML。这是一个例子:

declare @data xml

set @data = '<?xml version="1.0" encoding="utf-8"?>
             <collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
              <item>
               <stringprop1>foo</stringprop1>
               <stringprop2 xsi:nil="true" />
               <decimalprop3 xsi:nil="true" />
              </item>
             </collection>'

我想在 SQL Server 2008 R2 中查询该 XML。我正在使用 OPENXML,但它不能很好地处理十进制类型。这是我想写的代码:

declare @doc int
exec sp_xml_preparedocument @doc OUTPUT, @data;

select 
  stringprop1,
  stringprop2,
  decimalprop3  
from openxml(@doc, '/collection/item', 2)
with
(
  stringprop1 nvarchar(50)
  ,stringprop2 nvarchar(50)
  ,decimalprop3 decimal(18, 5)
)

exec sp_xml_removedocument @doc;

这抱怨将 nvarchar 转换为十进制。经过一番折腾,我得出了这个结论:

exec sp_xml_preparedocument @doc OUTPUT, @data;

select 
  nullif(stringprop1, '') as stringprop1,
  nullif(stringprop2, '') as stringprop2,
  convert(decimal(18, 5), nullif(decimalprop3, '')) as decimalprop3
from openxml(@doc, '/collection/item', 2)
with
(
  stringprop1 nvarchar(50)
  ,stringprop2 nvarchar(50)
  ,decimalprop3 nvarchar(50)
)

exec sp_xml_removedocument @doc;

我猜这很好。但是有什么方法可以告诉 OPENXML xsi:nil 表示 NULL 并且对于小数和字符串都可以?

4

3 回答 3

2

xsi:nil 是一个 XML Schema 特性,OpenXML 是在它存在之前设计的,不支持 xsi:nil。由于您使用 SQL Server 2008,因此使其工作的一种方法是:

  1. 使用适当的 XML 模式约束 XML,该模式验证数据并将识别 xsi:nil 并将其映射到空值。

  2. 使用 nodes() 和 value() 方法来提取数据。

最好的问候迈克尔

于 2011-06-09T10:03:31.623 回答
1

这应该这样做:

声明 @doc int
exec sp_xml_preparedocument @doc OUTPUT, @data, '< row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />'

选择  
    字符串prop1,
    字符串prop2,
    十进制prop3
来自 openxml(@doc, '/collection/item', 2)
和
(
    stringprop1 nvarchar(50),
    stringprop2 nvarchar(50) 'stringprop2[not(@xsi:nil = "true")]',
    decimalprop3 nvarchar(50) 'decimalprop3[not(@xsi:nil = "true")]'
)

执行 sp_xml_removedocument @doc;
于 2012-05-08T16:21:33.880 回答
0

死灵术。
这对我有用:

-- How to create the XML 
/*
DECLARE @xml XML 
SET @xml = ( SELECT (SELECT * FROM T_Benutzer FOR XML PATH('row'), ROOT('table'),  ELEMENTS xsinil) AS outerXml )

-- SELECT @xml 
*/


DECLARE @xml xml 
SET @xml = '<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <row>
    <PLK_UID>7CA68E6E-E998-FF92-BE70-126064765EAB</PLK_UID>
    <PLK_Status>1</PLK_Status>
    <BLA_UID>00000000-0000-0000-0000-000000000000</BLA_UID>
  </row>
  <row>
    <PLK_UID>C8A19BB1-6B45-67A6-0417-1F455EE8D2E1</PLK_UID>
    <PLK_Status>1</PLK_Status>
    <BLA_UID xsi:nil="true" />
  </row>
  <row>
    <PLK_UID>C8A19BB1-6B45-67A6-0417-1F455EE8D2E2</PLK_UID>
    <PLK_Status xsi:nil="true" />
    <BLA_UID xsi:nil="true" />
  </row>
  <row>
    <PLK_UID>C8A19BB1-0000-67A6-0417-1F455EE8D2E3</PLK_UID>
    <PLK_Status xsi:nil="true" />
    <BLA_UID>C8A19BB1-1111-67A6-0417-1F455EE8D2E1</BLA_UID>
  </row>
  <row>
    <PLK_UID>C8A19BB1-0001-67A6-0417-1F455EE8D2E4</PLK_UID>
    <PLK_Status>666</PLK_Status>
    <BLA_UID>C8A19BB1-1112-67A6-0417-1F455EE8D2E1</BLA_UID>
  </row>
</table>'


DECLARE @handle INT  
DECLARE @PrepareXmlStatus INT  

EXEC @PrepareXmlStatus = sp_xml_preparedocument @handle OUTPUT, @XML

SELECT 
     PLK_UID 
    ,PLK_Status 
    ,BLA_UID
FROM OPENXML(@handle, '/table/row', 2) WITH 
(
     PLK_UID uniqueidentifier 'PLK_UID[not(@*[local-name()="nil" and . ="true"])]' 
    ,PLK_Status int  'PLK_Status[not(@*[local-name()="nil" and . ="true"])]' 
    ,BLA_UID uniqueidentifier  'BLA_UID[not(@*[local-name()="nil" and . ="true"])]' 
)  

WHERE (1=1) -- AND

EXEC sp_xml_removedocument @handle 

如何创建字段列表:

SELECT 
      CASE WHEN ORDINAL_POSITION = 1 THEN N'     ' ELSE N'    ,' END 
    + N'"' + COLUMN_NAME 
    + N'" '  
    + 
    CASE 
        WHEN DATA_TYPE = 'nvarchar' THEN N'national character varying' 
        WHEN DATA_TYPE = 'varchar' THEN N'character varying' 
        ELSE DATA_TYPE 
    END 
    + 
    CASE 
        WHEN DATA_TYPE IN ('char', 'nchar', 'binary') THEN 
                  N'(' 
                + CAST(CHARACTER_MAXIMUM_LENGTH AS nvarchar(36)) 
                + N')' 
        WHEN DATA_TYPE IN ('varchar', 'nvarchar', 'varbinary') THEN 
                N'(' + 
                CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN 'MAX' ELSE CAST(CHARACTER_MAXIMUM_LENGTH AS nvarchar(36)) END 
                + N')' 
        WHEN DATA_TYPE IN ('datetimeoffset', 'datetime2', 'time', 'smalldatetime') THEN 
                  N'(' 
                + CAST(DATETIME_PRECISION AS nvarchar(36)) 
                + N')' 
        WHEN DATA_TYPE IN ('decimal', 'numeric') THEN 
                  N'(' 
                + CAST(NUMERIC_PRECISION AS nvarchar(36)) 
                + N',' 
                + CAST(NUMERIC_SCALE AS nvarchar(36)) 
                + N')' 

        ELSE N'' -- N'(default)' 
    END 
    + ' ''' + COLUMN_NAME + '[not(@*[local-name()="nil" and . ="true"])]''' 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_SCHEMA = 'dbo' 
AND TABLE_NAME = 'T_Benutzer' 
ORDER BY ORDINAL_POSITION 
于 2019-06-17T13:56:46.193 回答