SQL Server For XML自动问题

时间:2012-02-17 14:10:11

标签: sql-server xml sql-server-2008 tsql

您好我正在尝试让我的数据库输出XML并且我在某种程度上取得了成功。

当我使用各种联接进行标准选择时,一切正常,我添加以下行:

for xml auto, root('MyRoot')

这生成了所需的XML

然而,当我在选择其中一个标签时使用强制转换或转换时,将其合并到其父级中,我不知道为什么或如何修复它。其他一切都很完美。

下面是根据需要输出XML的代码

select  Tbl1.id, 
        'xyz   ' as [randCol], 
        Tbl2.id,
        Tbl2.name, 
        aDate as [date] --(aDate is the date field, date here is not data type, but a colum name for output) 
from dbo.table1 as Tbl1 
inner join dbo.table3 as Tbl3 
on Tbl1.id = Tbl3.table1id 
inner join table2 as Tbl2 
on Tbl3.table2id = Tbl2.id 
where Tbl1.id = 1 

for xml auto, root('MyRoot')

所以生成的XML是这样的:

<MyRoot>
  <Tbl1 id="1" randCol="xyz   ">
    <Tbl2 id="10001" name="John">
      <Tbl3 date="2011-10-19T22:59:00" />
    </Tbl2>
    <Tbl2 id="10002" name="Brian">
      <Tbl3 date="2011-10-19T22:59:00" />
    </Tbl2>
    <Tbl2 id="10003" name="Jimmy">
      <Tbl3 date="2011-05-19T23:00:00" />
    </Tbl2>
  </Tbl1>
</MyRoot>

问题在于,当我用以下行替换“aDate as date”行来格式化我的XML搞砸的日期。

CONVERT(date,aDate) as [date]

这会导致以下输出:

<MyRoot>
  <Tbl1 id="1" randCol="xyz   ">
    <Tbl2 id="10001" name="dave" date="2010-11-17" />
    <Tbl2 id="10002" name="harry" date="2010-11-16" />
    <Tbl2 id="10003" name="lenny" date="2010-06-15" />
  </Tbl1>
</MyRoot>

导致此更改的原因是我如何按照我想要的方式格式化日期并将其保存在单独的一行中,如第一个示例所示。

EDIT2:下面是db的ERD(我删除了erd的解释,只是放了一个错误。还有一些示例数据:以下是我想要的xml数据集。

id    randCol   id        name      date
1     xyz       10001     John      2011-10-19
1     xyz       10002     Brian     2011-10-19
1     xyz       10003     Jimmy     2011-05-19

使用select *运行的完整数据集将显示以下内容:(出于解释连接的目的)。

id  table1id   table2id   aDate                 id      name
1   1          10001      2011-10-19 22:59:00   10001   John
1   1          10002      2011-10-19 22:59:00   10002   Brian
1   1          10003      2011-05-19 23:00:00   10003   Jimmy

enter image description here

我想要实现的是以下格式的XML输出。

<MyRoot>
  <Tbl1 id="1" randCol="xyz   ">
    <Tbl2 id="10001" name="John">
      <Tbl3 date="2011-10-19" />
    </Tbl2>
    <Tbl2 id="10002" name="Brian">
      <Tbl3 date="2011-10-19" />
    </Tbl2>
    <Tbl2 id="10003" name="Jimmy">
      <Tbl3 date="2011-05-19" />
    </Tbl2>
  </Tbl1>
</MyRoot>

但是我需要在不使用Explisit的情况下实现这一点,因此需要知道我是应该使用Raw,Auto还是Path,以及使用什么组合的参数。

2 个答案:

答案 0 :(得分:1)

我认为问题在于,通过转换(与任何相当复杂的函数一样),结果列不再“属于”Tbl3(想象一个函数从多个表中获取列 - 哪个表是它“属于?)。正如Using AUTO Mode所说:

  

这不能很好地控制从查询结果生成的XML的形状。 ...使用EXPLICIT模式和使用PATH模式提供更多控制

  

SELECT子句中的列不能与FROM子句中标识的任何表关联时,如聚合列或计算列的情况,该列将添加到在列表中遇到最深嵌套级别的XML文档。如果此列显示为SELECT子句中的第一列,则该列将添加到顶部元素。

所以我建议切换到使用PATH。在简化查询时,我认为您已经过度简化了联接,因为它们现在都处于相同的id值,但以下内容会生成正确的查询形式:

declare @table1 table (
    id int not null
)
declare @table2 table (
    id int not null,
    name varchar(10) not null
)
declare @table3 table (
    table1id int not null,
    table2id int not null,
    aDate datetime not null
)

insert into @table1 (id) select 1
insert into @table2 (id,name) select 10001,'John' union all select 10002,'Brian' union all select 10003,'Jimmy'
insert into @table3 (table1id,table2id,aDate)
select 1,10001,'2011-10-19T22:59:00' union all
select 1,10002,'2011-10-19T22:59:00' union all
select 1,10003,'2011-05-19T23:00:00'
select  Tbl1.id as [@id],
        'xyz   ' as [@randCol],
        (select 
          Tbl2.id as [@id],
          Tbl2.name as [@name],
          CONVERT(date,aDate) as [Tbl3/@date] --(aDate is the date field, date here is not data type, but a colum name for output)
        from
          @table3 as Tbl3 
             inner join
          @table2 as Tbl2 
             on
                Tbl3.table2id = Tbl2.id 
        where
          Tbl1.id = Tbl3.table1id 
        for xml path('Tbl2'), type)
from @table1 as Tbl1 
where Tbl1.id = 1 

for xml path('Tbl1'), root('MyRoot')

结果:

<MyRoot>
  <Tbl1 id="1" randCol="xyz   ">
    <Tbl2 id="10001" name="John">
      <Tbl3 date="2011-10-19" />
    </Tbl2>
    <Tbl2 id="10002" name="Brian">
      <Tbl3 date="2011-10-19" />
    </Tbl2>
    <Tbl2 id="10003" name="Jimmy">
      <Tbl3 date="2011-05-19" />
    </Tbl2>
  </Tbl1>
</MyRoot>

答案 1 :(得分:0)

我认为在这种情况下你必须使用XML Path。 尝试这样的事情:

select  Tbl1.id,
        'xyz   ' as [randCol],
        (SELECT Tbl2.id,
                Tbl2.name,
                (convert(date,aDate,102)) as [date]
                FROM (dbo.table1 as Tbl1 inner join table3 as Tbl3 on Tbl1.id = Tbl3.id inner join table2 as Tbl2 on Tbl3.id = Tbl2.id where Tbl1.id = 1)
                FOR XML PATH('Table2'), TYPE
        ) 
from table1
FOR XML path('Table1'), root('myroot'), ELEMENTS;

如果它不起作用,你可以发布你的表格结构,以便更容易测试吗?