【问题标题】:Stored Procedure with a xml data带有 xml 数据的存储过程
【发布时间】:2017-11-21 22:28:54
【问题描述】:

我正在尝试从 SQL Server 表中的字段中获取数据。它存储为 xml,我想在不同的行中获取每个节点值。 xml示例是这样的:

<id>{a75f61ce-6627-489f-83bb-d03fc880b764}</id>
<rows>
    <row>
        <columns>
            <column name="ec_date" value="15-November-2017" type="System.DateTime" />
            <column name="ec_amount" value="160" type="System.Decimal" />
            <column name="ec_description" value="viaje en coche" type="System.String" />
            <column name="ec_factura" value="0" type="System.String" />
            <column name="ec_item" value="105.01" type="System.String" />
            <column name="DefaultKey" value="1" type="System.Int32" />
        </columns>
    </row>
    <row>
        <columns>
            <column name="ec_date" value="16-November-2017" type="System.DateTime" />
            <column name="ec_amount" value="2.55" type="System.Decimal" />
            <column name="ec_description" value="2 horas de parkin" type="System.String" />
            <column name="ec_factura" value="0" type="System.String" />
            <column name="ec_item" value="15.04" type="System.String" />
            <column name="DefaultKey" value="2" type="System.Int32" />
        </columns>
    </row>
    <row>
        <columns>
            <column name="ec_date" value="17-November-2017" type="System.DateTime" />
            <column name="ec_amount" value="200" type="System.Decimal" />
            <column name="ec_description" value="taxi a burgos" type="System.String" />
            <column name="ec_factura" value="0" type="System.String" />
            <column name="ec_item" value="15.06" type="System.String" />
            <column name="DefaultKey" value="3" type="System.Int32" />
        </columns>
    </row>
</rows> 

有人可以告诉我如何获取 sql 行中每个不同列值的 元素吗?

谢谢大家

【问题讨论】:

  • 如果此 XML 的构造在您的控制之下,我强烈建议您使用 ISO8601 作为日期(yyyy-MM-ddyyyy-MM-ddTHH:mm:ss)。您的格式取决于文化和语言,可能会通过所有内部测试,但会因 December 与 Dezember 之类的微小差异而在客户的系统上中断

标签: sql sql-server xml


【解决方案1】:

为了解析表中的Xml 列,您需要使用XQuery。这是一个示例,说明您将如何处理 - 每个row xml 元素将返回一行:

SELECT
    Rows.col.value('(column[@name="ec_date"]/@value)[1]', 
        'DATE') AS EcDate,
    Rows.col.value('(column[@name="ec_amount"]/@value)[1]', 
        'decimal(10,2)') AS EcAmount,
    Rows.col.value('(column[@name="ec_description"]/@value)[1]', 
        'varchar(max)') AS EcDescription
    -- .. etc
FROM
    MyTable mt
    CROSS APPLY
        mt.XmlCol.nodes('//rows/row/columns') 
      AS Rows(col);

(column[@name="ec_date"]/@value)[1] 粗略地翻译为“为我找到第一个具有 name 属性值为 ec_date 的列元素,并将 value 属性的值返回给我。

With a Sql Fiddle here

强制性警告

虽然 xml column 属性名称和类型看起来一致,但似乎数据中嵌入了一个类型系统 - 即尝试提供动态更改列类型的能力确实会使这非常混乱。

另一方面,在您的 Xml 文档中的所有数据中都有一个强大的架构,那么我认为 Xml 是数据建模的一个糟糕选择 - 最好将 row 标准化到它自己的表中. Xml 是一种冗长的格式,它会重复架构(即浪费空间),并且可能难以解析和过滤。

【讨论】:

  • 由于 'row' 和 'columns 之间存在 1:1 的关系,因此任何一种方式都有效,即使有多行 xml data。不过,我想我冒昧地在别名中调用了包装器“行”。
  • 对不起,你当然是对的!投票赞成...一个小提示:您在Xpath 中使用/xml,但问题中的原始XML 未显示根节点。可能会误导...
  • 好点 - OP 的原始文档没有根并且从技术上讲是无效的,但似乎 XQuery 可以接受。已更新。
【解决方案2】:

我觉得你可以用OPENXML

DECLARE @idoc int, @doc varchar(MAX)

SET @doc='<id>{a75f61ce-6627-489f-83bb-d03fc880b764}</id>
<rows>
    <row>
        <columns>
            <column name="ec_date" value="15-November-2017" type="System.DateTime" />
            <column name="ec_amount" value="160" type="System.Decimal" />
            <column name="ec_description" value="viaje en coche" type="System.String" />
            <column name="ec_factura" value="0" type="System.String" />
            <column name="ec_item" value="105.01" type="System.String" />
            <column name="DefaultKey" value="1" type="System.Int32" />
        </columns>
    </row>
    <row>
        <columns>
            <column name="ec_date" value="16-November-2017" type="System.DateTime" />
            <column name="ec_amount" value="2.55" type="System.Decimal" />
            <column name="ec_description" value="2 horas de parkin" type="System.String" />
            <column name="ec_factura" value="0" type="System.String" />
            <column name="ec_item" value="15.04" type="System.String" />
            <column name="DefaultKey" value="2" type="System.Int32" />
        </columns>
    </row>
    <row>
        <columns>
            <column name="ec_date" value="17-November-2017" type="System.DateTime" />
            <column name="ec_amount" value="200" type="System.Decimal" />
            <column name="ec_description" value="taxi a burgos" type="System.String" />
            <column name="ec_factura" value="0" type="System.String" />
            <column name="ec_item" value="15.06" type="System.String" />
            <column name="DefaultKey" value="3" type="System.Int32" />
        </columns>
    </row>
</rows>'

-- delete <id>
SET @doc=STUFF(@doc,1,47,'')    

EXEC sp_xml_preparedocument @idoc OUTPUT, @doc;

SELECT *  
FROM OPENXML(@idoc,'/rows/row/columns',2)   
  WITH (ec_date        date         './column[1]/@value',   
        ec_amount      float        './column[2]/@value',   
        ec_description varchar(200) './column[3]/@value',   
        ec_factura     int          './column[4]/@value',   
        ec_item        float        './column[5]/@value',
        DefaultKey     int          './column[6]/@value');

EXEC sp_xml_removedocument @idoc;
GO

我首先删除了&lt;id&gt;{a75f61ce-6627-489f-83bb-d03fc880b764}&lt;/id&gt;

【讨论】:

  • FROM OPENXML 与相应的 SP 准备和删除文档已过时,不应再使用。而是使用适当的methods the XML data type provides
  • @Shnugo - 感谢您提供信息!我需要更新关于 XML 的知识。我已经很长时间没有使用它了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 2013-11-17
相关资源
最近更新 更多