Window Functions in SQL Server Hi Folks, Im going to start a new series of three articles about Window functions, starting off by explaining what they are, and how they are used to provide details of an aggregation. Window functions Window functions belong to a type of function known as a set function, which means a function that applies to a set of rows. The word window is used to refer to the set of rows that the function works on. Windowing functions were added to the standard SQL 2. ISO and it was specified in more detail in SQL 2. For some time, other DBMSs such as Oracle, Sybase and DB2 have had support for window functions. Even the open source RDBMS Postgre. SQL has a full implementation. SQL Server has had only a partial implementation up to now, but it is coming in SQL 2. One of the most important benefits of window functions is that we can access the detail of the rows from an aggregation. To see an example, lets first suppose we have this table and data USEtempdb. GOIFOBJECTIDTest. AggregationISNOTNULL DROPTABLETest. Aggregation. GOCREATETABLETest. Aggregation IDINT,Value. Numeric1. 8,2GOINSERTINTOTest. Aggregation ID,ValueVALUES1,5. GO This is what the data looks like 1. SELECTFROMTest. Aggregation If we sum the column Value grouping by ID, by using a conventional GROUP BY, we would have the following query and result SELECTID,SUMValue FROMTest. Aggregation. GROUPBYID Here we can see a sample of the partitions of rows, or sets that the SUM aggregation function is working on. In the blue we have partition 1, green as partition 2 and red as partition 3. Because we applied the aggregation function in the column value, grouping the results by ID, we the lose the details of the data. In this case the details are the values of the columns of the rows in the partitions 1, 2 and 3. Lets suppose I need to write a query to return the total value of sales, the average value of sales and the quantity of sales for each ID, and still return the actual values of the rows, then we might think that we could use something like this to return this data SELECTID, Value, SUMValueASSum AVGValueASAvg COUNTValueASQuantity FROMTest. Aggregation. GROUPBYID Msg 8. Level 1. 6, State 1, Line 2 Column Test. Aggregation. Value is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. Unfortunately it is against the way that aggregations work. If you group by something, then you lose access to the details. A very commonly used alternative is to write every aggregation into a subquery, and then correlate with the main query using a join, something like 1. SELECTTest. Aggregation. ID, Test. Aggregation. Value, Tab. Sum. Sum Tab. Avg. Avg Tab. Count. Quantity FROMTest. Aggregation INNERJOINSELECTID,SUMValueASSum FROMTest. Aggregation GROUPBYIDASTab. Sum ONTab. Sum. IDTest. Aggregation. ID INNERJOINSELECTID,AVGValueASAvg FROMTest. Aggregation GROUPBYIDASTab. Avg ONTab. Avg. IDTest. Aggregation. ID INNERJOINSELECTID,COUNTValueASQuantity FROMTest. Aggregation GROUPBYIDASTab. Count ONTab. Count. IDTest. Aggregation. ID But a neater and faster solution is thisSELECT Test. Aggregation. ID, Test. Aggregation. Value, Aggregated. Values. Sum, Aggregated. Play Feeding Frenzy 2 Without Downloading here. Values. Avg, Aggregated. Values. Quantity. FROM Test. Aggregation. INNERJOIN SELECTID, SUMValueASSum AVGValueASAvg COUNTValueASQuantity FROMTest. Aggregation GROUPBYIDAggregated. Values. ONAggregated. Values. IDTest. Aggregation. ID A very elegant alternative is to use the clause OVER implemented in the aggregation functions, it allow us to access the details of the rows that have been aggregated. For instance we could try to get the result we want with this SELECTID, Value, SUMValueOVERASSum AVGValueOVERASAvg COUNTValueOVERASQuantity FROMTest. Aggregation but, with this query, we didnt return the expected results. In fact, we returned the aggregate values for the entire table rather than for each ID. Using the clause OVER with the aggregation function SUM, AVG and COUNT we have accessed the details of the grouped data along with a total aggregation of the data, but, in In fact, we want the aggregates for the data grouped by ID. To do this, we should use the clause PARTITION BY clause. For instance SELECTID, Value, SUMValueOVERPARTITIONBYIDASSum AVGValueOVERPARTITIONBYIDASAvg COUNTValueOVERPARTITIONBYIDASQuantity FROMTest. Aggregation Now we can see the same results as in the subquery alternative, but with a much more simple and elegant code. In the following picture we can see that even the results are grouped by ID we can see access the details of the aggregated partitions through the clause OVER and PARTITION BY. Set based thinking It can get tedious to hear about this set base thing, but in fact its not so easy to think set based. Sometimes its very hard to find a set based solution to a query we have. Window Functions give us more set based solutions to awkward problems. The main point of windowing functions its that they were created to work with a set. SQL Server never was good on processing queries row by row, thats why you always hearing that cursors are evil, and are not good for performance, you should avoid them and so on. SQL Server was not built to work row by row. Lets illustrate this. SQL Server takes an average of 5. Win. 32 app. DECLAREi. INT0,Time. Time3GETDATEWHILEilt 1. BEGIN SETi1 ENDSELECTCONVERTTime3,GETDATE TimeASTotal. Timetorunthe. Loop Delphi Code PROCEDURETForm. Button. 1ClickSender TObject Var i Integer Tempo TDate. Time BEGIN i 0 Tempo Now WHILEilt 1. BEGIN inci END Of course it is an unfair comparison. The compiler of a win. SQL Server, what I wanted to show here is the fact that SQL Server was not supposed to run row by row. I once was in London doing training with my colleague Itzik Ben Gan when I remember he said There is no row by row code that you cannot run an equivalent set based version, the problem is that you didnt figured out how to do it. Yes its a heavy phrase but, who could tell Itzik that this is not true Not I Window functions on SQL Server 2. Since SQL Server 2. ROWNUMBER, RANK, DENSERANK and NTILE. In this first article well review how these functions works, and how they can help us to write better and efficient set based codes. Test database To test the functions well use a table called Tab. The code to create the table is the following USETemp. DBGOIFOBJECTIDTab. ISNOTNULL DROPTABLETab. GOCREATETABLETab. Col. 1INTGOINSERTINTOTab. VALUES5,5,3,1GO RowNumber The ROWNUMBER function is used to generate a sequence of numbers based in a set in a specific order, in easy words, it returns the sequence number of each row inside a set in the order that you specify. For instance Row. Number. SELECTCol. ROWNUMBEROVERORDERBYCol. DESCASROWNUMBER FROMTab. The column called ROWNUMBER is one of a series of numbers created in the order of Col. The clause OVERORDER BY Col. DESC is used to specify the order of the sequence for which the number should be created. How To Show Serial Number In Sql Query To Find© 2017