如何在Sql Server XML中的不同表中创建Element和Attriubte?

时间:2016-07-04 17:26:30

标签: xml sql-server-2012

我正在尝试使用Sql Server 2012 Express在表中创建一些XML值。具体来说,我希望一个元素具有来自1个表的属性,并且该元素具有来自另一个表的值。用例是属性表示内部Id,而值/文本表示人类可读的内容。

我有两张桌子:

卡,其中包含列

Id, Name, BookId, and Page

类别,其中包含列

Id and Name

所需的XML是:

<Card id="2">
  <Name>My Card</Name>
  <Location>
    <Book cid="66">My Book</Book>
    <Page>118</Page>
  </Location>
</Card>

注意“Book”元素,它具有Card表中的属性和Category表中的Value / Text。

我已经尝试了两个让我非常接近的查询,但并不完全相同。这个查询会将book id放在“Location”元素中(boo!),但它按照我想要的方式构造元素(是的!):

select
    c.Id [@id],
    c.Name,
    (
        select
            (
                select
                    c.BookId [@cid]
                    ,book.Name
                for
                    xml path( 'Book' ), type
            ),
            c.[Page]
        for
            xml path( 'Location' ), type
    )
from
     Card c
     left outer join Category book on book.Id = c.BookId
where
    c.Id = @cardId
for
    xml path( 'Card' ), type

产生

<Card id="2">
  <Name>My Card</Name>
  <Location>
    <Book cid="66">
      <Name>My Book</Name> <!-- need to stop My Book from appearing in its own element -->
    </Book>
    <Page>118</Page>
  </Location>
</Card>

和这个查询,它将书籍ID放在书籍元素中(耶!),但将书名放在自己的元素中(嘘!)。

select
        c.Id [@id],
        c.Name,
        (
            select
                c.BookId [@bookId],
                book.Name Book,
                c.[Page]
            for
                xml path( 'Location' ), type
        )
    from
         Card c
         left outer join Category book on book.Id = c.BookId
    where
        c.Id = @cardId
    for
        xml path( 'Card' ), type

产生

<Card id="2">
  <Name>My Card</Name>
  <Location bookId="66"> <!-- need bookId to appear in the Book element -->
    <Book>My Book</Book>
    <Page>118</Page>
  </Location>
</Card>

我认为我非常接近,但在这一点上它是盲目的试验和错误,这不是我想要度过我的假期:)任何帮助将不胜感激。谢谢!

编辑 - 2017/01/08 我最终得到了以下查询,它提供了我想要的内容。 Shnugo在下面也提供了一个非常相似的答案,没有使用子选择。

select
    c.Id [@id],
    c.Name,
    (
        select
            c.BookId [Book/@bookId],
            book.Name [Book],
            c.Page [Page]
        for
            xml path( 'Location' ), type
    )
from
    Card c
    inner join Category book on book.Id = c.BookId
for
    xml path( 'Card' ), type

2 个答案:

答案 0 :(得分:1)

我认为你正在寻找:

如果<Card><Location>之间没有1:n关系,则无需进行子选择......

DECLARE @Card TABLE(Id INT, Name VARCHAR(100), BookId INT,  [Page] INT);
INSERT INTO @Card VALUES(2,'My Card',66,118);
DECLARE @Category TABLE(Id INT,Name VARCHAR(100));
INSERT INTO @Category VALUES(66,'My Book');

SELECT c.Id AS [@id]
      ,c.Name AS [Name]
      ,c.BookId AS [Location/Book/@cid]
      ,book.Name AS [Location/Book]
      ,c.Page AS [Location/Page]
from
     @Card c
     left outer join @Category book on book.Id = c.BookId
FOR XML PATH('Card')

结果

<Card id="2">
  <Name>My Card</Name>
  <Location>
    <Book cid="66">My Book</Book>
    <Page>118</Page>
  </Location>
</Card>

答案 1 :(得分:0)

你可以用XQuery

来做
select (

    select c.Id [@id], c.Name, book.Name [Book], book.Id [cid], c.Page
    from Card c
    left outer join Category book on book.Id = c.BookId
    where c.Id = @cardId
    for xml path('Card'), type

).query('

<Card id="{/Card/@id}">
    {/Card/Name}
    <Location>
        <Book cid="{/Card/cid}">{data(/Card/Book)}</Book>
        {/Card/Page}
    </Location>
</Card>

')