SQL Server 2008 ДЛЯ справки ПО ПУТИ XML

#sql #sql-server #xml #sql-server-2008 #for-xml

#sql #sql-сервер #xml #sql-server-2008 #для-xml

Вопрос:

У меня есть таблица записей истории. Одно поле [добавлено] имеет тип данных datetime. Что я пытаюсь сделать, так это выбрать 20 самых последних записей пользователя, но затем сгруппировать их по строке, полученной из поля [добавлено]. Допустим, его значение было 2011-05-24 03:32:57.353 , строка является 'Tuesday, May 24, 2011' . Я хочу сгруппировать записи по этой строке, но затем упорядочить дочерние узлы по фактическому времени. Я также хочу немного пользовательского вывода XML.

 <ActivityHistory>
   <Actvities foo="Tuesday, May 24, 2011">
       <Activity id="10000" bar="zoo" bam="2011-05-24 03:32:57.353" />
       <Activity id="10001" bar="zoo" bam="2011-05-24 03:31:57.353" />
       <Activity id="10002" bar="zoo" bam="2011-05-24 03:28:57.353" />
       <Activity id="10003" bar="zoo" bam="2011-05-24 03:21:57.353" />
   </Activities>
   <Actvities foo="Monday, May 23, 2011">
       <Activity id="9990" bar="zoo" bam="2011-05-23 03:32:57.353" />
       <Activity id="9989" bar="zoo" bam="2011-05-23 03:31:57.353" />
       <Activity id="9988" bar="zoo" bam="2011-05-23 03:28:57.353" />
       <Activity id="9987" bar="zoo" bam="2011-05-23 03:21:57.353" />
   </Activities>
   <Actvities foo="Sunday, May 22, 2011">
       <Activity id="9900" bar="zoo" bam="2011-05-22 03:32:57.353" />
       <Activity id="9899" bar="zoo" bam="2011-05-22 03:31:57.353" />
       <Activity id="9898" bar="zoo" bam="2011-05-22 03:28:57.353" />
       <Activity id="9897" bar="zoo" bam="2011-05-22 03:21:57.353" />
   </Activities>
</ActivityHistory>
  

Эта полезная нагрузка всегда будет содержать только 0-20 записей. Скорее всего, это всегда будет 20.

Пока мой запрос выглядит следующим образом.

     SELECT TOP 20
     fnHistoryGroupingText(Added) [@foo]        
    FROM ActivityHistory 
WHERE MricId = 1
GROUP BY fnHistoryGroupingText(Added)
FOR XML PATH ('Activities'), ROOT ('ActivityHistory')
  

Он выдает XML, аналогичный тому, что я ищу.

 <ActivityHistory>
   <Activities foo="Friday, May 20, 2011" />
   <Activities foo="Monday, May 23, 2011" />
   <Activities foo="Saturday, May 21, 2011" />
   <Activities foo="Sunday, May 22, 2011" />
   <Activities foo="Tuesday, May 24, 2011" />
</ActivityHistory>
  

Обратите внимание, что это не отсортировано по дате и отсутствие дочерних узлов. Я бы хотел, чтобы они были отсортированы в обратном хронологическом порядке. Я намеренно исключил некоторые поля из запроса, поскольку на этом этапе запроса я как бы получаю структуру, которую я в конечном итоге хочу. Когда я представляю другие поля, XML-это далеко не так. Группирующий текст — это переменный символ, который плохо скрывает дату. Я могу каким-то образом использовать поле [добавлено], но когда я включаю его в запрос, это нарушает мою группировку. Кто-нибудь может указать мне правильное направление для исправления этих проблем? [A] Правильно напишите запрос и [B] Покажите мне, как правильно вывести XML, который я ищу.

Ответ №1:

Попробуйте это:

 /*  INIT  */
DECLARE @ActivityHistory TABLE (id int, bar VARCHAR(3), bam datetime)
INSERT INTO @ActivityHistory 
             SELECT  id='10000', bar='zoo', bam='2011-05-24 03:32:57' 
       UNION SELECT  id='10001', bar='zoo', bam='2011-05-24 03:31:57' 
       UNION SELECT  id='10002', bar='zoo', bam='2011-05-24 03:28:57' 
       UNION SELECT  id='10003', bar='zoo', bam='2011-05-24 03:21:57' 
       UNION SELECT  id= '9990', bar='zoo', bam='2011-05-23 03:32:57' 
       UNION SELECT  id= '9989', bar='zoo', bam='2011-05-23 03:31:57' 
       UNION SELECT  id= '9988', bar='zoo', bam='2011-05-23 03:28:57' 
       UNION SELECT  id= '9987', bar='zoo', bam='2011-05-23 03:21:57' 
       UNION SELECT  id= '9900', bar='zoo', bam='2011-05-22 03:32:57' 
       UNION SELECT  id= '9899', bar='zoo', bam='2011-05-22 03:31:57' 
       UNION SELECT  id= '9898', bar='zoo', bam='2011-05-22 03:28:57' 
       UNION SELECT  id= '9897', bar='zoo', bam='2011-05-22 03:21:57' 

/*  QUERY  */
;WITH 
resALL AS ( SELECT *
      , foo = DATENAME(weekday, bam) ', '  CONVERT(VARCHAR(30), bam, 107) 
      , food = CONVERT(VARCHAR(10), bam, 121) 
    FROM @ActivityHistory AS Activity
  )
, resD AS ( SELECT DISTINCT foo, food FROM resALL 
  )

SELECT 
 Activities.foo
 , (
    SELECT id, bar, bam 
    FROM resALL AS Activity 
    WHERE foo = Activities.foo 
    ORDER BY bam desc 
    FOR XML AUTO, TYPE
   )
FROM resD AS Activities
ORDER BY Activities.food DESC
FOR XML AUTO, TYPE, ROOT ('ActivityHistory')

/*  OUTPUT
<ActivityHistory>
  <Activities foo="Tuesday, May 24, 2011">
    <Activity id="10000" bar="zoo" bam="2011-05-24T03:32:57" />
    <Activity id="10001" bar="zoo" bam="2011-05-24T03:31:57" />
    <Activity id="10002" bar="zoo" bam="2011-05-24T03:28:57" />
    <Activity id="10003" bar="zoo" bam="2011-05-24T03:21:57" />
  </Activities>
  <Activities foo="Monday, May 23, 2011">
    <Activity id="9990" bar="zoo" bam="2011-05-23T03:32:57" />
    <Activity id="9989" bar="zoo" bam="2011-05-23T03:31:57" />
    <Activity id="9988" bar="zoo" bam="2011-05-23T03:28:57" />
    <Activity id="9987" bar="zoo" bam="2011-05-23T03:21:57" />
  </Activities>
  <Activities foo="Sunday, May 22, 2011">
    <Activity id="9900" bar="zoo" bam="2011-05-22T03:32:57" />
    <Activity id="9899" bar="zoo" bam="2011-05-22T03:31:57" />
    <Activity id="9898" bar="zoo" bam="2011-05-22T03:28:57" />
    <Activity id="9897" bar="zoo" bam="2011-05-22T03:21:57" />
  </Activities>
</ActivityHistory>
*/
  

Комментарии:

1. Я пошел публиковать решение и увидел, что ваше решение практически такое же. для вас.

2. Замечательно!! Работает идеально. У меня вопрос, является ли ResD вторым распространенным табличным выражением? Я вижу, что начинается повторная отправка; С ПОМОЩЬЮ xxx as (), затем ставится запятая, и определяется ResD. Это правильно? Большое спасибо за отличное решение. Я был уверен, ЧТО XML PATH — это правильный путь.

3. @Hcabnettek: да, resD это второй CTE, и да, это правильный синтаксис для определения нескольких CTE.