OPENXML、Xsi:nil 和小数

发布于 2024-11-15 00:32:40 字数 1459 浏览 4 评论 0原文

我有一些 XML,其中包含某些字符串和数字元素的 xsi:nil="true" 。下面是一个示例:

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 并且这对于小数和字符串都可以吗?

I have some XML containing xsi:nil="true" for certain string and numeric elements. Here's an example:

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>'

I want to query that XML in SQL Server 2008 R2. I'm using OPENXML but it's not playing nicely with decimal types. Here's the code I'd like to write:

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;

This complains about converting nvarchar to decimal. After some hacking around, I arrived at this:

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;

Which is fine, I guess. But is there any way to tell OPENXML that xsi:nil means NULL and that that's ok for decimals as well as strings?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

友欢 2024-11-22 00:32:40

xsi:nil 是一种 XML 模式功能,OpenXML 是在它出现之前就设计的,并且不支持 xsi:nil。由于您使用 SQL Server 2008,使其发挥作用的一种方法是:

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

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

此致
迈克尔

xsi:nil is an XML Schema feature and OpenXML was designed before it's existance and does not support xsi:nil. Since you use SQL Server 2008, one way to make this to work is to:

  1. constrain the XML with the appropriate XML Schema that validates the data and will recognize the xsi:nil and map it to the empty value.

  2. use the nodes() and value() methods to extract the data.

Best regards
Michael

烙印 2024-11-22 00:32:40

这应该做:

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

select  
    stringprop1, 
    stringprop2, 
    decimalprop3 
from openxml(@doc, '/collection/item', 2) 
with 
( 
    stringprop1 nvarchar(50), 
    stringprop2 nvarchar(50) 'stringprop2[not(@xsi:nil = "true")]', 
    decimalprop3 nvarchar(50) 'decimalprop3[not(@xsi:nil = "true")]' 
) 

exec sp_xml_removedocument @doc; 

This should do:

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

select  
    stringprop1, 
    stringprop2, 
    decimalprop3 
from openxml(@doc, '/collection/item', 2) 
with 
( 
    stringprop1 nvarchar(50), 
    stringprop2 nvarchar(50) 'stringprop2[not(@xsi:nil = "true")]', 
    decimalprop3 nvarchar(50) 'decimalprop3[not(@xsi:nil = "true")]' 
) 

exec sp_xml_removedocument @doc; 
山人契 2024-11-22 00:32:40

死灵术。
这对我有用:

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

Necromancing.
This is what works for me:

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

How to create the field-list:

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 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文