AND t3.non_key_1 = 333 GROUP BY ROLLUP ( t1.key_1, t3.key_1 ) HAVING COUNT(*) > 1 ORDER BY 1, 2; The START AT 2 clause eliminates the grand total row to produce the final result set in this example: a b c d === ==== = ==== 100 NULL 2 666 200 NULL 6 1998 200 3000 3 999 200 4000 3 999 Step 13: Each NUMBER(*) call in the select list is computed for each row and appended to the row. Note that NUMBER(*) cant be evaluated until all the other clauses have had their turn; the rows cant be numbered until all the rows have been sorted and all unwanted rows have been eliminated. And thats why there are so many restrictions on where you can call NUMBER(*); for example, you cant use it in a WHERE clause because thats much too early to calculate NUMBER(*). Here is what the example SELECT looks like with a NUMBER(*) call added; the DISTINCT clause has been commented out because it conflicts with NUMBER(*): SELECT --DISTINCT TOP 4 START AT 2 t1.key_1 * 100 AS a, t3.key_1 * 1000 AS b, COUNT(*) AS c, SUM ( t3.non_key_1 ) AS d, NUMBER(*) AS e FROM ( t1 LEFT OUTER JOIN t2 ON t1.key_1 = t2.key_1 ) CROSS JOIN t3 WHERE b <= 5000 AND t3.non_key_1 = 333 GROUP BY ROLLUP ( t1.key_1, t3.key_1 ) HAVING COUNT(*) > 1 ORDER BY 1, 2; The resulting output shows the row number as column e: a b c d e === ==== = ==== = 100 NULL 2 666 1 200 NULL 6 1998 2 200 3000 3 999 3 200 4000 3 999 4 Step 14: The FOR XML clause is applied to transform the result set into a sin- gle row consisting of a single XML document column. Step 15: The INTO clause is executed to fill host variables or a temporary table. A temporary table can accept multiple rows, while host variables can only be used if the result set is a single row. Heres what the example SELECT looks like with INTO and FOR XML clauses added; the NUMBER(*) call has been removed because it conflicts with FOR XML: