只能从xml变量中获取标记下的第一条记录

时间:2016-06-24 15:03:21

标签: sql-server xml

我很感激有人帮助我。有时我在所有结果中得到相同的id,我永远无法获得第2个记录(毕业),只有第1个。

xml格式如下:记录标记可以包含一个或多个DOCTORAL标记:

    <Record username=<"erttt">
      <DOCTORAL>
        <PROGRAM>Program Name 1</PROGRAM>
        <MILESTONE>Entered Program</MILESTONE>
        <DTM_DATE>August</DTM_DATE>
        <DTD_DATE>24</DTD_DATE>
        <DTY_DATE>2015</DTY_DATE>
      </DOCTORAL>
   </Record>
   <Record> username=<"xxxgh">
      <DOCTORAL>
         <PROGRAM>Program Name 2</PROGRAM>
         <MILESTONE>Entered Program</MILESTONE>
         <DTM_DATE>Jan</DTM_DATE>
         <DTD_DATE>2</DTD_DATE>
         <DTY_DATE>2014</DTY_DATE>
     </DOCTORAL>
     <DOCTORAL>
         <PROGRAM>Program Name 2</PROGRAM>
         <MILESTONE>Graduated</MILESTONE>
         <DTM_DATE>August</DTM_DATE>
         <DTD_DATE>26</DTD_DATE>
         <DTY_DATE>2016</DTY_DATE>
     </DOCTORAL>
  </Record>

我希望获得如下结果:

    username  Program           Milestone         
    erttt     Program Name 1    Entered Program    
    xxxgh     Program Name 2    Entered Program     
    xxxgh     Program Name 2    Graduated           

所以,上面会有3条记录。

以下内容不起作用,我尝试了很多不同的组合,并查看了本网站上的示例。只是无法弄清楚......

 
SELECT
     x.value('(//Record/@username)[1]','varchar(50)') AS username, --'@username','varchar(50)' DOESN'T WORK HERE
     c.value('(//Record/DOCTORAL/PROGRAM)[1]','varchar(200)') as PROGRAM, 
    c.value('(//Record/DOCTORAL/MILESTONE)[1]','varchar(50)') as MILESTONE,
    c.value('(//Record/DOCTORAL/DTM_DATE)[1]','varchar(8)') as DTM_DATE, --DTM_DATE
    c.value('(//Record/DOCTORAL/DTD_DATE)[1]','varchar(2)') as DTD_DATE,  --DTD_DATE
    c.value('(//Record/DOCTORAL/DTY_DATE)[1]','varchar(4)') as DTY_DATE  --DTY_DATE 
from @xmlDocPrelim.nodes('//Record') t(x)  -- if ends with 'Record', then same id in all recs; if ends in DOCTORAL, then not.  In either case, no grad recs
  cross apply  x.nodes('./DOCTORAL')r(c)

2 个答案:

答案 0 :(得分:1)

我相信这是您需要的语法:

declare @xmlDocPrelim as xml
set @xmlDocPrelim =
'<Record username="erttt">
      <DOCTORAL>
        <PROGRAM>Program Name 1</PROGRAM>
        <MILESTONE>Entered Program</MILESTONE>
        <DTM_DATE>August</DTM_DATE>
        <DTD_DATE>24</DTD_DATE>
        <DTY_DATE>2015</DTY_DATE>
      </DOCTORAL>
   </Record>
   <Record username="xxxgh">
      <DOCTORAL>
         <PROGRAM>Program Name 2</PROGRAM>
         <MILESTONE>Entered Program</MILESTONE>
         <DTM_DATE>Jan</DTM_DATE>
         <DTD_DATE>2</DTD_DATE>
         <DTY_DATE>2014</DTY_DATE>
     </DOCTORAL>
     <DOCTORAL>
         <PROGRAM>Program Name 2</PROGRAM>
         <MILESTONE>Graduated</MILESTONE>
         <DTM_DATE>August</DTM_DATE>
         <DTD_DATE>26</DTD_DATE>
         <DTY_DATE>2016</DTY_DATE>
     </DOCTORAL>
  </Record>
 '
 select @xmlDocPrelim

 SELECT
     x.value('@username','varchar(50)') AS username,
    c.value('./PROGRAM[1]','varchar(200)') as PROGRAM, 
    c.value('./MILESTONE[1]','varchar(50)') as MILESTONE,
    c.value('./DTM_DATE[1]','varchar(8)') as DTM_DATE,
    c.value('(./DTD_DATE)[1]','varchar(2)') as DTD_DATE,
    c.value('(./DTY_DATE)[1]','varchar(4)') as DTY_DATE
from @xmlDocPrelim.nodes('//Record') t(x)
cross apply x.nodes('DOCTORAL') r(c)

结果:

username   PROGRAM           MILESTONE           DTM_DATE DTD_DATE DTY_DATE
---------- ----------------- ------------------- -------- -------- --------
erttt      Program Name 1    Entered Program     August   24       2015
xxxgh      Program Name 2    Entered Program     Jan      2        2014
xxxgh      Program Name 2    Graduated           August   26       2016

答案 1 :(得分:0)

首先,XML中存在语法错误。修复后,以下代码给出了您想要的内容。

declare @x xml=
'<Record username="erttt">
      <DOCTORAL>
        <PROGRAM>Program Name 1</PROGRAM>
        <MILESTONE>Entered Program</MILESTONE>
        <DTM_DATE>August</DTM_DATE>
        <DTD_DATE>24</DTD_DATE>
        <DTY_DATE>2015</DTY_DATE>
      </DOCTORAL>
   </Record>
   <Record username="xxxgh">
      <DOCTORAL>
         <PROGRAM>Program Name 2</PROGRAM>
         <MILESTONE>Entered Program</MILESTONE>
         <DTM_DATE>Jan</DTM_DATE>
         <DTD_DATE>2</DTD_DATE>
         <DTY_DATE>2014</DTY_DATE>
     </DOCTORAL>
     <DOCTORAL>
         <PROGRAM>Program Name 2</PROGRAM>
         <MILESTONE>Graduated</MILESTONE>
         <DTM_DATE>August</DTM_DATE>
         <DTD_DATE>26</DTD_DATE>
         <DTY_DATE>2016</DTY_DATE>
     </DOCTORAL>
  </Record>'

  select  t.v.value('../@username','varchar(20)') username,
          t.v.value('PROGRAM[1]','varchar(20)') Program,
          t.v.value('MILESTONE[1]','varchar(20)') Milestone
  from @x.nodes('//DOCTORAL') t(v)