2009-09-18 2 views
1

Я пытаюсь создать XML-документ из базы данных SQL Server 2005 с помощью конструкции «FOR XML».SQL Server 2005 «FOR XML PATH» Группировка

Есть два простых таблиц в базе данных с отношения один-ко-многим:

1) Журналы

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

2) Статьи

| 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 | 

Давайте предположим, что я должен найдите все журналы, которые имеют изделие размером более 1000 и для получения следующего 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> 

Я пытаюсь произвести такое XML, используя режим "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 

Он будет производить следующий 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> 

Таким образом, есть два элемента для журнала с Id = "54" (по одному для каждой статьи), и это проблема.

Я могу переписать запрос с использованием подзапроса как это:

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 

И это производит следующий 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> 

Но с помощью подзапроса я не могу фильтровать журналы статьями столбцов (без сложных дополнительных запросов).

«FOR XML AUTO» режим не подходит, потому что это очень просто и не поддерживает некоторые «PATH» функции (такие как атрибуты, используя @, ROOT, и т.д ..)

Итак, есть ли возможность в режиме «PATH» группировать внутренние данные таблицы, например, в режиме «AUTO»?

Спасибо!

ответ

1

Ну, вы можете получить один шаг ближе, указав «размер> 1000» внутри подзапроса:

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 

Что вы теперь не хватает является тот факт, вы все равно получите журналы, которые не имеют статей с размером> 1000. Вы можете устранить это что-то вроде этого:

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 

(проверялся, у меня нет сервера SQL под руку прямо сейчас).

Это работает для вас? Это дает вам журналы и статьи, которые вы ищете?

Marc

+0

Привет, Марк! Спасибо вам за помощь!Ваш запрос работает очень хорошо, но, к сожалению, подзапросы приводят к некоторым проблемам производительности на стороне SQL. Итак, мы решили построить xml на стороне сервера приложений. Спасибо, в любом случае! – junglit

0

Использовать FOR XML явным образом. Самый длинный код для записи, но при этом исчезают проблемы с производительностью, провоцируемые подзапросами.

Смежные вопросы