从SQL Server表

时间:2016-02-29 13:52:22

标签: sql sql-server xml

我已经尝试了与此主题相关的SO线程的所有建议,但仍然没有得到我需要的东西。我有一个名为SC的XML列。这是在SQL Server 2014上(如果它很重要)。表格中只有一行,而SC列中的XML数据包含以下代码段...

<SC_ROOT>
  <COMPONENTS>
    <COMPONENT>
      <NAME>Status A Detection</NAME>
      <PROPERTIES>
        <COMP_ENABLED>True</COMP_ENABLED>
      </PROPERTIES>
    </COMPONENT>
    ...
  </COMPONENTS>
</SC_ROOT>

我想仅返回<NAME><COMP_ENABLED>的表格,仅用于<NAME>包含“检测”的项目。如果已经有一个很好的例子请指点我吗?提前谢谢!

2 个答案:

答案 0 :(得分:4)

试试这个:

SELECT
    Name = xc.value('(NAME)[1]', 'varchar(50)'),
    CompEnabled = xc.value('(PROPERTIES/COMP_ENABLED)[1]', 'varchar(10)')
FROM 
    dbo.YourTable
CROSS APPLY
    SC.nodes('/SC_ROOT/COMPONENTS/COMPONENT') AS XT(XC)
WHERE
    xc.value('(NAME)[1]', 'varchar(50)') LIKE '%Detection'

.nodes()调用基本上返回一个“虚拟表”,其表别名为XT,其中包含一列(别名XC),其中包含与XPath表达式对应的XML片段 - 基本上是<COMPONENT> XML片段。您可以深入了解所需的详细信息

更新:如果你的XML看起来像这样:

<COMPONENT>
  <NAME>Status A Detection</NAME>
  <PROPERTIES NAME="COMP_ENABLED" VALUE="True" />
</COMPONENT>

然后使用此代码获取结果:

SELECT
    Name = xc.value('(NAME)[1]', 'varchar(50)'),
    CompEnabled = xc.value('(PROPERTIES[@NAME="COMP_ENABLED"]/@VALUE)[1]', 'varchar(10)')
FROM 
    dbo.YourTable
CROSS APPLY
    SC.nodes('/SC_ROOT/COMPONENTS/COMPONENT') AS XT(XC)
WHERE
    xc.value('(NAME)[1]', 'varchar(50)') LIKE '%Detection'

答案 1 :(得分:2)

因此,假设COMPONENT可以重复,并且您只想选择COMPONENT NAME LIKE '%Detection%'个节点,则以下内容应该有效:

DECLARE @xml xml = '<SC_ROOT>
  <COMPONENTS>
    <COMPONENT>
      <NAME>Status A Detection</NAME>
      <PROPERTIES>
        <COMP_ENABLED>True</COMP_ENABLED>
      </PROPERTIES>
    </COMPONENT>  
    <COMPONENT>
      <NAME>Status B Other</NAME>
      <PROPERTIES>
        <COMP_ENABLED>True</COMP_ENABLED>
      </PROPERTIES>
    </COMPONENT>  
    <COMPONENT>
      <NAME>Status C Detection</NAME>
      <PROPERTIES>
        <COMP_ENABLED>True</COMP_ENABLED>
      </PROPERTIES>
    </COMPONENT>    
  </COMPONENTS>
</SC_ROOT>'

SELECT X.Component.query('.')
FROM @xml.nodes('/SC_ROOT/COMPONENTS/COMPONENT') as X(Component)
WHERE CAST(x.Component.query('NAME/text()') AS NVARCHAR(100)) LIKE '%Detection%'

输出:

<COMPONENT><NAME>Status A Detection</NAME><PROPERTIES><COMP_ENABLED>True</COMP_ENABLED></PROPERTIES></COMPONENT>
<COMPONENT><NAME>Status C Detection</NAME><PROPERTIES><COMP_ENABLED>True</COMP_ENABLED></PROPERTIES></COMPONENT>

这将为您提供原始XML片段。如果您想将其粉碎到表格,则必须修改您选择的列以及.query()中的SELECT。只要至少有一个NAME中包含单词COMPONENT,无论'Detection'NAME中重复多少次,这都会有效。

如果SELECT X.Component.query('.') FROM @xml.nodes('/SC_ROOT/COMPONENTS/COMPONENT[contains(NAME[1], "Detection")]') as X(Component) 只能出现一次,或者您只关心第一个实例,那么您也可以这样做:

SELECT 
    DATEPART(yyyy, ce.DueDate) AS year,
    DATEPART(mm, ce.DueDate) AS Month,
    COUNT(CASE WHEN rt.Code = 'Pass' THEN 1 ELSE NULL END) AS NumPass,
    COUNT(CASE WHEN rt.Code = 'Fail' THEN 1 ELSE NULL END) AS NumFail
FROM
    ControlEvent ce
INNER JOIN 
    ProcessEvent pe ON pe.ControlEventId = ce.Id
INNER JOIN 
    ResultType rt ON pe.ResultTypeId = rt.Id
WHERE 
    DATEDIFF(dd,ce.DueDate,GETDATE()) <= 0
    AND DATEDIFF(dd,ce.DueDate,DATEADD(mm, 3, GETDATE())) >= 0
    AND pe.ProcessId = 1040
GROUP BY 
    DATEPART(yyyy, ce.DueDate), DATEPART(mm, ce.DueDate)
ORDER BY 
    DATEPART(yyyy, ce.DueDate), DATEPART(mm, ce.DueDate)

哪个会产生相同的输出。