Domanda

Quick question about summary data:

I have the below code which will pull sales information and put it into a month/year grid, which is terrific (http://sqlfiddle.com/#!3/9d79e/1):

WITH 
months AS (SELECT 1 AS mon UNION ALL SELECT mon + 1 FROM months WHERE mon < 12),
years AS (SELECT 2011 AS yr UNION ALL SELECT yr + 1 FROM years WHERE yr < 2015),
invoices AS (
SELECT CAST('2013-06-27' AS date) AS InvoiceDate, 40 AS MarginAmount
UNION 
SELECT CAST('2013-07-29' AS date) AS InvoiceDate, 40 AS MarginAmount
UNION 
SELECT CAST('2013-10-30' AS date) AS InvoiceDate, 40 AS MarginAmount
)

-- End data setup, real work begins here
SELECT * FROM
(
SELECT 
months.mon, years.yr, COALESCE(SUM(inv.MarginAmount), 0) AS MarginAmount
FROM 
months
CROSS JOIN years 
LEFT OUTER JOIN invoices inv ON ( (YEAR(inv.InvoiceDate) = years.yr) AND   (MONTH(inv.InvoiceDate) = months.mon) )
GROUP BY 
months.mon, years.yr 
) AS source 
PIVOT
(
MAX(MarginAmount)
FOR yr in ([2011], [2012], [2013], [2014], [2015])
)
AS pvt  
ORDER BY mon

I was wondering how I could change two things:

Replace the numbers 1 - 11 with the names of the months of the year and

Create a line at the bottom of the table summarizing the information above it, where the mon column would have the word 'Total'

Any help would be greatly appreciated

e.g The sum of all sales in 2012 would be displayed at the bottom of the 2012 column

È stato utile?

Soluzione

Question 1. Replace numbers

To replace the numbers, you can for instance change this:

months AS (SELECT 1 AS mon UNION ALL SELECT mon + 1 FROM months WHERE mon < 12)

to

months AS (SELECT 1 AS mon, 'Jan' name UNION ALL SELECT mon + 1, months.name FROM months WHERE mon < 12)

Question 2. Grand totals

To create a bottom line with totals you can either use grouping sets (your query seems to be SQL Server, don't know whether SQL Server supports that, please specify):

group
by    grouping sets
      ( ()
      , (full list)
      )

or add a union to the query:

with myresults as (the whole thing)
select 1 ordering
,      myresults.columns-minus-total
,      myresults.something subtotal
from   myresults
union all
select 2 ordering
,      myresults.columns-minus-total
,      sum(something) grandtotal
from   myresults
order
by     1
,      ...other...

Complete example using Microsoft SQL Server 2008 R2

Original code was prettified and without dependencies on tables:

with months as 
( select 1 as mon 
  ,      'Jan' monname
  union all 
  select 2
  ,      'Feb'
  union all 
  select 3
  ,      'Mar'
  union all 
  select 4
  ,      'Apr'
  union all 
  select 5
  ,      'May'
  union all 
  select 6
  ,      'Jun'
  union all 
  select 7
  ,      'Jul'
  union all 
  select 8
  ,      'Aug'
  union all 
  select 9
  ,      'Sep'
  union all 
  select 10
  ,      'Oct'
  union all 
  select 11
  ,      'Nov'
  union all 
  select 12
  ,      'Dec'
)
, years as 
  ( select 2011 as yr 
    union all 
    select 2012 
    union all 
    select 2013
    union all 
    select 2014
  )
, invoices as 
  ( select cast('2013-06-27' as date) as invoicedate
    ,      40 as marginamount
    union 
    select cast('2013-07-29' as date) as invoicedate
    ,      40 as marginamount
    union 
    select cast('2013-10-30' as date) as invoicedate
    ,      40 as marginamount
  )
select * 
from   ( select months.mon
         ,      years.yr
         ,      coalesce(sum(inv.marginamount), 0) as marginamount
         from   months
         cross 
         join   years 
         left 
         outer 
         join   invoices inv 
         on     year(inv.invoicedate)  = years.yr
         and    month(inv.invoicedate) = months.mon
         group 
         by     months.mon
         ,      years.yr 
       ) source 
pivot  ( max(marginamount)
         for yr 
         in  ( [2011], [2012], [2013], [2014], [2015]
             )
       ) pvt  
order 
by     mon

Adding the text and grand totals leads to:

with months as 
( select 1 as mon 
  ,      'Jan' monname
  union all 
  select 2
  ,      'Feb'
  union all 
  select 3
  ,      'Mar'
  union all 
  select 4
  ,      'Apr'
  union all 
  select 5
  ,      'May'
  union all 
  select 6
  ,      'Jun'
  union all 
  select 7
  ,      'Jul'
  union all 
  select 8
  ,      'Aug'
  union all 
  select 9
  ,      'Sep'
  union all 
  select 10
  ,      'Oct'
  union all 
  select 11
  ,      'Nov'
  union all 
  select 12
  ,      'Dec'
)
, years as 
  ( select 2011 as yr 
    union all 
    select 2012 
    union all 
    select 2013
    union all 
    select 2014
  )
, invoices as 
  ( select cast('2013-06-27' as date) as invoicedate
    ,      40 as marginamount
    union 
    select cast('2013-07-29' as date) as invoicedate
    ,      40 as marginamount
    union 
    select cast('2013-10-30' as date) as invoicedate
    ,      40 as marginamount
  )
select case
       when mon is null
       then 'Total'
       else cast(mon as varchar)
       end
,      monname
,      [2011]
,      [2012]
,      [2013]
,      [2014]
,      [2015]
from   ( select months.mon
         ,      months.monname
         ,      years.yr
         ,      coalesce(sum(inv.marginamount), 0) as marginamount
         from   months
         cross 
         join   years 
         left 
         outer 
         join   invoices inv 
         on     year(inv.invoicedate)  = years.yr
         and    month(inv.invoicedate) = months.mon
         group
         by     grouping sets
                ( (months.mon, months.monname, years.yr)
                , (years.yr)
                )
       ) source 
pivot  ( max(marginamount)
         for yr 
         in  ( [2011], [2012], [2013], [2014], [2015]
             )
       ) pvt  
order 
by     coalesce(mon, 100)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top