在SQL Server的嵌套XML中传递参数

问题描述 投票:0回答:1

我有一个如下所示的xml文件。具有主分支Teacherdetails的xml查询可以是单个对象或多个对象。内部教师详细信息学生人数用b表示,学生列表以嵌套对象的形式表示。

<teacherdetails>
    <teacher>2222</teacher>
    <a>10</a>
    <b>3</b>
    <students>
        <student>
          <stua>2000</stua>
          <dista>1</dista>
        </student>
        <student>
          <stua>20</stua>
          <dista>1</dista>
         </student>
         <student>
          <stua>20</stua>
          <dista>1</dista>
         </student>
         <student>
             <Reportno>1586215497241</Reportno>
             <sal>
                <month>13.245555</month>
                <month>72.234355</month>
             </sal>
</teacherdetails>
<teacherdetails>
      <teacher>2222</teacher>
      <a>10</a>
      <b>3</b>
      <students>
        <student>
          <stua>2000</stua>
          <dista>1</dista>
        </student>
        <student>
          <stua>20</stua>
          <dista>1</dista>
         </student>
        <student>
          <stua>20</stua>
          <dista>1</dista>
         </student>
        <student>
      <Reportno>1586215497241</Reportno>
      <sal>
        <month>13.245555</month>
        <month>72.234355</month>
      </sal>
</teacherdetails>

我正在尝试使用SQL访问a,b,b学生的详细信息。当我使用while循环使用xml.nodes时,我尝试设置低于该值会引发错误

;with numbers as
(
    select number
    from master..spt_values
    where type = 'P'
)
select
    T.N.value('teacher[1]', 'varchar(50)') as teacher,
    T.N.value('(students/student/stua[position()=sql:column("N.Number")])['+ @set +']', 'varchar(max)') as student,
    T.N.value('(students/student/dista[position()=sql:column("N.Number")])['+ @set +']', 'varchar(max)')as distance
from 
    @string.nodes('/teacherdetails') as T(N)
cross join 
    numbers as n
where 
    n.number between 1 and (T.N.value('count(students)', 'int'))

注意:当我用硬编码1或2代替@set值时,它工作正常]

引发错误:

这里应该是字符串文字...

我尝试更改引号使其成为动态查询

sql sql-server xml xquery-sql
1个回答
0
投票
declare @x xml = N'
<teacherdetails>
  <teacher>2222</teacher>
  <a>10</a>
  <b>3</b>
  <students>
    <student>
      <stua>2000</stua>
      <dista>1</dista>
    </student>
    <student>
      <stua>20</stua>
      <dista>2</dista>
    </student>
    <student>
      <stua>30</stua>
      <dista>3</dista>
    </student>
  </students>
  <Reportno>1586215497241</Reportno>
  <sal>
    <month>13.245555</month>
    <month>72.234355</month>
  </sal>
</teacherdetails>
<teacherdetails>
  <teacher>3456</teacher>
  <a>10</a>
  <b>2</b>
  <students>
    <student>
      <stua>789</stua>
      <dista>1</dista>
    </student>
    <student>
      <stua>20</stua>
      <dista>2</dista>
    </student>
  </students>
  <Reportno>1586215343434</Reportno>
  <sal>
    <month>13.245555</month>
    <month>72.234355</month>
  </sal>
</teacherdetails>
';    


select 
    t.tchr.value('./teacher[1]', 'nvarchar(50)') as teacherId,
    s.std.value('./stua[1]', 'nvarchar(50)') as stua,
    s.std.value('./dista[1]', 'nvarchar(50)') as dista  
from @x.nodes('./teacherdetails') as t(tchr) --teacher
cross apply t.tchr.nodes('./students/student') as s(std); --students of each teacher


--for your approach, student[position()= sql:column("n.number")]/stua is always a single element thus [1]
;with numbers as(
select number
from master..spt_values
where type = 'P'
)
select
n.number,
T.N.value('teacher[1]', 'varchar(50)') as teacher,
T.N.value('(./students/student[position()= sql:column("n.number")]/stua)[1]', 'varchar(max)') as student,
T.N.value('(./students/student[position()= sql:column("n.number")]/dista)[1]', 'varchar(max)')as distance
from @x.nodes('/teacherdetails')  as T(N)
cross join numbers as n
where n.number between 1 and (T.N.value('./b[1]','int'));
© www.soinside.com 2019 - 2024. All rights reserved.