<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>GROUP BY</title>
        <link>http://weblogs.sqlteam.com/jeffs/category/254.aspx</link>
        <description>Grouping and summarizing data in SQL, using aggregate functions, etc.</description>
        <language>en-US</language>
        <copyright>Jeff Smith</copyright>
        <managingEditor>smith_jeffreyt@yahoo.com</managingEditor>
        <generator>Subtext Version 1.9.4.0</generator>
        <item>
            <title>GROUP BY ALL</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2008/05/05/group-by-all.aspx</link>
            <description>Here's an obscure piece of SQL you may not be aware of:  The "ALL" option when using a GROUP BY.&lt;br /&gt;
&lt;br /&gt;
Consider the following table:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;Create table Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    SaleID int identity not null primary key,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    CustomerID int,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    ProductID int,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    SaleDate datetime,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    Qty int,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    Amount money&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;insert into Sales (CustomerID, ProductID, SaleDate, Qty, Amount)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 1,1,'2008-01-01',12,400 union all&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 1,2,'2008-02-25',6,2300 union all&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 1,1,'2008-03-02',23,610 union all&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 2,4,'2008-01-04',1,75 union all&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 2,2,'2008-02-18',52,5200 union all&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 3,2,'2008-03-09',99,2300 union all&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 3,1,'2008-04-19',3,4890 union all&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 3,1,'2008-04-21',74,2840&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;SaleID      CustomerID  ProductID   SaleDate                Qty         Amount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- ----------- ----------- ----------------------- ----------- ---------------------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;9           1           1           2008-01-01 00:00:00.000 12          400.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;10          1           2           2008-02-25 00:00:00.000 6           2300.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;11          1           1           2008-03-02 00:00:00.000 23          610.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;12          2           4           2008-01-04 00:00:00.000 1           75.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;13          2           2           2008-02-18 00:00:00.000 52          5200.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;14          3           2           2008-03-09 00:00:00.000 99          2300.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;15          3           1           2008-04-19 00:00:00.000 3           4890.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;16          3           1           2008-04-21 00:00:00.000 74          2840.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(8 row(s) affected)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Suppose we'd like to see the customers that were sold Product #1 along with the total amount that they spent.&lt;br /&gt;
&lt;br /&gt;
We would basically write a simple SELECT with a GROUP BY like this:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select CustomerID, sum(Amount) as TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where ProductID = 1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by CustomerID&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
And sure enough, we'd get our answer:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;CustomerID  TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- ---------------------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           1010.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;3           7730.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(2 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Now, let's say that we'd like to see &lt;span style="font-style: italic;"&gt;all &lt;/span&gt;customers that have been sold &lt;span style="font-style: italic;"&gt;any &lt;/span&gt;products, but we still just want to see the "TotalAmount" for ProductID #1.  For customers that have never ordered ProductID #1, it should output a "TotalAmount" value of $0.   One way to do this is with a CASE expression; instead of filtering so that only ProductID #1 is returned, we can conditionally SUM() the Amount only for orders for ProductID #1.  Like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select CustomerID, &lt;span style="font-weight: bold;"&gt;sum(case when ProductID=1 then Amount else 0 end) as TotalAmount&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by CustomerID&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;CustomerID  TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- ---------------------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           1010.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           0.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;3           7730.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(3 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
That gives us the results we want.   Because we are not using a WHERE clause to filter the data, we see an entry for CustomerID #2 in the output.  &lt;br /&gt;
&lt;br /&gt;
However, in situations where you have written the above SQL, you could actually replace the SUM(CASE...) expression by using &lt;span style="font-weight: bold;"&gt;GROUP BY ALL&lt;/span&gt;, instead of just a standard GROUP BY, like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select CustomerID, sum(Amount) as TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where ProductID = 1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by &lt;span style="font-weight: bold;"&gt;all &lt;/span&gt;CustomerID&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;CustomerID  TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- ---------------------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           1010.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           NULL&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;3           7730.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;Warning: Null value is eliminated by an aggregate or other SET operation.&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(3 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Notice that now &lt;span style="font-style: italic;"&gt;all &lt;/span&gt;Customers are now returned, and a NULL is shown as the TotalAmount for Customer #2, who has no orders for ProductID #1 ...  Even though though the WHERE clause seems to indicate that we should &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; be seeing customer #2 in the results!&lt;br /&gt;
&lt;br /&gt;
The ALL option basically says "ignore the WHERE clause when doing the GROUPING, but still apply it for any aggregate functions".   So, in this case, the WHERE clause is not considered when generating the population of CustomerID values, but it is applied when calculating the SUM.  This is very much like our first solution, where we removed the WHERE clause completely, and used a SUM(CASE...) expression to conditionally calculate the aggregate.  &lt;br /&gt;
&lt;br /&gt;
Values that are excluded from the aggregation according to the WHERE clause have NULL values returned, as you can see in the result.  A simple ISNULL() or COALESCE() will allow us to return 0 instead of NULL:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select CustomerID, isnull(sum(Amount),0) as TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where ProductID = 1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by all CustomerID&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;CustomerID  TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- ---------------------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           1010.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           0.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;3           7730.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;Warning: Null value is eliminated by an aggregate or other SET operation.&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(3 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Notice that the warning about NULL being aggregated still displays, since that is the standard behavior in SQL Server when you calculate an aggregate on a NULL value.  You can turn these warnings off if you like for the during of the batch by issuing a &lt;span style="font-family: Courier New;"&gt;set ANSI_WARNINGS off &lt;/span&gt;command before your SELECT.&lt;br /&gt;
&lt;br /&gt;
GROUP BY ALL is kind of obscure and neat to know, but not really useful in most situations since there are usually easier or better ways to get this result.  For one thing, this won't work if we want all Customers to be displayed, since a customer &lt;span style="font-style: italic;"&gt;must have at least one order &lt;/span&gt;to show up in the result.  If we want to see all customers, even those that have never ordered, we would need to do a LEFT OUTER JOIN from the Customers table to our Orders aggregate SELECT:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;create table Customers (CustomerID int primary key)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;insert into Customers&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 1 union all &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 2 union all &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 3 union all &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 4&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;-- Notice that we have 4 customers, but our Sales data has sales for only 3.&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select c.customerID, isnull(s.TotalAmount,0) as TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from Customers c&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;left outer join &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    (select customerID, sum(Amount) as TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;     from Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;     where ProductID = 1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    group by customerID) s on c.customerID = s.customerID&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;customerID  TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- ---------------------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           1010.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           0.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;3           7730.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;4           0.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(4 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
That is typically the standard way to return data for an entire population, regardless of existing transactions.  GROUP BY ALL gets us close, but if a new customer has never made an Order, they will never show up in the results.   Of course, depending on your needs, that may be what you want.&lt;br /&gt;
&lt;br /&gt;
Another limitation is we can not use GROUP BY ALL if we want to return a grand total for all orders, along with the total just for ProductID #1.  For example, using the SUM(CASE...) expression along with a regular SUM(), we can do this:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select CustomerID, sum(case when ProductID=1 then Amount else 0 end) as Product1Amount,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    sum(Amount) as TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by CustomerID&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;CustomerID  Product1Amount        TotalAmount&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- --------------------- ---------------------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           1010.00               3310.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           0.00                  5275.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;3           7730.00               10030.00&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(3 row(s) affected)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
That lets us calculate two different totals all in one pass through the table.  However, we cannot translate that using GROUP BY ALL, because while we will be able to return the Product1Amount, there would be no easy way to also get the TotalAmount for all products without an additional join or sub-query.&lt;br /&gt;
&lt;br /&gt;
. . .&lt;br /&gt;
&lt;br /&gt;
So, that's the story with GROUP BY ALL. It is interesting, and not widely well-known, and may even make for a good interview question if you really want to see how much SQL a candidate knows.  But for practical purposes, it is pretty rarely used and there are generally better ways to get the same results more easily or more efficiently.&lt;br /&gt;
&lt;br /&gt;
Anyone have a good situation or an example of where GROUP BY ALL really worked well for you?  Be sure to share your experiences in the comments.&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60588.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2008/05/05/group-by-all.aspx</guid>
            <pubDate>Mon, 05 May 2008 16:25:24 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60588.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2008/05/05/group-by-all.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60588.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60588.aspx</trackback:ping>
        </item>
        <item>
            <title>Simplify Your SQL with Variables and Derived Tables (or Common Table Expressions)</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/12/20/simplify-sql-with-variables-and-derived-tables.aspx</link>
            <description>As with any programming language, it is important in SQL to keep your code short, clear and concise.   Here are two quick tips that I find are very helpful in obtaining this goal.  &lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Tip 1:  For any relatively complicated constant expression, always declare a variable&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Consider the following:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select *&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from Transactions&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where TranDate &amp;gt;= &lt;span style="font-style: italic;"&gt;{some long, complicated expression to determine the start date}&lt;/span&gt; and&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;      &lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;TranDate &lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;&amp;lt;  &lt;span style="font-style: italic;"&gt;{some long, complicated expression to determine the end date}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
      &lt;br /&gt;
This is one of the most common things that I see in the &lt;a target="_blank" href="http://www.sqlteam.com/forums"&gt;SQLTeam forums&lt;/a&gt;, from both the people asking questions and the people giving answers.  If the starting date and ending date range are &lt;span style="font-style: italic;"&gt;constants for the entire SELECT&lt;/span&gt; (i.e., they don't vary by row, they are based on the current date or some parameters passed to the stored procedure), then simply declare them as variables, set the values once, and reference those variables in your WHERE clause:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;declare @start datetime, @end datetime&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;set @start = &lt;span style="font-style: italic;"&gt;{some long, complicated expression to determine the start date}&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;set @end = &lt;span style="font-style: italic;"&gt;{some long, complicated expression to determine the end date}&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select * from Transactions&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where TranDate &amp;gt;= @start and TranDate &amp;lt; @end&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Now, you could argue that we just technically made the code longer.  But, we have made our code clearer and much easier to read and debug! We can now print and/or analyze the @start and @end dates to make sure that our formulas are working, without repeatedly running the entire SELECT over and over and glancing at the results and trying to determine if they "look right".  &lt;br /&gt;
&lt;br /&gt;
We can also potentially use these variables to make these formulas (or others) much simpler.   For example, if the end date is always one day later than the start date, we can write:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;declare @start datetime, @end datetime&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;set @start = &lt;/span&gt;&lt;span style="font-style: italic; font-family: Courier New;"&gt;{some long, complicated expression to determine the start date}&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;set @end = &lt;span style="font-weight: bold;"&gt;dateadd(day, 1, @start)&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select * from Transactions&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where TranDate &amp;gt;= @start and TranDate &amp;lt; @end&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
That is much, much easier to read, write and debug then if we repeated the long complicated expression twice, and it makes it very clear what the relationship is between the start date and the ending date.  If we need to tweak our starting date formula, we can do it in one place and again it is easier to debug since we can just print out the value of the variable. We also have the ability to name our variables intelligently to help with the readability of our code. &lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Tip 2: To avoid repeating non-constant expressions, use a Derived Table or a Common Table Expression (CTE)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Another common thing found in lots of SQL code is to repeat the non-constant expressions over and over.  For example, if we have a DateTime column called TranDate, this expression will round that date to the first day of the month:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;dateadd(m, datediff(m,0, TranDate),0)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
    &lt;br /&gt;
Using that knowledge, if we need to summarize transactions by month, the result often ends up looking something like this:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  dateadd(m, datediff(m,0, TranDate),0) as [Month], sum(value)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  table&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  dateadd(m, datediff(m,0, TranDate),0) &amp;gt;= @min and &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  dateadd(m, datediff(m,0, TranDate),0) &amp;lt;= @max&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;   dateadd(m, datediff(m,0, TranDate),0)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;order by&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;   dateadd(m, datediff(m,0, TranDate),0)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Notice that the date expression is repeated &lt;span style="font-style: italic;"&gt;five times &lt;/span&gt;in the SQL statement!   Looks kind of silly, but I see it over and over again from both beginner and experienced programmers alike.  The solution to simplifying this is to calculate the formula &lt;span style="font-style: italic;"&gt;once&lt;/span&gt; and assign it a meaningful alias&lt;span style="font-style: italic;"&gt; &lt;/span&gt;using a derived table:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  [Month], sum(value)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  (&lt;br /&gt;
   select &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;     dateadd(m, datediff(m,0, TranDate),0) as [Month], value&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;   from &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;     table&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  ) x&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    x.[Month] &amp;gt;= @min and x.[Month] &amp;lt;= @max&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    x.[Month]&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;order by&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    x.[Month]&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Now the SELECT is much easier to read and maintain, and we can access the result of the calculation in the outer SELECT as many times as we need by referencing the "month" column returned by the derived table.   Also, if our "month" formula is wrong, or needs tweaking or testing, it can all be done in one place and it doesn't need to be repeated over and over.  &lt;br /&gt;
&lt;br /&gt;
If you are using SQL Server version 2005 or greater, you can also use a Common Table Expression (CTE) in the same way.  In fact, in many ways CTEs are even more readable and easier to work with than derived tables since the code doesn't require as much nesting and is more linear.   Here's the previous example as a CTE:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;with MonthSummary as&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;   select&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;     dateadd(m, datediff(m,0, TranDate),0) as [Month], value&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;   from&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;     table&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  [Month], sum(value)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  MonthSummary&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  [Month] &amp;gt;= @min and [Month] &amp;lt;= @max&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  [Month]&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;order by&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  [Month]&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Repeating expressions is common for mathematical formulas as well, such as using CASE to avoid dreaded "divide by zero" errors when the denominator is an expression:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select &lt;br /&gt;
  c as Numerator, a+b as Denominator, &lt;br /&gt;
  case when a+b = 0 then null else c / (a+b) end as Result&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from &lt;br /&gt;
  tbl&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Notice that a+b is repeated &lt;span style="font-style: italic;"&gt;three times&lt;/span&gt; in the previous SELECT statement.  Again, using a derived table, we can easily change this to:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select &lt;br /&gt;
  Numerator, &lt;br /&gt;
  Denominator, &lt;br /&gt;
  case when Denominator = 0 the null else Numerator / Denominator end as Result&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  (&lt;br /&gt;
  select&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;     c as Numerator, a+b as Denominator&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  from&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;     tbl&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  ) x&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
... and once again, we can now clearly label our expression and see exactly what it is and our code is much clearer and easier to maintain.  This example is quite simple and the difference doesn't seem like much, but if that expression is long and complicated and used in other places as well, the improvement in the code can be tremendous.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
It is not just readability that we are concerned with, it is also eliminating and finding bugs and optimizing code.  Repeating expressions in more than one place, or embedding them deep into SQL statements where we can never really be sure they are working, can result in bugs that are tough to track down.   It is also can force the optimizer to calculate these expressions over and over as well, when they should optimally only be calculated once.&lt;br /&gt;
&lt;br /&gt;
So, remember: for constant expressions that don't change, just declare and set variables, and examine the variables' contents before using them anywhere to ensure that your expressions are working as you intend.  For repeated expressions that are based on values in the tables you are querying, consider calculating them once within a Derived Table or a Common Table Expression.  In addition, be sure to use meaningful variable names and aliases which will help to greatly improve the clarity and intentions of your code.&lt;br /&gt;
&lt;br /&gt;
It all comes back to the "golden rule" of programming: If you need to cut and paste, you're probably doing it wrong!&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60440.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/12/20/simplify-sql-with-variables-and-derived-tables.aspx</guid>
            <pubDate>Thu, 20 Dec 2007 17:20:25 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60440.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/12/20/simplify-sql-with-variables-and-derived-tables.aspx#feedback</comments>
            <slash:comments>6</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60440.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60440.aspx</trackback:ping>
        </item>
        <item>
            <title>SELECT DISTINCT and ORDER BY</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/12/13/select-distinct-order-by-error.aspx</link>
            <description>Let's take a look at another one of those &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/07/20/60261.aspx" target="_blank"&gt;stupid, arbitrary SQL Server error messages&lt;/a&gt; that Bill Gates clearly only created because Micro$oft is evil and incompetent and they want to annoy us (and probably kill baby squirrels, too):&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New; color: rgb(153, 51, 0);"&gt;Msg 145, Level 15, State 1, Line 4&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(153, 51, 0);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(153, 51, 0);"&gt;ORDER BY items must appear in the select list if SELECT DISTINCT is specified.&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(153, 51, 0);" /&gt;
&lt;/div&gt;
&lt;br /&gt;
This message pops up when you ask for DISTINCT rows for one set of columns, but you'd like to have the results ordered by one or more columns &lt;span style="font-style: italic;"&gt;not &lt;/span&gt;specified in your distinct set.  For some reason, SQL Server will not allow this!  Why not?&lt;br /&gt;
&lt;br /&gt;
Let's look at an example.  Suppose we have the following data:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;Letter  Value&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----    ------    &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;A       1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;A       1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;B       3&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;B       3&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;C       2&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
From that, let's say we'd like see only DISTINCT letters, ordered by value.  Clearly, this means we want to return:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;A&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;C&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;B&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
... right?  "A" has the lowest values of 1, followed "C" with a value of 2, and finally "B" with values of 3.  Yet, if we write:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select distinct letter&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from x&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;order by Value&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
we receive back the above error message.  Why?&lt;br /&gt;
&lt;br /&gt;
Remember, the "rules" of what is allowed and not allowed in SQL is not determined by how your data looks at a particular point in time; it is a constant.  Just because one set of data &lt;span style="font-style: italic;"&gt;seems &lt;/span&gt;to be perfectly orderable in this scenario does &lt;span style="font-style: italic;"&gt;not &lt;/span&gt;mean that &lt;span style="font-style: italic;"&gt;all &lt;/span&gt;data is always going to be perfectly orderable as well.  What if we had this set of data instead:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;Letter  Value&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----    -----    &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;A       1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;A       1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;B       3&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;B       0&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;C       2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Look carefully at the above, and think about what should be returned when asking for distinct Letters ordered by Value.  &lt;br /&gt;
&lt;br /&gt;
The answer is .... there is no correct answer!  B contains a value of both 0 and 3, so should it appear &lt;span style="font-style: italic;"&gt;first&lt;/span&gt;, or should it appear &lt;span style="font-style: italic;"&gt;last&lt;/span&gt;?  The answer is -- who knows?!  It is not specified when simply asking for distinct Letters ordered by Value.   It is not a clear, complete, deterministic question that you are asking SQL Server to answer; it is like asking someone "what color is it when you add 4 and 3?"  -- the question makes no sense and cannot be conclusively answered as stated.&lt;br /&gt;
&lt;br /&gt;
Now, one person might say, "well, clearly, we want to B to be returned &lt;span style="font-style: italic;"&gt;first&lt;/span&gt;, since it has the value of 0 and that is lower than all the other values", and another might say "well, clearly, we want B to be returned &lt;span style="font-style: italic;"&gt;last&lt;/span&gt;, since it has the value of 3 and that is clearly higher than all the other values."  And both people would technically be right, and both are entitled to their logic and their needs -- but that logic and those requirements need to be specified; they cannot be implied, since there is more than one way to interpret the question.  Computers are funny that way, right? They are pretty darn smart, but they always insist on being told &lt;span style="font-style: italic;"&gt;exactly&lt;/span&gt; what it is we want.   How annoying!&lt;br /&gt;
&lt;br /&gt;
(I often use this analogy regarding users or programmers who refuse to express their requirements or needs logically and completely: It is like a magic Genie saying "you can have anything in the world, all you need to do is &lt;span style="font-style: italic;"&gt;tell me specifically what you want &lt;/span&gt;and make it &lt;span style="font-style: italic;"&gt;perfectly clear&lt;/span&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt;and &lt;span style="font-style: italic;"&gt;you will get it!"&lt;/span&gt;, and the users thinking about it, and eventually concluding "nahh... not worth it, sounds like too much work; can't you just figure out what I want?")&lt;br /&gt;
&lt;br /&gt;
So, what is the solution here? To make the error "just go away", we can try just adding the Value column to the SELECT clause like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select distinct Letter, Value&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from x&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;order by Value&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
In our original set of data, this works fine -- it returns the results we want and expect, only with an additional column.  If your data has a 1-1 relation between the ORDER BY columns and the SELECT columns, then simply adding the ORDER BY columns to your SELECT does the trick.  &lt;br /&gt;
&lt;br /&gt;
However, running that SELECT on the second set of data (in which "B" has values of 0 and 3) results in "B" being repeated twice:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;B    0&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;A    1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;C    2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;B    3&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
To solve this, like usual, we simply must decide what we want, and explicitly tell SQL Server what that is.  If we want to order by the letter using the lowest associated value, then we simply ask for that ... not by using DISTINCT, but by using GROUP BY:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select Letter&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from x&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by Letter&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;order by min(Value)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
This results in:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;B&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;A&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;C&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
... And if we want to do the opposite, and order by the Letter with the greatest associated value, then we write:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select Letter&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from x&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by Letter&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;order by max(Value)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;A&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;C&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;B&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
We may even want to add up all of the values for each letter and order by that, or maybe there is some other rule. The key is that SQL Server cannot help you until you specifically express what you are looking for.  And that is what this error message is all about -- "Hey, what you are asking for can be interpreted many different ways; can you be more specific?"&lt;br /&gt;
&lt;br /&gt;
SQL (and any other programming language) really is like the magic Genie; it can give you whatever you want, but there is a catch -- you need to ask for it!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;see also:&lt;br /&gt;
&lt;/span&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/10/12/sql-distinct-group-by.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl10_HyperLink1"&gt;By The Way ... DISTINCT is not a function ...&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/08/30/string-literal-alias-sql-server.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl08_HyperLink1"&gt;Is it a String Literal or an Alias?&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/07/26/60271.aspx" title="View Entry"&gt;SELECT * FROM TABLE -- except for these columns&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/07/20/60261.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl06_HyperLink1"&gt;But *WHY* Must That Column Be Contained in an Aggregate Function or the GROUP BY clause?&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/05/03/60195.aspx" title="View Entry"&gt;In SQL, it's a Case Expression, *not* a Case Statement&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/03/14/60133.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl08_HyperLink1"&gt;Sometimes the problem isn't the code.  It's the specs.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60429.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/12/13/select-distinct-order-by-error.aspx</guid>
            <pubDate>Thu, 13 Dec 2007 19:58:57 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60429.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/12/13/select-distinct-order-by-error.aspx#feedback</comments>
            <slash:comments>11</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60429.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60429.aspx</trackback:ping>
        </item>
        <item>
            <title>Some SELECTs will never return 0 rows -- regardless of the criteria</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/11/13/sql-aggregate-totals.aspx</link>
            <description>In SQL, the general rule of thumb is that the number of rows returned from a SELECT will be zero if your criteria did not match any data.  However, there is an important exception to this rule: it does &lt;span style="font-style: italic;"&gt;not &lt;/span&gt;apply when asking for aggregate calculations such as SUM(), MIN() or MAX(), without any grouping.  This is rather interesting and important to know and look out for, as it can cause some confusion and recently some of my ASP.NET code failed due to this.  Let's take a look.&lt;br /&gt;
&lt;br /&gt;
We'll be using the following simple table for our examples:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;create table tmp (f1 int, f2 int)&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;/span&gt; &lt;span style="font-family: Courier New;"&gt;insert into tmp&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 1,1 union all&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 1,2 union all&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select 2,3&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Now, if we SELECT from this table without any criteria, we will get 3 rows returned:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select f1,f2 from tmp&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;f1          f2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- -----------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           3&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(3 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
If we put criteria on our SELECT that doesn't match any rows -- for example, where f2 &amp;gt; 3 -- we will get back zero rows:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select f1,f2 from tmp where f2 &amp;gt; 3&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;f1          f2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- -----------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(0 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
So far, so good.  Let's try adding a GROUP BY clause to this SELECT.  If we want just the the MAX(f2) per f1, we get back two rows:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select f1, max(f2) as MaxF2 from tmp group by f1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;f1          MaxF2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- -----------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           3&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(2 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Once again, let's constrain our results so that no data matches:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select f1, max(f2) as MaxF2 from tmp where f2 &amp;gt; 3 group by f1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;f1          MaxF2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------- -----------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(0 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
... and once again, no rows are returned.  This should all be expected, and when writing our client code, we can do simple checks to verify if any data matched our SELECT statement's criteria simply by checking the row count.  In the case of a SqlDataReader, the Read() method will return False immediately and we know that no rows were returned, so no data matched our criteria.&lt;br /&gt;
&lt;br /&gt;
So, it seems that we have simply verified the following:  &lt;span style="font-style: italic;"&gt;In a SELECT statement, if the WHERE clause results in no matching rows in the underlying table(s), zero rows are returned in the result set.   &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
However, there is an exception to this rule!   Let's get the SUM() of the f1 column from the entire table, without any criteria or grouping.  As expected, this will result in a single row returned with the total:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select sum(f1) as TotalF1 &lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;from tmp&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;TotalF1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;-----------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;4&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(1 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Next, let's filter the result, just as before, so that no rows match our criteria, and again ask for the SUM(f1).  Since no rows match our criteria, we expect to once again get 0 results returned.  However, notice what happens:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select sum(f1) as TotalF1 from tmp where f1 &amp;gt; 4&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;TotalF1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;-----------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;NULL&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(1 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
A row is returned, with a Null value! Yet, there are *no* rows that match our criteria!  This is very interesting, and rather important to know.   Please note that there is a big difference between getting a single row back with a NULL value as opposed to getting no rows back at all, even though we might logically interpret the results the same way.   In fact, if you just are selecting only aggregate calculations from a table, without any grouping, one row will &lt;span style="font-style: italic;"&gt;always &lt;/span&gt;be returned -- never more, never less  (note that this does not apply if you add a HAVING clause -- see below).  &lt;br /&gt;
&lt;br /&gt;
As an example, say that you have a simple stored procedure like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;create procedure GetPreviousWeek @CurrentWeek DateTime&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;as&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;select Max(Week) as PreviousWeek&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from Calendar&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;where Week &amp;lt; @CurrentWeek&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Written as is, it is important to remember that you will &lt;span style="font-style: italic;"&gt;always &lt;/span&gt;get a &lt;span style="font-style: italic;"&gt;single row &lt;/span&gt;back, even if there is no previous week before the @CurrentWeek parameter!  I had a similar stored procedure, and incorrectly wrote my client logic like this:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;SqlDataReader r = cmd.ExecuteReader()&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;if (r.Read())&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;{&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  // there is a previous week&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;}&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;else&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;{&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  // there is not a previous week&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
That was based on the assumption that the WHERE clause would result in no rows being returned if there was no previous week and therefore no matching data.  However, since the stored procedure was only calculating and returning an aggregate total, a single row is always returned, which meant that my logic was flawed.  What I really needed was something like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;SqlDataReader r = cmd.ExecuteReader()&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;if (r.Read())&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;{&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  if (r["PreviousWeek"] == dbNull.Value)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  {&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    // there is no previous week&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  }&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  else&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  {&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    // there IS a previous week value &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  }&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;}&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;else&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;{&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  // this should never occur!&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;}&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Notice the difference in the logic.&lt;br /&gt;
&lt;br /&gt;
In short, I think it makes sense:  If I ask for only an aggregate &lt;span style="font-style: italic;"&gt;value &lt;/span&gt;for some data, even if that data has no rows, I should always get a value back -- though, of course, it may be NULL.  However, if I specifically ask for a &lt;span style="font-style: italic;"&gt;set of rows &lt;/span&gt;(by not aggregating or by providing a GROUP BY clause) then I should expect that I might not receive any rows back at all if no data matches my criteria.&lt;br /&gt;
&lt;br /&gt;
Consider a "real world" example: If I asked you for the total population of all U.S. states that start with "Z", you would be able to reply with a single value (NULL, or perhaps 0).  But, if I ask you to list all of the states that start with "Z" along with their individual population, the answer would be an empty set; you would not be able to give me a value or set of values, you would reply that "no states start with Z so there is no data to return."&lt;br /&gt;
&lt;br /&gt;
Please note that adding a HAVING clause to filter your SELECT may indeed result in zero rows being returned, since the HAVING is applied after the aggregate is calculated.  For example:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select sum(f1) as TotalF1 from tmp having sum(f1) &amp;gt; 10&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;TotalF1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;-----------&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(0 row(s) affected)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
In that case, the single value is calculated, but it is not returned in the final results because the HAVING clause prevented it.&lt;br /&gt;
&lt;br /&gt;
So, keep this in mind when returning single, aggregate values in a SELECT:  You will always get a single row returned, and never an "empty set", unless you also provide a HAVING clause filter.  If you have any columns in your GROUP clause, however, this does not apply and you may indeed get an empty set returned if your criteria does not match any data.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;see also:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/10/12/sql-distinct-group-by.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl04_HyperLink1"&gt;By The Way ... DISTINCT is not a function ...&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/09/27/sql-nullif-function.aspx" title="View Entry"&gt;A handy but little-known SQL function: NULLIF()&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/08/30/string-literal-alias-sql-server.aspx" title="View Entry"&gt;Is it a String Literal or an Alias?&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/06/26/60240.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl06_HyperLink1"&gt;Passing an Array or Table Parameter to a Stored Procedure&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/07/26/60271.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl02_HyperLink1"&gt;SELECT * FROM TABLE -- except for these columns&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/05/03/60195.aspx" title="View Entry"&gt;In SQL, it's a Case Expression, *not* a Case Statement&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2004/11/22/2927.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl10_HyperLink1"&gt;Returning Random Numbers in a SELECT statement&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60397.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/11/13/sql-aggregate-totals.aspx</guid>
            <pubDate>Tue, 13 Nov 2007 16:11:19 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60397.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/11/13/sql-aggregate-totals.aspx#feedback</comments>
            <slash:comments>10</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60397.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60397.aspx</trackback:ping>
        </item>
        <item>
            <title>The Mailbag: Referencing Assemblies in Reporting Services; some SQL help</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/10/18/60377.aspx</link>
            <description>As &lt;a href="http://en.wikipedia.org/wiki/David_Letterman" target="_blank"&gt;David Letterman&lt;/a&gt; would say, wake the kids, call the neighbors, it's time for &lt;a href="http://weblogs.sqlteam.com/jeffs/contact.aspx"&gt;The Mailbag!&lt;/a&gt;  Just some quickies today.&lt;br /&gt;
&lt;br /&gt;
Christopher writes:&lt;br /&gt;
&lt;br /&gt;
&lt;p style="font-family: Arial; margin-left: 40px; font-style: italic;"&gt;Greetings Jeff,&lt;br /&gt;
&lt;br /&gt;
First and foremost, great job with all of the blogs. I have a questions&lt;br /&gt;
that I cannot seem to get a straight answer for. I am working with SQL&lt;br /&gt;
Server Reporting Services (SSRS) and have the need to create VB&lt;br /&gt;
functions to customize the reports generated. For example, a setter/getter to&lt;br /&gt;
display information that would not be readily available from the&lt;br /&gt;
query. SSRS allows this type of custom Visual Basic code to reside in the&lt;br /&gt;
report itself, but since most of my code is across multiple reports, it&lt;br /&gt;
makes 0 sense to place the same code in each report. Do you know of a&lt;br /&gt;
way that I can create a "code library" so that there is one location for&lt;br /&gt;
all of the code and all of the reports can access it?&lt;br /&gt;
&lt;br /&gt;
Thank you very much for your time and effort.&lt;br /&gt;
&lt;br /&gt;
Sincerely,&lt;br /&gt;
Christopher McGraw&lt;/p&gt;
Chris, Here's all the information that you need:  &lt;a href="http://msdn2.microsoft.com/en-us/library/ms153561.aspx" target="_blank"&gt;Using Custom Assemblies with Reports&lt;/a&gt;  (from SQL Server 2005 Books On Line).  I can't really add much to it -- it explains everything in detail.&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;
&lt;/div&gt;
Traner writes:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px; font-family: Arial; font-style: italic;"&gt;
&lt;p&gt;I have two tables, table1's primary key is table2's foreign key.&lt;br /&gt;
Table2 has multiple dates that relate to table1.&lt;br /&gt;
&lt;br /&gt;
ie. &lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: Courier New;"&gt;Table1  : Table2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;JOE      : 10/18/07&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;DAVE    : 11/14/07&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;JOE      : 11/27/08&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br /&gt;
I am trying to get highest date from table2 related to table1.  Do you&lt;br /&gt;
know how this can be accomplished.  Any assistance will be greatly&lt;br /&gt;
appreciated.&lt;/p&gt;
&lt;/div&gt;
&lt;br /&gt;
That really isn't the clearest way to convey your schema, but I think I know what you mean.   Let's assume that Table1 has two columns, ID and Name, and that table2 has 3 columns, ID, Date and Value.&lt;br /&gt;
&lt;br /&gt;
First, to get the highest date per ID, you simply use the MAX() aggregate function along with GROUP BY when selecting from Table2:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select ID, Max(Date) as MaxDate&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from Table2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;group by ID&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Be sure to read up and practice with GROUP BY and aggregate functions if you are not familiar with them -- they are very powerful and very fundamental to SQL. &lt;br /&gt;
&lt;br /&gt;
Now, you can select from Table1 and join to the above SQL statement in a derived table to return all rows from Table1 and the maximum date from table 2:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New; font-weight: bold;"&gt;select Table1.ID, Table1.&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;&lt;span style="font-weight: bold;"&gt;Name, t2.MaxDate&lt;/span&gt;&lt;br style="font-weight: bold;" /&gt;
&lt;span style="font-weight: bold;"&gt;from Table1&lt;/span&gt;&lt;br style="font-weight: bold;" /&gt;
&lt;span style="font-weight: bold;"&gt;inner join &lt;/span&gt;&lt;br /&gt;
(  select ID, Max(Date) as MaxDate&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;   from Table2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;   group by ID&lt;br /&gt;
) t2 on Table1.ID = Table2.ID&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
As you can see, we have enclosed our previous SQL statement in parenthesis, and assigned it an alias ("t2" in this case), and we can join to it and select from it just like any other table.  So, we have simply selected from Table1 and joined to a summarized version of Table2 that only returns the maximum date per ID.&lt;br /&gt;
&lt;br /&gt;
Finally, notice that all we are returning from Table2 is the date; if there are other columns from Table2 that we wish to return (for example, the "Value" column), we must add &lt;span style="font-style: italic;"&gt;another &lt;/span&gt;join to Table2, that returns only the row with the maximum date per ID:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select &lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;Table1.&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;ID, &lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;Table1.&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;Name, t2.MaxDate, &lt;span style="font-weight: bold;"&gt;Table2.Value&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Courier New;"&gt; from Table1&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Courier New;"&gt; inner join &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Courier New;"&gt; (  select ID, Max(Date) as MaxDate&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;   from Table2&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;   group by ID&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Courier New;"&gt; ) t2 on Table1.ID = Table2.ID&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;inner join Table2 on t2.ID = Table2.ID and t2.MaxDate = t2.Date&lt;/span&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
Notice that the "on" clause indicates that we are joining on ID as you might expect, but also on MaxDate = Date, so that we only return the row in Table2 that has the maximum date per ID.&lt;br /&gt;
&lt;br /&gt;
If you are using SQL Server 2005, this can be done a little easier, with only one join, using the new Rank() function:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select x.ID, x.Name, x.Date, x.Value&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;from&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  select Table1.ID, Table1.Name, Table2.Date, Table2.Value,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;   rank() over (partion by Table1.ID order by Table2.Date DESC) as Rank&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  from Table1&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;  inner join Table2 on Table1.ID = Table2.ID&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;) x&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;where x.Rank = 1&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
More on Rank() and partitions &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/03/28/60146.aspx"&gt;here&lt;/a&gt;.  Hope this helps you out. &lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60377.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/10/18/60377.aspx</guid>
            <pubDate>Thu, 18 Oct 2007 16:19:54 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60377.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/10/18/60377.aspx#feedback</comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60377.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60377.aspx</trackback:ping>
        </item>
        <item>
            <title>Group by Month (and other time periods)</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/09/10/group-by-month-sql.aspx</link>
            <description>When you need to summarize transactional data by Month, there are several ways to do it, some better than others.  What to ultimately choose depends on your needs, but remember: Keep it short and simple in T-SQL, and always do all of your formatting at your presentation layer where it belongs.  &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/09/10/group-by-month-sql.aspx"&gt;read more...&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60324.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/09/10/group-by-month-sql.aspx</guid>
            <pubDate>Mon, 10 Sep 2007 15:28:56 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60324.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/09/10/group-by-month-sql.aspx#feedback</comments>
            <slash:comments>28</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60324.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60324.aspx</trackback:ping>
        </item>
        <item>
            <title>More on GROUP BY; Examining SUM(Distinct) </title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/07/31/60274.aspx</link>
            <description>I've written a two part article on using SQL GROUP BY clauses over at &lt;a target="_blank" href="http://www.sqlteam.com"&gt;SQLTeam.com&lt;/a&gt;.  It's always a common topic of discussion and confusion amongst beginner and intermediate SQL programmers alike, so I thought I'd write a fairly long and hopefully comprehensive piece that takes a common summary report request and works towards the solution step-by-step.&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a target="_blank" href="http://www.sqlteam.com/article/how-to-use-group-by-in-sql-server"&gt;Part I:&lt;/a&gt;  Intro to GROUP BY; Duplicates caused by JOINS; Identifying "Virtual Primary Keys"; Using COUNT(Distinct)&lt;br /&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a target="_blank" href="http://www.sqlteam.com/article/how-to-use-group-by-with-distinct-aggregates-and-derived-tables"&gt;Part II:&lt;/a&gt;  Examining SUM(Distinct); GROUPING before JOINING; Using Derived Tables&lt;br /&gt;
    &lt;/li&gt;
&lt;/ul&gt;
I tried to focus on what happens when you join two tables and then try to group and aggregate the results, and where and how to do this to avoid aggregating duplicate values.   As always, I attempt to demonstrate breaking down the larger problem into smaller, simpler parts and then putting those pieces together to produce the final result.&lt;br /&gt;
&lt;br /&gt;
Perhaps most importantly: if you've ever used &lt;span style="font-style: italic;"&gt;SUM(Distinct) &lt;/span&gt;in your code in an attempt to handle duplicates, be sure to read Part II.  As &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Inigo_Montoya"&gt;Inigo Montoya&lt;/a&gt; would say: &lt;span style="font-style: italic;"&gt;I do not think it means what you think it means!&lt;/span&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60274.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/07/31/60274.aspx</guid>
            <pubDate>Tue, 31 Jul 2007 16:44:49 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60274.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/07/31/60274.aspx#feedback</comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60274.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60274.aspx</trackback:ping>
        </item>
        <item>
            <title>But *WHY* Must That Column Be Contained in an Aggregate Function or the GROUP BY clause?</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/07/20/60261.aspx</link>
            <description>&lt;font style="color:red; font-family: courier new;"&gt;Column 'xyz' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.&lt;/font&gt;&lt;br&gt;&lt;br&gt;Arggh!! There it is, yet again .. that annoying error message.   Why is SQL so picky about this?  What's the deal!? &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/07/20/60261.aspx"&gt;read more...&lt;/a&gt;
&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60261.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/07/20/60261.aspx</guid>
            <pubDate>Fri, 20 Jul 2007 14:33:29 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60261.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/07/20/60261.aspx#feedback</comments>
            <slash:comments>28</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60261.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60261.aspx</trackback:ping>
        </item>
        <item>
            <title>Using GROUP BY to avoid self-joins</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/06/12/60230.aspx</link>
            <description>Sometimes, it appears that a necessary solution to common SQL problems is to join a table to itself.   While self-joins do indeed have their place, and can be very powerful and useful, often times there is a much easier and more efficient way to get the results you need when querying a single table.
&lt;br&gt;&lt;br&gt;&lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/06/12/60230.aspx"&gt;read more...&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60230.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/06/12/60230.aspx</guid>
            <pubDate>Tue, 12 Jun 2007 15:35:33 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60230.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/06/12/60230.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60230.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60230.aspx</trackback:ping>
        </item>
        <item>
            <title>SQL Server 2005: Specifying Partitions for Aggregate Functions</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/05/21/60211.aspx</link>
            <description>Did you know that a new feature in SQL Server 2005 allows you to specify an OVER partition for aggregate functions in your SELECT statements?  
&lt;br&gt;
&lt;br&gt;
&lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/05/21/60211.aspx"&gt;read more...&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60211.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/05/21/60211.aspx</guid>
            <pubDate>Mon, 21 May 2007 18:52:05 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60211.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/05/21/60211.aspx#feedback</comments>
            <slash:comments>7</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60211.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60211.aspx</trackback:ping>
        </item>
    </channel>
</rss>