已解决:在MSSQL

时间:2018-07-19 10:30:33

标签: sql-server xml xsd

一个客户要求从数据库中转储一堆带有不同列的数据。只要是SQL,一切都很好,也很容易,但是我遇到了一个问题,其中对于两个请求的值,我需要从XML文件中提取它。我刚上班,进入公司并没有太多帮助,而且我想在这里给我的老板留下深刻的印象,所以很多事情都危在旦夕。

这是XML文件的一个片段:

<record xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" runtimeVersion="2">
  <insureds>
    <insured uid="xxx" category="000" name="this name" index="0">
      <dimensions>
        <dimension id="name">
          <value xsi:type="xsd:string">Morten</value>
        </dimension>
        <dimension id="price">
          <value xsi:type="xsd:decimal">20</value>
        </dimension>
        <dimension id="duration">
          <value xsi:type="xsd:decimal">10</value>
        </dimension>
     </dimensions>
   </insured>
   <insured uid="xxx" category="000" name="this other name" index="1">
     <dimensions>
       <dimension id="price">
         <value xsi:type="xsd:decimal">40</value>
       </dimension>
       <dimension id="name">
         <value xsi:type="xsd:string">Casper</value>
       </dimension>
     </dimensions>
   </insured>
   <insured uid="xxx" category="000" name="this last name" index="2">
     <dimensions>
       <dimension id="price">
         <value xsi:type="xsd:decimal">0</value>
       </dimension>
     </dimensions>
   </insured>

对于每种XML,我都希望其中的值是id =“ price”。但是,我的问题是XML随时间而变化,因此对于所有示例而言,价格都不是相同的索引值。相反,我需要在每个XML中找到FIRST TIME id =“ price”的值(因为可以有多个保险/尺寸/价格,并且第一个实例可以移动到新位置)。因此,在上面的示例中,我正在寻找值20。

我得到了下面的工作,但不幸的是,它仅在“价格”处于位置[36]的情况下有效,在生产500000条记录的过程中它已经移动了很多次...

SELECT  Xml.value('(/record/insureds/insured/dimensions/dimension/value) [36]', 
'varchar(max)')     AS 'Price'

我正在尝试根据一些在线示例对其进行修改,这就是我得到的:

SELECT Xml.value('(/record/insureds/insured/dimensions/dimension/@id=@trip_cost)[1]', 
'varchar(max)')     AS 'Price'

这给了我一个错误:“不支持顶级属性节点。”

现在,我被困住了...关于如何实现获取第一个维度id =“ price”的值的目的的任何想法,无论它在XML中的位置如何?

任何提示,想法或其他类似的东西都非常感谢!

**编辑-这已通过@JeroenMostert的评论**

解决。

1 个答案:

答案 0 :(得分:2)

使用.value()将返回一个单个值。您的问题对我来说还不是很清楚,但是我的魔幻水晶球告诉我,您可能正在寻找这个:

DECLARE @xml XML=
'<record xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" runtimeVersion="2">
  <insureds>
    <insured uid="xxx" category="000" name="this name" index="0">
      <dimensions>
        <dimension id="name">
          <value xsi:type="xsd:string">Morten</value>
        </dimension>
        <dimension id="price">
          <value xsi:type="xsd:decimal">20</value>
        </dimension>
        <dimension id="duration">
          <value xsi:type="xsd:decimal">10</value>
        </dimension>
     </dimensions>
   </insured>
   <insured uid="xxx" category="000" name="this other name" index="1">
     <dimensions>
       <dimension id="price">
         <value xsi:type="xsd:decimal">40</value>
       </dimension>
       <dimension id="name">
         <value xsi:type="xsd:string">Casper</value>
       </dimension>
     </dimensions>
   </insured>
   <insured uid="xxx" category="000" name="this last name" index="2">
     <dimensions>
       <dimension id="price">
         <value xsi:type="xsd:decimal">0</value>
       </dimension>
     </dimensions>
   </insured>
 </insureds>
</record>';

-此查询将以经典的 entity-value 列表返回所有内容的派生表(嗯,其余内容取决于您,但应该很容易)。您可以将其打包到CTE中,并对派生表使用任何类型的WHERE

SELECT i.value('@uid','varchar(max)') AS insured_uid
      ,d.value('@id','varchar(max)') AS dimension_id
      ,d.value('(value/text())[1]','varchar(max)') AS dimension_value
FROM @xml.nodes('/record/insureds/insured') A(i)
CROSS APPLY i.nodes('dimensions/dimension') B(d);

-这将找到所有<dimension>个节点,其中有一个值为@id的属性"price"并列出以下值:

SELECT d.value('(value/text())[1]','varchar(max)') AS dimension_value
FROM @xml.nodes('//dimension[@id="price"]') A(d);

如果这对您没有帮助,最好将预期的输出拟合包括到所提供的样本数据中。最好是MCVE(一个独立,经过简化但完整的示例,如我上面提供的代码)。