How to Use a Window Aggregate in an Aggregate Query

A window aggregate function is an easy way to perform an aggregate calculation without changing the query to an aggregate query. This means that you can calculate an aggregate over the entire dataset while keeping the detail in the results. You can also perform calculations on smaller windows, or partitions, of the data. Here is a query that provides an overall total, a total for each customer, and the average sale for each customer. Even though the query is returning sums and an average, the detail remains in the results.

SELECT CustomerID, TotalDue, SalesOrderID, SUM(TotalDue) OVER() AS GrandTotal,
SUM(TotalDue) OVER(PARTITION BY CustomerID) AS CustTotal,
AVG(TotalDue) OVER(PARTITION BY CustomerID) AS CustAvg
FROM Sales.SalesOrderHeader;

agag1

You can also use windows aggregate functions within aggregate queries with some caveats. When I first began using these functions back in the SQL Server 2005 days, I had mixed success with this technique. That was long before I began focusing on window functions in my writing and speaking. I have learned a lot since then.

Let’s start with an aggregate query grouped at the customer level.

SELECT CustomerID, SUM(TotalDue) AS CustTotal,AVG(TotalDue) AS CustAvg
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

agag2

 

Let’s say I wanted to add a grand total by adding this to the query: SUM(TotalDue) OVER() AS GrandTotal.

SELECT CustomerID, SUM(TotalDue) AS CustTotal,
AVG(TotalDue) AS CustAvg,
SUM(TotalDue) OVER() AS GrandTotal
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

Unfortunately, this doesn’t work. I see this error message:

agag3

This seems really strange since TotalDue is part of an aggregate function. The problem is that the window aggregate function must operate either on a column in the GROUP BY clause or on an aggregate expression. I can’t add TotalDue to the GROUP BY because that will change the results I expect, but I can operate on the sum of TotalDue:

SELECT CustomerID, SUM(TotalDue) AS CustTotal,
AVG(TotalDue) AS CustAvg,
SUM(SUM(TotalDue)) OVER() AS GrandTotal
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

agag4

It is also not possible to add a PARTITION BY option on a non-grouping column or non-aggregated column. Let’s say I want to get a total for each order year and try this:

SELECT CustomerID, SUM(TotalDue) AS CustTotal,
AVG(TotalDue) AS CustAvg,
SUM(SUM(TotalDue)) OVER() AS GrandTotal,
SUM(SUM(TotalDue))
OVER(PARTITION BY YEAR(OrderDate)) AS YearTotal
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

agag5

At this point, I can go back to a non-aggregate query and use all window functions to actually get the results I am looking for.

SELECT CustomerID, YEAR(OrderDate) AS OrderYear,
SUM(TotalDue) OVER(PARTITION BY CustomerID) AS CustTotal,
AVG(TotalDue) OVER(PARTITION BY CustomerID) AS CustAvg,
SUM(TotalDue) OVER() AS GrandTotal,
SUM(TotalDue) OVER(PARTITION BY YEAR(OrderDate)) AS YearTotal
FROM Sales.SalesOrderHeader;

agag6

So, how can you tell when adding a window aggregate function to an aggregate query will work? Well, think about how the window function works. SQL Server will create a work table of each partition and perform the calculation on the work table. It can only work with what is available in the result set.

If my query is a non-aggregate query, then the window will contain all the columns and the window aggregate function can work with any of the columns in the table depending on data type. If the query is an aggregate query, then the window function can only work on what could normally be listed in the SELECT list. That means that the window function can operate on any of the grouping columns or on an aggregate function.

Window aggregate functions are extremely useful. They make some queries very easy to write and maintain.

Posted in T-SQL, T-SQL Window Functions | Leave a comment

What I Wish I Knew Sooner

Mike Walsh tagged me in his post 4 Attitudes I Wish I Had Earlier as a DBA.

When I look back over my career in IT, I think I have done pretty well. The opportunities and people I needed to meet just seemed to be there for me when I needed them. I often joke that my life is kind of magic. I suppose that it really isn’t magic, and actually networking, hard work, and goal setting are the reasons for my success.

What are some things I have learned? One thing I learned even before working in IT is the importance of customer service.  I learned that my customer might be my coworker, my manager, someone in another department, or a client who has engaged my services. This means that I will communicate the progress of the project, either through scrum meetings, emails, or even stopping by my customer’s desk to chat. I will make sure that I understand their requirements and do my best work. I won’t promise things that I can’t deliver, but I will always deliver more than I promise.  I understand that I am being paid a very nice wage to do my job, and my customer is going to get their money’s worth.

One thing that I am struggling with is how to handle criticism. When you put yourself out there as a speaker, writer, or trainer, you get a lot of it! For example, I gave a webinar presentation a couple of months ago with over 500 people attending. Not everyone put in comments, but most of the comments received were very positive, either asking a question or stating how much they liked the presentation. One person, though, wrote two paragraphs saying how terrible the presentation was. He didn’t really say what I could do better, just complaints. Was this guy having a bad day? Was he right and everyone else wrong? I still don’t know what to think or how to handle this. I think I am making positive contributions to the community, but maybe I am not.

Another area that many of us struggle with is saying “no” and knowing our limits. I think I am doing a pretty good job with this, and end up saying no to opportunities quite often. For example, I am not going to take on a big side project when I am in the middle of writing a book, and I can’t go to every SQL Saturday even when the organizers personally reach out to me. I still find myself overbooked from time to time and sometimes end up a bit overwhelmed.  Going forward, I’ll be working part time, so I will be able to take on more of the projects that I have turned down in the past.

One thing I realized last year is to not turn down opportunities for fun even if they seem expensive. Last year, I didn’t take a week long vacation, but I took several mini-trips. For the most part, I thought of the trip and just decided right then to do it and started making plans. Some of the trips were expensive, but I realized that I will make more money. In IT we work really, really hard and sometimes long hours. We must have some fun once in awhile with our families and friends. It’s easy to get burned out. My kids are grown up, so they are more like friends to me now, but I also have four grandchildren. I make sure that I spend lots of time playing with them. They are small for such a short time.

The things that I have learned and wish I knew earlier:

  • Provide stellar customer service
  • Don’t dwell on unfair criticism
  • Know my limits
  • Have some fun

 

 

 

 

 

Posted in Life in IT | 7 Comments

Taking a new direction

Bifurcation in a Country roadTwo and a half years ago I made a very smart decision and joined Pragmatic Works. PW is a wonderful company made up of talented, passionate people. The founder of the company, Brian Knight (@brianknight), helped me get to where I am today, even before I actually worked for him. He is one of the original founders of SQL Server Central where I published my first article almost 10 years ago. He gave me my first big break, recruiting me to contribute two chapters to the first SSIS book ever published.  I had never imagined that I would get to be a book author, and my life has not been the same since. Not only was Brian one of the founders of SSC, he was also one of the early board members of PASS.  Brian can take a big share of the credit for the vibrant community we enjoy today.  PW reflects the way Brian lives his life: work really hard, but have lots of fun, and always give back.

For over 5 years, I have had a dream. My dream is to work as an independent consultant part time, but to also spend time teaching and writing. This dream also includes lots of time for playing (I have four grandchildren!) and vacations. Once this plan was in place, I figured I could gradually work less and less over time and ease on into retirement. Six months ago, if you had asked me, I would have said that I was going to actually fulfill this dream within the next 5 years. I guess it was my “five year plan.”

A couple of months ago several things starting falling into place and it seemed like it was now the right time to realize this dream. Beginning Sept. 2nd, I will be working as an independent consultant associated with Linchpin People. The consultants at Linchpin have a lot in common with those at PW. They also work hard, have fun, and always give back. I will continue to remember my days at PW fondly. I worked with some fantastic people there.

So, if there is anything that you think I can do for you, such as speaking at your user group, teaching a class for your company, or anything SQL Server related, please fill out the contact form.  If I can’t help you, I’ll forward the request on to someone at Linchpin People or Pragmatic Works who can.

 

 

 

 

 

 

Posted in Life in IT | 9 Comments