Search code examples
sqlsql-serverxmlsql-server-2008for-xml

SQL Server 2008 FOR XML PATH help


I have a table of history records. One field [added] has a datetime data type. What I'm trying to do is select a users 20 most recent records, but then group them by a string derived from the [added] field. Say its value was 2011-05-24 03:32:57.353, the string is 'Tuesday, May 24, 2011'. I want to group the records by that string, but then order the child nodes by the actual time. I also want a bit of custom XML output.

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

This payload will always only have 0-20 records. Likely it will always be 20.

So far my query looks like this.

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

It produces XML similar to what I'm looking for.

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

Notice it is not date sorted and the lack of child nodes. I would like them sorted in reverse chronological order. I purposely excluded some fields from the query as at this point in the query I'm sort of getting the structure I ultimately want. When I introduce the other fields, the XML is way off. Grouping text is a varchar and doesn't covert nicely to a date. I can use the [added] field somehow, but when I include it in the query, it busts my grouping. Can anyone point me in the right direction to correct these problems? [A] Write the query correctly, and [B] Show me how to correctly output the XML I'm looking for.


Solution

  • Try this:

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