存储过程与xml数据

时间:2017-11-21 10:23:30

标签: sql sql-server xml

我正在尝试从SQL服务器表中的字段获取数据。它存储为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> 

有人可以告诉我如何获得每个&lt;行&gt;具有每个不同列值的SQL行中的元素?

谢谢大家

2 个答案:

答案 0 :(得分:3)

为了解析表中的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的{​​{1}}属性的第一个列元素,并返回ec_date属性的值。

With a Sql Fiddle here

强制性警告

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

另一方面,你的Xml文档中的所有数据都有一个强大的模式,那么我认为Xml是数据建模的不良选择 - 最好将column标准化为其中自己的桌子。 Xml是一种冗长的格式,它重复了模式(即浪费空间),并且很难解析和过滤。

答案 1 :(得分:1)

我认为您可以使用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

<id>{a75f61ce-6627-489f-83bb-d03fc880b764}</id>

我首先删除了#include "Fam.h" #include "iostream" #include "string" using namespace std; using namespace Project1; [STAThread] int main(array<System::String ^> ^args) { Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); Application::Run(gcnew Fam()); return 0; }