Pergunta

Eu estou tentando gerar um documento XML do banco de dados SQL Server 2005 usando "FOR XML" construto.

Existem duas tabelas simples no banco de dados com um relacionamento um-para-muitos:

1) Revistas

 | Id | Number | Name       |
 ----------------------------
 | 53 | 0001   | Magazine 1 |
 | 54 | 0002   | Magazine 2 |
 | 55 | 0003   | Magazine 3 |

2) artigos

 | Id |   Title   | MagazineId | Size |
 --------------------------------------
 | 1  | Article 1 |        53  | 1205 |
 | 2  | Article 2 |        53  | 817  |
 | 3  | Article 3 |        54  | 1570 |
 | 4  | Article 4 |        54  | 2510 |
 | 5  | Article 5 |        55  | 910  |

Vamos supor que eu tenho que encontrar todas as revistas que têm um artigo com tamanho maior que 1000 e para produzir o seguinte xml:

<Magazines>
    <Magazine Id="53">
      <Number>0001</Number>
      <Articles>
        <Article Id="1">
           <Title>Article 1</Title>
           <Size>1205</Size>
        </Article>
      </Articles>
    </Magazine>
    <Magazine Id="54">
      <Number>0002</Number>
      <Articles>
        <Article Id="3">
          <Title>Article 3</Title>
          <Size>1570</Size>
        </Article>
        <Article Id="4">
          <Title>Article 4</Title>
          <Size>2510</Size>
        </Article>
      </Articles>
    </Magazine>
</Magazines>

Eu estou tentando produzir tais xml usando um modo "PATH":

SELECT Magazines.Id AS "@Id",
       Magazines.Number AS "Number",
       Articles.Id AS "Articles/Article/@Id",
       Articles.Title AS "Articles/Article/Title",
       Articles.Size AS "Articles/Article/Size"
FROM Magazines INNER JOIN Articles ON Magazines.Id = Articles.MagazineId
WHERE Articles.Size > 1000
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE

Ela irá produzir o seguinte xml:

<Magazines>
  <Magazine Id="53">
    <Number>0001</Number>
    <Articles>
      <Article Id="1">
        <Title>Article 1</Title>
        <Size>1205</Size>
      </Article>
    </Articles>
  </Magazine>
  <Magazine Id="54">
    <Number>0002</Number>
    <Articles>
      <Article Id="3">
        <Title>Article 3</Title>
        <Size>1570</Size>
      </Article>
    </Articles>
  </Magazine>
  <Magazine Id="54">
    <Number>0002</Number>
    <Articles>
      <Article Id="4">
        <Title>Article 4</Title>
        <Size>2510</Size>
      </Article>
    </Articles>
  </Magazine>
</Magazines>

Assim, existem dois elementos para a Revista com Id = "54" (um para cada artigo) e este é o problema.

Eu posso reescrever a consulta usando uma subconsulta como esta:

SELECT M.Id AS "@Id",
       M.Number AS "Number",
    (SELECT Articles.Id AS "@Id",
               Articles.Title AS "Title",
               Articles.Size AS "Size"
  FROM Articles
  WHERE Articles.MagazineId = M.Id
  FOR XML PATH('Article'), ROOT('Articles'), TYPE
    )
FROM Magazines AS M 
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE

E esta produzir a seguinte xml:

<Magazines>
  <Magazine Id="53">
    <Number>0001</Number>
    <Articles>
      <Article Id="1">
        <Title>Article 1</Title>
        <Size>1205</Size>
      </Article>
      <Article Id="2">
        <Title>Article 2</Title>
        <Size>817</Size>
      </Article>
    </Articles>
  </Magazine>
  <Magazine Id="54">
    <Number>0002</Number>
    <Articles>
      <Article Id="3">
        <Title>Article 3</Title>
        <Size>1570</Size>
      </Article>
      <Article Id="4">
        <Title>Article 4</Title>
        <Size>2510</Size>
      </Article>
    </Articles>
  </Magazine>
  <Magazine Id="55">
    <Number>0003</Number>
    <Articles>
      <Article Id="5">
        <Title>Article 5</Title>
        <Size>910</Size>
      </Article>
    </Articles>
  </Magazine>
</Magazines>

Mas usando uma subconsulta não posso revistas filtro por colunas artigos (sem consultas adicionais complexos).

O modo "PARA AUTO XML" não é adequado, porque é muito simples e não suporta algumas características "Caminho" (como atributos usando @, raiz, etc ..)

Assim, há qualquer possibilidade no modo "PATH" para agrupar dados de mesa interior como no modo "AUTO"?

Obrigado!

Foi útil?

Solução

Bem, você pode obter um passo mais próximo, especificando o "tamanho> 1000" dentro do seu subconsulta:

SELECT M.Id AS "@Id",
       M.Number AS "Number",
    (SELECT Articles.Id AS "@Id",
               Articles.Title AS "Title",
               Articles.Size AS "Size"
     FROM Articles
     WHERE Articles.MagazineId = M.Id
           AND Articles.Size > 1000
     FOR XML PATH('Article'), ROOT('Articles'), TYPE
    )
FROM Magazines AS M 
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE

O que está faltando agora é o fato de que você ainda vai receber revistas que não têm artigos com um tamanho> 1000. Você pode eliminar aqueles algo como isto:

SELECT M.Id AS "@Id",
       M.Number AS "Number",
    (SELECT Articles.Id AS "@Id",
               Articles.Title AS "Title",
               Articles.Size AS "Size"
      FROM Articles
      WHERE Articles.MagazineId = M.Id
            AND Articles.Size > 1000
      FOR XML PATH('Article'), ROOT('Articles'), TYPE
    )
FROM Magazines AS M 
WHERE EXISTS(SELECT * FROM Articles 
             WHERE Articles.MagazineId = M.Id 
               AND Articles.Size > 1000)
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE

(não testado, eu não tenho um servidor SQL na mão agora).

Isso funciona para você? Dá-lhe as revistas e artigos que você está procurando?

Marc

Outras dicas

Use FOR XML explícita. É um código mais longo para escrever, mas desaparecem os problemas de desempenho provocate por sub consultas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top