TSQL Sum by group for monthly reports

僤鯓⒐⒋嵵緔 提交于 2019-12-07 23:17:13

问题


I'm in the process of trying to produce a report (monthly, year to date, etc) on a group of shipping entries in our database to show correct sums as well as group them by shipping company. How can I accomplish taking all this information and produce proper reports?

One thing to note is that all of the entries in this table are nvarchar(max) due to text importing with odd characters from various sources.

The master database list looks something like this:

table - shipping_info

shipping_company | ship_date | shipping_category | shipping_cost

UPS              | 20130301  |  CD'S             |  3.50
UPS              | 20130310  |  Records          |  4.50
UPS              | 20130322  |  CD'S             |  7.50
UPS              | 20130313  |  Tapes            |  12.44
UPS              | 20130324  |  CD'S             |  3.50
UPS              | 20120312  |  Records          |  4.50
UPS              | 20120304  |  CD'S             |  5.50
UPS              | 20120306  |  Tapes            |  3.50
UPS              | 20130309  |  CD'S             |  3.50
USPS             | 20130301  |  Tapes            |  3.50
USPS             | 20130301  |  CD'S             |  5.50
USPS             | 20130301  |  CD'S             |  4.50
USPS             | 20130201  |  Tapes            |  3.50
USPS             | 20130201  |  CD'S             |  3.50
USPS             | 20130201  |  Records          |  7.50
USPS             | 20130201  |  Tapes            |  9.50
USPS             | 20130201  |  CD'S             |  12.50
USPS             | 20120301  |  CD'S             |  14.50
USPS             | 20120301  |  Records          |  3.50
USPS             | 20130301  |  CD'S             |  23.50
USPS             | 20120301  |  Tapes            |  15.50
USPS             | 20120301  |  CD'S             |  34.50
DHL              | 20120301  |  Tapes            |  35.50
DHL              | 20120301  |  CD'S             |  3.50
DHL              | 20130301  |  Tapes            |  3.50
DHL              | 20130401  |  CD'S             |  3.50
DHL              | 20130401  |  Records          |  4.50
DHL              | 20130501  |  CD'S             |  4.50
DHL              | 20120201  |  Tapes            |  5.50
DHL              | 20120101  |  CD'S             |  6.50
DHL              | 20120501  |  CD'S             |  3.50
DHL              | 20120301  |  Tapes            |  7.50

My Goal is to get a final list that will print a filtered list by shipping_company of total shipping costs per month. Down the line I'd like to get a list of year to date and things like that. Anyways, what I'd like to see happen for the monthy reports is something like this:

UPS Shipping Cost Report for March 2013

CD's - $23.50
Records - $9.00
Tapes - $15.94

What I've tried is first

SELECT shipping_company, ship_date, shipping_category, shipping_cost FROM shipping_info WHERE (shipping_company = 'UPS' and shipping_cost IS NOT NULL and shipping_cost != '')  GROUP BY shipping_company, ship_date, shipping_category, shipping_cost ORDER BY shipping_company, ship_date, shipping_category, shipping_cost 

This produced a great filtered table but I still needed to figure out sums and group the totals together by category.

I then tried this....

SELECT shipping_company, ship_date, shipping_category, SUM(shipping_cost) FROM shipping_info WHERE (shipping_company = 'UPS' and shipping_cost IS NOT NULL and shipping_cost != '')  GROUP BY shipping_company, ship_date, shipping_category, shipping_cost ORDER BY shipping_company, ship_date, shipping_category, shipping_cost 

Since this is an NVARCHAR(MAX) table the t-sql crapped out with an error telling me I need to convert the shipping_cost into int.

So....I next tried this.

SELECT shipping_company, ship_date, shipping_category, convert(decimal(10, 2), shipping_cost) FROM shipping_info WHERE (shipping_company = 'UPS' and shipping_cost IS NOT NULL and shipping_cost != '')  GROUP BY shipping_company, ship_date, shipping_category, shipping_cost ORDER BY shipping_company, ship_date, shipping_category, shipping_cost 

Which kind of worked and kind of didn't.

Right now I'm stumped as to which direction from the first example to proceed when it comes to breaking down this list into reportable segments. Am I on the right path to get my information into the monthly report format that I need?

::EDIT/UPDATE::

This is great and it's working. I spent time going through each individual step of this code and I now understand the theory behind what's going on here. There's one final thing I'm sturggling with here. Since this table is NVARCHAR(MAX) I'm having a challenge trying to get the ship_date to convert to numeric with no success.

I took the original code below - EXAMPLE 1:

select  
CASE WHEN (GROUPING(shipping_company) = 1) THEN 'TOTAL'
            ELSE shipping_company END AS shipping_company,
CASE WHEN (GROUPING(SUBSTRING(ship_date, 1, 6)) = 1) THEN 'TOTAL'
            ELSE SUBSTRING(ship_date, 1, 6) END AS Date,
CASE WHEN (GROUPING(shipping_category) = 1) THEN 'Yearly TOTAL'
            ELSE shipping_category END AS shipping_category,
sum(convert(decimal(10,2),shipping_cost))
from tbl
group by shipping_company, SUBSTRING(ship_date, 1, 6), 
shipping_category WITH rollup

And then added numeric convert commands as noted below - EXAMPLE 2:

select  
CASE WHEN (GROUPING(shipping_company) = 1) THEN 'TOTAL'
            ELSE shipping_company END AS shipping_company,
CASE WHEN (GROUPING(CONVERT(numeric, (SUBSTRING(ship_date, 1, 6))) = 1) THEN 'TOTAL'
            ELSE (CONVERT(numeric, SUBSTRING(ship_date, 1, 6))) END AS Date,
CASE WHEN (GROUPING(shipping_category) = 1) THEN 'Yearly TOTAL'
            ELSE shipping_category END AS shipping_category,
sum(convert(decimal(10,2),shipping_cost))
from tbl
group by shipping_company, (CONVERT(numeric, SUBSTRING(ship_date, 1, 6))), 
shipping_category WITH rollup

But still got convert nvarchar to numeric errors. I then moved things around like so - EXAMPLE 3:

select  
CASE WHEN (GROUPING(shipping_company) = 1) THEN 'TOTAL'
            ELSE shipping_company END AS shipping_company,
CASE WHEN (CONVERT(numeric, GROUPING(SUBSTRING(ship_date, 1, 6))) = 1) THEN 'TOTAL'
            ELSE (CONVERT(numeric, SUBSTRING(ship_date, 1, 6))) END AS Date,
CASE WHEN (GROUPING(shipping_category) = 1) THEN 'Yearly TOTAL'
            ELSE shipping_category END AS shipping_category,
sum(convert(decimal(10,2),shipping_cost))
from tbl
group by shipping_company, (CONVERT(numeric, SUBSTRING(ship_date, 1, 6))), 
shipping_category WITH rollup

and got 'Argument 1 of the Grouping function does not match any expressions in the GROUP BY clause' which makes sense. I really would like to learn the theory behind not only why the second example doesn't work but what the right course of action would be to make the conversions work.


回答1:


Try this query

I have extracted year and month part from the date so grouping happens for every month of particular year.

select 
   shipping_company, 
   SUBSTRING(ship_date, 1, 6), 
   shipping_category, 
   sum(convert(decimal(10,2),shipping_cost))
from 
   tbl
group by 
   shipping_company, 
   SUBSTRING(ship_date, 1, 6), 
   shipping_category

SQL FIDDLE:

| SHIPPING_COMPANY | COLUMN_1 | SHIPPING_CATEGORY | COLUMN_3 |
--------------------------------------------------------------
|              DHL |   201201 |              CD'S |      6.5 |
|              DHL |   201202 |              CD'S |      5.5 |
|              DHL |   201203 |              CD'S |     46.5 |
|              DHL |   201205 |              CD'S |      3.5 |
|              DHL |   201303 |              CD'S |      3.5 |
|              DHL |   201304 |              CD'S |        8 |
|              DHL |   201305 |              CD'S |      4.5 |
|              UPS |   201203 |              CD'S |      5.5 |
|              UPS |   201203 |           Records |      4.5 |
|              UPS |   201203 |             Tapes |      3.5 |
|              UPS |   201303 |              CD'S |       18 |
|              UPS |   201303 |           Records |      4.5 |
|              UPS |   201303 |             Tapes |    12.44 |
|             USPS |   201203 |              CD'S |       68 |
|             USPS |   201302 |              CD'S |     36.5 |
|             USPS |   201303 |              CD'S |       37 |

If you want yearly total then you can use WITH ROLLUP.

NOTE Consider yearly total as Monthly total...

Query 1:

select  
CASE WHEN (GROUPING(shipping_company) = 1) THEN 'TOTAL'
            ELSE shipping_company END AS shipping_company,
CASE WHEN (GROUPING(SUBSTRING(ship_date, 1, 6)) = 1) THEN 'TOTAL'
            ELSE SUBSTRING(ship_date, 1, 6) END AS Date,
CASE WHEN (GROUPING(shipping_category) = 1) THEN 'Yearly TOTAL'
            ELSE shipping_category END AS shipping_category,
sum(convert(decimal(10,2),shipping_cost))
from tbl
group by shipping_company, SUBSTRING(ship_date, 1, 6), 
shipping_category WITH rollup

SQL FIDDLE:

| SHIPPING_COMPANY |   DATE | SHIPPING_CATEGORY | COLUMN_3 |
------------------------------------------------------------
|              DHL | 201201 |              CD'S |      6.5 |
|              DHL | 201201 |      Yearly TOTAL |      6.5 |
|              DHL | 201202 |              CD'S |      5.5 |
|              DHL | 201202 |      Yearly TOTAL |      5.5 |
|              DHL | 201203 |              CD'S |     46.5 |
|              DHL | 201203 |      Yearly TOTAL |     46.5 |
|              DHL | 201205 |              CD'S |      3.5 |
|              DHL | 201205 |      Yearly TOTAL |      3.5 |
|              DHL | 201303 |              CD'S |      3.5 |
|              DHL | 201303 |      Yearly TOTAL |      3.5 |
|              DHL | 201304 |              CD'S |        8 |
|              DHL | 201304 |      Yearly TOTAL |        8 |
|              DHL | 201305 |              CD'S |      4.5 |
|              DHL | 201305 |      Yearly TOTAL |      4.5 |
|              DHL |  TOTAL |      Yearly TOTAL |       78 |
|              UPS | 201203 |              CD'S |      5.5 |
|              UPS | 201203 |           Records |      4.5 |
|              UPS | 201203 |             Tapes |      3.5 |
|              UPS | 201203 |      Yearly TOTAL |     13.5 |
|              UPS | 201303 |              CD'S |       18 |
|              UPS | 201303 |           Records |      4.5 |
|              UPS | 201303 |             Tapes |    12.44 |
|              UPS | 201303 |      Yearly TOTAL |    34.94 |
|              UPS |  TOTAL |      Yearly TOTAL |    48.44 |
|             USPS | 201203 |              CD'S |       68 |
|             USPS | 201203 |      Yearly TOTAL |       68 |
|             USPS | 201302 |              CD'S |     36.5 |
|             USPS | 201302 |      Yearly TOTAL |     36.5 |
|             USPS | 201303 |              CD'S |       37 |
|             USPS | 201303 |      Yearly TOTAL |       37 |
|             USPS |  TOTAL |      Yearly TOTAL |    141.5 |
|            TOTAL |  TOTAL |      Yearly TOTAL |   267.94 |

EDIT

Ok got your problem in your updated queries. Both the cases of If statement should return same datatype of result so when you are trying to cast the date values back to numeric your true case returns varchar datatype field which is TOTAL and the else field returns a numeric type field so this causes the error.

To solve it you need to remove the case statement then it would work properly as per your need.

select  
CASE WHEN (GROUPING(shipping_company) = 1) THEN 'TOTAL'
            ELSE shipping_company END AS shipping_company,
CONVERT(numeric, (SUBSTRING(ship_date, 1, 6))) AS Date,
CASE WHEN (GROUPING(shipping_category) = 1) THEN 'Yearly TOTAL'
            ELSE shipping_category END AS shipping_category,
sum(convert(decimal(10,2),shipping_cost))
from tbl
group by shipping_company, (CONVERT(numeric, SUBSTRING(ship_date, 1, 6))), 
shipping_category WITH rollup

SQL FIDDLE:

| SHIPPING_COMPANY |   DATE | SHIPPING_CATEGORY | COLUMN_3 |
------------------------------------------------------------
|              DHL | 201201 |              CD'S |      6.5 |
|              DHL | 201201 |      Yearly TOTAL |      6.5 |
|              DHL | 201202 |              CD'S |      5.5 |
|              DHL | 201202 |      Yearly TOTAL |      5.5 |
|              DHL | 201203 |              CD'S |     46.5 |
|              DHL | 201203 |      Yearly TOTAL |     46.5 |
|              DHL | 201205 |              CD'S |      3.5 |
|              DHL | 201205 |      Yearly TOTAL |      3.5 |
|              DHL | 201303 |              CD'S |      3.5 |
|              DHL | 201303 |      Yearly TOTAL |      3.5 |
|              DHL | 201304 |              CD'S |        8 |
|              DHL | 201304 |      Yearly TOTAL |        8 |
|              DHL | 201305 |              CD'S |      4.5 |
|              DHL | 201305 |      Yearly TOTAL |      4.5 |
|              DHL | (null) |      Yearly TOTAL |       78 |
|              UPS | 201203 |              CD'S |      5.5 |
|              UPS | 201203 |           Records |      4.5 |
|              UPS | 201203 |             Tapes |      3.5 |
|              UPS | 201203 |      Yearly TOTAL |     13.5 |
|              UPS | 201303 |              CD'S |       18 |
|              UPS | 201303 |           Records |      4.5 |
|              UPS | 201303 |             Tapes |    12.44 |
|              UPS | 201303 |      Yearly TOTAL |    34.94 |
|              UPS | (null) |      Yearly TOTAL |    48.44 |
|             USPS | 201203 |              CD'S |       68 |
|             USPS | 201203 |      Yearly TOTAL |       68 |
|             USPS | 201302 |              CD'S |     36.5 |
|             USPS | 201302 |      Yearly TOTAL |     36.5 |
|             USPS | 201303 |              CD'S |       37 |
|             USPS | 201303 |      Yearly TOTAL |       37 |
|             USPS | (null) |      Yearly TOTAL |    141.5 |
|            TOTAL | (null) |      Yearly TOTAL |   267.94 |

So now you have to bear with null values in the date columns. Hope this answers your doubts.

Hope this helps......



来源:https://stackoverflow.com/questions/16454370/tsql-sum-by-group-for-monthly-reports

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!