In this article we will try to elaborate on the usage of window functions in PostgreSQL.
A window function performs a calculation across a set of table rows that are somehow related to the current row. This is comparable to the type of calculation that can be done with an aggregate function. However, window functions do not cause rows to become grouped into a single output row like non-window aggregate calls would. Instead, the rows retain their separate identities. Behind the scenes, the window function is able to access more than just the current row of the query result.
To sum this up we can say that:
- Define a set of rows per row within the result-set.
- Perform an operation on those rows
- Return the result of this operation as the value of each row.
Which rows will be in the window is defined by the window definition -which is also the main syntactic distinction is that window function- defined by the OVER
clause. The operation which we want to apply will be defined alongside the OVER
clause.
Overall when we see an OVER
clause then the function is a window function else it will simply be an aggregation or scalar function.
Syntax – F.O.P.O.
In terms of syntax for window functions, when you are getting started with them F.O.P.O. is a nice way to remember the components you need.
- F: The function component, essentially how we want to treat our data. (
AVG(), RANK()
etc). - O: The OVER() clause, the way to invoke the functions
- P: The
PARTITION BY()
clause, the way we want to create subgroups – essentially ourGROUP BY
for the window functions. - O:
ORDER BY()
ascending or descending order of data based on the desired column(s).
func() over (PARTITION BY column ORDER BY column)
There are several window function provided in PostgreSQL. The complete list can be found here.
Dataset
We will be using the Northwind Database for our example for which the ERD you can found below.
![](http://karolos.me/wp-content/uploads/2022/06/image-906x1024.png)
Examples
Let’s start working with them to get familiarized. Assume that we want to get some data from the product (name, and unit price e.g) and also we want to calculate the average unit price for the category of the particular product. Most likely we would create a CTE where we would calculate the the average unit price per category and then join it with the rest of the results. Or perhaps we could do a complex group by as well.
Utilizing window function that would be something like:
SELECT product_id, product_name, unit_price, category_id, AVG(unit_price) OVER(PARTITION BY category_id) AS average_unit_price_in_category FROM products WHERE not discontinued::bool;
And this will produce the below outcome:
product_id | product_name | unit_price | category_id | average_unit_price_in_category |
---|---|---|---|---|
39 | Chartreuse verte | 18 | 1 | 46.02777777777778 |
76 | Lakkalikööri | 18 | 1 | 46.02777777777778 |
38 | Côte de Blaye | 263.5 | 1 | 46.02777777777778 |
35 | Steeleye Stout | 18 | 1 | 46.02777777777778 |
34 | Sasquatch Ale | 14 | 1 | 46.02777777777778 |
75 | Rhönbräu Klosterbier | 7.75 | 1 | 46.02777777777778 |
70 | Outback Lager | 15 | 1 | 46.02777777777778 |
67 | Laughing Lumberjack Lager | 14 | 1 | 46.02777777777778 |
43 | Ipoh Coffee | 46 | 1 | 46.02777777777778 |
61 | Sirop d'érable | 28.5 | 2 | 22.990909229625355 |
4 | Chef Anton's Cajun Seasoning | 22 | 2 | 22.990909229625355 |
6 | Grandma's Boysenberry Spread | 25 | 2 | 22.990909229625355 |
8 | Northwoods Cranberry Sauce | 40 | 2 | 22.990909229625355 |
15 | Genen Shouyu | 13 | 2 | 22.990909229625355 |
44 | Gula Malacca | 19.45 | 2 | 22.990909229625355 |
3 | Aniseed Syrup | 10 | 2 | 22.990909229625355 |
63 | Vegie-spread | 43.9 | 2 | 22.990909229625355 |
65 | Louisiana Fiery Hot Pepper Sauce | 21.05 | 2 | 22.990909229625355 |
66 | Louisiana Hot Spiced Okra | 17 | 2 | 22.990909229625355 |
77 | Original Frankfurter grüne Soße | 13 | 2 | 22.990909229625355 |
27 | Schoggi Schokolade | 43.9 | 3 | 25.1600000674908 |
19 | Teatime Chocolate Biscuits | 9.2 | 3 | 25.1600000674908 |
16 | Pavlova | 17.45 | 3 | 25.1600000674908 |
47 | Zaanse koeken | 9.5 | 3 | 25.1600000674908 |
48 | Chocolade | 12.75 | 3 | 25.1600000674908 |
49 | Maxilaku | 20 | 3 | 25.1600000674908 |
50 | Valkoinen suklaa | 16.25 | 3 | 25.1600000674908 |
62 | Tarte au sucre | 49.3 | 3 | 25.1600000674908 |
68 | Scottish Longbreads | 12.5 | 3 | 25.1600000674908 |
20 | Sir Rodney's Marmalade | 81 | 3 | 25.1600000674908 |
21 | Sir Rodney's Scones | 10 | 3 | 25.1600000674908 |
25 | NuNuCa Nuß-Nougat-Creme | 14 | 3 | 25.1600000674908 |
26 | Gumbär Gummibärchen | 31.23 | 3 | 25.1600000674908 |
11 | Queso Cabrales | 21 | 4 | 28.729999923706053 |
31 | Gorgonzola Telino | 12.5 | 4 | 28.729999923706053 |
32 | Mascarpone Fabioli | 32 | 4 | 28.729999923706053 |
33 | Geitost | 2.5 | 4 | 28.729999923706053 |
71 | Flotemysost | 21.5 | 4 | 28.729999923706053 |
12 | Queso Manchego La Pastora | 38 | 4 | 28.729999923706053 |
72 | Mozzarella di Giovanni | 34.8 | 4 | 28.729999923706053 |
59 | Raclette Courdavault | 55 | 4 | 28.729999923706053 |
60 | Camembert Pierrot | 34 | 4 | 28.729999923706053 |
69 | Gudbrandsdalsost | 36 | 4 | 28.729999923706053 |
64 | Wimmers gute Semmelknödel | 33.25 | 5 | 21.291666666666668 |
52 | Filo Mix | 7 | 5 | 21.291666666666668 |
23 | Tunnbröd | 9 | 5 | 21.291666666666668 |
56 | Gnocchi di nonna Alice | 38 | 5 | 21.291666666666668 |
57 | Ravioli Angelo | 19.5 | 5 | 21.291666666666668 |
22 | Gustaf's Knäckebröd | 21 | 5 | 21.291666666666668 |
54 | Tourtière | 7.45 | 6 | 15.724999904632568 |
55 | Pâté chinois | 24 | 6 | 15.724999904632568 |
14 | Tofu | 23.25 | 7 | 29.0625 |
74 | Longlife Tofu | 10 | 7 | 29.0625 |
7 | Uncle Bob's Organic Dried Pears | 30 | 7 | 29.0625 |
51 | Manjimup Dried Apples | 53 | 7 | 29.0625 |
41 | Jack's New England Clam Chowder | 9.65 | 8 | 20.682499885559082 |
45 | Rogede sild | 9.5 | 8 | 20.682499885559082 |
46 | Spegesild | 12 | 8 | 20.682499885559082 |
58 | Escargots de Bourgogne | 13.25 | 8 | 20.682499885559082 |
73 | Röd Kaviar | 15 | 8 | 20.682499885559082 |
10 | Ikura | 31 | 8 | 20.682499885559082 |
30 | Nord-Ost Matjeshering | 25.89 | 8 | 20.682499885559082 |
18 | Carnarvon Tigers | 62.5 | 8 | 20.682499885559082 |
36 | Inlagd Sill | 19 | 8 | 20.682499885559082 |
37 | Gravad lax | 26 | 8 | 20.682499885559082 |
40 | Boston Crab Meat | 18.4 | 8 | 20.682499885559082 |
13 | Konbu | 6 | 8 | 20.682499885559082 |
This SELECT
statement may be syntactically confusing initially so let us try to break it down:
- As in any
SELECT
statement we have the columns we want to display in the output. - Then we have the
AVG()
function called with the unit price. - This is what we want to calculate over a subset of rows (per category essentially). The
PARTITION
does this for us. So as the name implies it will partition the results over category_id. - The aggregate function (
AVG(unit_price)
) will now be calculated for each partition/group.
Let us perform one more similar example. Assume now that we want to produce the count of orders for each customer, along with the count of orders for the country of the customer. Again this can happen with a CTE easily and join with the outer query to get the desired outcomes. This can also happen with window functions.
SELECT DISTINCT c.customer_id, c.company_name, c.country, COUNT(order_id) OVER (PARTITION BY c.customer_id) as customer_orders, COUNT(order_id) OVER (PARTITION BY country) as country_orders FROM orders JOIN customers c on orders.customer_id = c.customer_id;
The logic is similar to the above but this time we are using the COUNT()
function. In the first occurrence we partition over customers and in the second over countries. Note the DISTINCT
in this case. Since we do not have an actual GROUP BY()
clause this will produce one row per order per customer if we do not use DISTINCT
.
The outcome will be:
customer_id | company_name | country | customer_orders | country_orders |
---|---|---|---|---|
BERGS | Berglunds snabbköp | Sweden | 18 | 37 |
LACOR | La corne d'abondance | France | 4 | 77 |
REGGC | Reggiani Caseifici | Italy | 12 | 28 |
OLDWO | Old World Delicatessen | USA | 10 | 122 |
THECR | The Cracker Box | USA | 3 | 122 |
ANTON | Antonio Moreno Taquería | Mexico | 7 | 28 |
FURIB | Furia Bacalhau e Frutos do Mar | Portugal | 8 | 13 |
EASTC | Eastern Connection | UK | 8 | 56 |
HILAA | HILARION-Abastos | Venezuela | 18 | 46 |
LEHMS | Lehmanns Marktstand | Germany | 15 | 122 |
SANTG | Santé Gourmet | Norway | 6 | 6 |
ANATR | Ana Trujillo Emparedados y helados | Mexico | 4 | 28 |
NORTS | North/South | UK | 3 | 56 |
BLONP | Blondesddsl père et fils | France | 11 | 77 |
ALFKI | Alfreds Futterkiste | Germany | 6 | 122 |
PRINI | Princesa Isabel Vinhos | Portugal | 5 | 13 |
CACTU | Cactus Comidas para llevar | Argentina | 6 | 16 |
FAMIA | Familia Arquibaldo | Brazil | 7 | 83 |
DRACD | Drachenblut Delikatessen | Germany | 6 | 122 |
FRANR | France restauration | France | 3 | 77 |
FOLKO | Folk och fä HB | Sweden | 19 | 37 |
WILMK | Wilman Kala | Finland | 7 | 22 |
HUNGC | Hungry Coyote Import Store | USA | 5 | 122 |
BOTTM | Bottom-Dollar Markets | Canada | 14 | 30 |
MAGAA | Magazzini Alimentari Riuniti | Italy | 10 | 28 |
LAMAI | La maison d'Asie | France | 14 | 77 |
BOLID | Bólido Comidas preparadas | Spain | 3 | 23 |
WOLZA | Wolski Zajazd | Poland | 7 | 7 |
CHOPS | Chop-suey Chinese | Switzerland | 8 | 18 |
SAVEA | Save-a-lot Markets | USA | 31 | 122 |
KOENE | Königlich Essen | Germany | 14 | 122 |
WARTH | Wartian Herkku | Finland | 15 | 22 |
LINOD | LINO-Delicateses | Venezuela | 12 | 46 |
TOMSP | Toms Spezialitäten | Germany | 6 | 122 |
TORTU | Tortuga Restaurante | Mexico | 10 | 28 |
AROUT | Around the Horn | UK | 13 | 56 |
HUNGO | Hungry Owl All-Night Grocers | Ireland | 19 | 19 |
LETSS | Let's Stop N Shop | USA | 4 | 122 |
GALED | Galería del gastrónomo | Spain | 5 | 23 |
FOLIG | Folies gourmandes | France | 5 | 77 |
MORGK | Morgenstern Gesundkost | Germany | 5 | 122 |
RANCH | Rancho grande | Argentina | 5 | 16 |
GROSR | GROSELLA-Restaurante | Venezuela | 2 | 46 |
PICCO | Piccolo und mehr | Austria | 10 | 40 |
FRANK | Frankenversand | Germany | 15 | 122 |
OCEAN | Océano Atlántico Ltda. | Argentina | 5 | 16 |
ERNSH | Ernst Handel | Austria | 30 | 40 |
WANDK | Die Wandernde Kuh | Germany | 10 | 122 |
QUICK | QUICK-Stop | Germany | 28 | 122 |
LAZYK | Lazy K Kountry Store | USA | 2 | 122 |
RICSU | Richter Supermarkt | Switzerland | 10 | 18 |
THEBI | The Big Cheese | USA | 4 | 122 |
ISLAT | Island Trading | UK | 10 | 56 |
SPECD | Spécialités du monde | France | 4 | 77 |
SEVES | Seven Seas Imports | UK | 9 | 56 |
WELLI | Wellington Importadora | Brazil | 9 | 83 |
GODOS | Godos Cocina Típica | Spain | 10 | 23 |
BSBEV | B's Beverages | UK | 10 | 56 |
MAISD | Maison Dewey | Belgium | 7 | 19 |
SPLIR | Split Rail Beer & Ale | USA | 9 | 122 |
PERIC | Pericles Comidas clásicas | Mexico | 6 | 28 |
VINET | Vins et alcools Chevalier | France | 5 | 77 |
SIMOB | Simons bistro | Denmark | 7 | 18 |
VICTE | Victuailles en stock | France | 10 | 77 |
TRADH | Tradição Hipermercados | Brazil | 6 | 83 |
ROMEY | Romero y tomillo | Spain | 5 | 23 |
DUMON | Du monde entier | France | 4 | 77 |
LILAS | LILA-Supermercado | Venezuela | 14 | 46 |
TRAIH | Trail's Head Gourmet Provisioners | USA | 3 | 122 |
VAFFE | Vaffeljernet | Denmark | 11 | 18 |
FRANS | Franchi S.p.A. | Italy | 6 | 28 |
HANAR | Hanari Carnes | Brazil | 14 | 83 |
CONSH | Consolidated Holdings | UK | 3 | 56 |
BLAUS | Blauer See Delikatessen | Germany | 7 | 122 |
SUPRD | Suprêmes délices | Belgium | 12 | 19 |
MEREP | Mère Paillarde | Canada | 13 | 30 |
BONAP | Bon app' | France | 17 | 77 |
QUEDE | Que Delícia | Brazil | 9 | 83 |
GOURL | Gourmet Lanchonetes | Brazil | 9 | 83 |
LAUGB | Laughing Bacchus Wine Cellars | Canada | 3 | 30 |
CENTC | Centro comercial Moctezuma | Mexico | 1 | 28 |
LONEP | Lonesome Pine Restaurant | USA | 8 | 122 |
RICAR | Ricardo Adocicados | Brazil | 11 | 83 |
RATTC | Rattlesnake Canyon Grocery | USA | 18 | 122 |
WHITC | White Clover Markets | USA | 14 | 122 |
OTTIK | Ottilies Käseladen | Germany | 10 | 122 |
QUEEN | Queen Cozinha | Brazil | 13 | 83 |
COMMI | Comércio Mineiro | Brazil | 5 | 83 |
GREAL | Great Lakes Food Market | USA | 11 | 122 |
RANK()
The previously examples were mostly to demonstrate the syntax and utility of window functions. Let us now move on more practical examples and functionality.
Going back to our first example (average unit price per category), assume that you want to know how each product’s price ranks against the rest of the product prices within the same category. Also let’s say that we want to assign the highest ranks to the most expensive product. We can do this utilizing the RANK()
function.
SELECT product_id, product_name, unit_price, category_id, AVG(unit_price) OVER(PARTITION BY category_id) AS average_unit_price_in_category, RANK() OVER (PARTITION BY category_id ORDER BY unit_price DESC ) as product_price_ranked_in_category FROM products WHERE not discontinued::bool;
This is the same as earlier with the addition of the latest line in selector. What we define there, is that we want to give a rank (RANK()
) to each record/product of the same category (PARTITION BY category_id
) based on their unit price (ORDER BY unit_price
) and that the most expensive product should be ranked as first (DESC
).
This is the outcome:
product_id | product_name | unit_price | category_id | average_unit_price_in_category | product_price_ranked_in_category |
---|---|---|---|---|---|
38 | Côte de Blaye | 263.5 | 1 | 46.02777777777778 | 1 |
43 | Ipoh Coffee | 46 | 1 | 46.02777777777778 | 2 |
35 | Steeleye Stout | 18 | 1 | 46.02777777777778 | 3 |
76 | Lakkalikööri | 18 | 1 | 46.02777777777778 | 3 |
39 | Chartreuse verte | 18 | 1 | 46.02777777777778 | 3 |
70 | Outback Lager | 15 | 1 | 46.02777777777778 | 6 |
67 | Laughing Lumberjack Lager | 14 | 1 | 46.02777777777778 | 7 |
34 | Sasquatch Ale | 14 | 1 | 46.02777777777778 | 7 |
75 | Rhönbräu Klosterbier | 7.75 | 1 | 46.02777777777778 | 9 |
63 | Vegie-spread | 43.9 | 2 | 22.990909229625355 | 1 |
8 | Northwoods Cranberry Sauce | 40 | 2 | 22.990909229625355 | 2 |
61 | Sirop d'érable | 28.5 | 2 | 22.990909229625355 | 3 |
6 | Grandma's Boysenberry Spread | 25 | 2 | 22.990909229625355 | 4 |
4 | Chef Anton's Cajun Seasoning | 22 | 2 | 22.990909229625355 | 5 |
65 | Louisiana Fiery Hot Pepper Sauce | 21.05 | 2 | 22.990909229625355 | 6 |
44 | Gula Malacca | 19.45 | 2 | 22.990909229625355 | 7 |
66 | Louisiana Hot Spiced Okra | 17 | 2 | 22.990909229625355 | 8 |
77 | Original Frankfurter grüne Soße | 13 | 2 | 22.990909229625355 | 9 |
15 | Genen Shouyu | 13 | 2 | 22.990909229625355 | 9 |
3 | Aniseed Syrup | 10 | 2 | 22.990909229625355 | 11 |
20 | Sir Rodney's Marmalade | 81 | 3 | 25.1600000674908 | 1 |
62 | Tarte au sucre | 49.3 | 3 | 25.1600000674908 | 2 |
27 | Schoggi Schokolade | 43.9 | 3 | 25.1600000674908 | 3 |
26 | Gumbär Gummibärchen | 31.23 | 3 | 25.1600000674908 | 4 |
49 | Maxilaku | 20 | 3 | 25.1600000674908 | 5 |
16 | Pavlova | 17.45 | 3 | 25.1600000674908 | 6 |
50 | Valkoinen suklaa | 16.25 | 3 | 25.1600000674908 | 7 |
25 | NuNuCa Nuß-Nougat-Creme | 14 | 3 | 25.1600000674908 | 8 |
48 | Chocolade | 12.75 | 3 | 25.1600000674908 | 9 |
68 | Scottish Longbreads | 12.5 | 3 | 25.1600000674908 | 10 |
21 | Sir Rodney's Scones | 10 | 3 | 25.1600000674908 | 11 |
47 | Zaanse koeken | 9.5 | 3 | 25.1600000674908 | 12 |
19 | Teatime Chocolate Biscuits | 9.2 | 3 | 25.1600000674908 | 13 |
59 | Raclette Courdavault | 55 | 4 | 28.729999923706053 | 1 |
12 | Queso Manchego La Pastora | 38 | 4 | 28.729999923706053 | 2 |
69 | Gudbrandsdalsost | 36 | 4 | 28.729999923706053 | 3 |
72 | Mozzarella di Giovanni | 34.8 | 4 | 28.729999923706053 | 4 |
60 | Camembert Pierrot | 34 | 4 | 28.729999923706053 | 5 |
32 | Mascarpone Fabioli | 32 | 4 | 28.729999923706053 | 6 |
71 | Flotemysost | 21.5 | 4 | 28.729999923706053 | 7 |
11 | Queso Cabrales | 21 | 4 | 28.729999923706053 | 8 |
31 | Gorgonzola Telino | 12.5 | 4 | 28.729999923706053 | 9 |
33 | Geitost | 2.5 | 4 | 28.729999923706053 | 10 |
56 | Gnocchi di nonna Alice | 38 | 5 | 21.291666666666668 | 1 |
64 | Wimmers gute Semmelknödel | 33.25 | 5 | 21.291666666666668 | 2 |
22 | Gustaf's Knäckebröd | 21 | 5 | 21.291666666666668 | 3 |
57 | Ravioli Angelo | 19.5 | 5 | 21.291666666666668 | 4 |
23 | Tunnbröd | 9 | 5 | 21.291666666666668 | 5 |
52 | Filo Mix | 7 | 5 | 21.291666666666668 | 6 |
55 | Pâté chinois | 24 | 6 | 15.724999904632568 | 1 |
54 | Tourtière | 7.45 | 6 | 15.724999904632568 | 2 |
51 | Manjimup Dried Apples | 53 | 7 | 29.0625 | 1 |
7 | Uncle Bob's Organic Dried Pears | 30 | 7 | 29.0625 | 2 |
14 | Tofu | 23.25 | 7 | 29.0625 | 3 |
74 | Longlife Tofu | 10 | 7 | 29.0625 | 4 |
18 | Carnarvon Tigers | 62.5 | 8 | 20.682499885559082 | 1 |
10 | Ikura | 31 | 8 | 20.682499885559082 | 2 |
37 | Gravad lax | 26 | 8 | 20.682499885559082 | 3 |
30 | Nord-Ost Matjeshering | 25.89 | 8 | 20.682499885559082 | 4 |
36 | Inlagd Sill | 19 | 8 | 20.682499885559082 | 5 |
40 | Boston Crab Meat | 18.4 | 8 | 20.682499885559082 | 6 |
73 | Röd Kaviar | 15 | 8 | 20.682499885559082 | 7 |
58 | Escargots de Bourgogne | 13.25 | 8 | 20.682499885559082 | 8 |
46 | Spegesild | 12 | 8 | 20.682499885559082 | 9 |
41 | Jack's New England Clam Chowder | 9.65 | 8 | 20.682499885559082 | 10 |
45 | Rogede sild | 9.5 | 8 | 20.682499885559082 | 11 |
13 | Konbu | 6 | 8 | 20.682499885559082 | 12 |
Notice how rows with the same value in unit price within the same category have the same rank and how the order is skipped to the actual rank in the next row (When you have for example two records with rank 2 the next one will have rank 4 and so on so forth). For each category the RANK() creates rankings and also allows us to keep track of duplicates. This is extremely powerful considering also how easy this construct is.
DENSE_RANK()
In the case when we need to keep the ranking complete and not skip any ranks when we have same ranks within the partition we can use DENSE_RANK(). This is the same as RANK() except the skipping ranks part. Let ‘s check them side by side.
SELECT product_id, product_name, unit_price, category_id, RANK() OVER (PARTITION BY category_id ORDER BY unit_price DESC ) as product_price_ranked_in_category, DENSE_RANK() OVER (PARTITION BY category_id ORDER BY unit_price DESC ) as dense_product_price_ranked_in_category FROM products WHERE not discontinued::bool;
Output:
product_id | product_name | unit_price | category_id | product_price_ranked_in_category | dense_product_price_ranked_in_category |
---|---|---|---|---|---|
38 | Côte de Blaye | 263.5 | 1 | 1 | 1 |
43 | Ipoh Coffee | 46 | 1 | 2 | 2 |
35 | Steeleye Stout | 18 | 1 | 3 | 3 |
76 | Lakkalikööri | 18 | 1 | 3 | 3 |
39 | Chartreuse verte | 18 | 1 | 3 | 3 |
70 | Outback Lager | 15 | 1 | 6 | 4 |
67 | Laughing Lumberjack Lager | 14 | 1 | 7 | 5 |
34 | Sasquatch Ale | 14 | 1 | 7 | 5 |
75 | Rhönbräu Klosterbier | 7.75 | 1 | 9 | 6 |
63 | Vegie-spread | 43.9 | 2 | 1 | 1 |
8 | Northwoods Cranberry Sauce | 40 | 2 | 2 | 2 |
61 | Sirop d'érable | 28.5 | 2 | 3 | 3 |
6 | Grandma's Boysenberry Spread | 25 | 2 | 4 | 4 |
4 | Chef Anton's Cajun Seasoning | 22 | 2 | 5 | 5 |
65 | Louisiana Fiery Hot Pepper Sauce | 21.05 | 2 | 6 | 6 |
44 | Gula Malacca | 19.45 | 2 | 7 | 7 |
66 | Louisiana Hot Spiced Okra | 17 | 2 | 8 | 8 |
77 | Original Frankfurter grüne Soße | 13 | 2 | 9 | 9 |
15 | Genen Shouyu | 13 | 2 | 9 | 9 |
3 | Aniseed Syrup | 10 | 2 | 11 | 10 |
20 | Sir Rodney's Marmalade | 81 | 3 | 1 | 1 |
62 | Tarte au sucre | 49.3 | 3 | 2 | 2 |
27 | Schoggi Schokolade | 43.9 | 3 | 3 | 3 |
26 | Gumbär Gummibärchen | 31.23 | 3 | 4 | 4 |
49 | Maxilaku | 20 | 3 | 5 | 5 |
16 | Pavlova | 17.45 | 3 | 6 | 6 |
50 | Valkoinen suklaa | 16.25 | 3 | 7 | 7 |
25 | NuNuCa Nuß-Nougat-Creme | 14 | 3 | 8 | 8 |
48 | Chocolade | 12.75 | 3 | 9 | 9 |
68 | Scottish Longbreads | 12.5 | 3 | 10 | 10 |
21 | Sir Rodney's Scones | 10 | 3 | 11 | 11 |
47 | Zaanse koeken | 9.5 | 3 | 12 | 12 |
19 | Teatime Chocolate Biscuits | 9.2 | 3 | 13 | 13 |
59 | Raclette Courdavault | 55 | 4 | 1 | 1 |
12 | Queso Manchego La Pastora | 38 | 4 | 2 | 2 |
69 | Gudbrandsdalsost | 36 | 4 | 3 | 3 |
72 | Mozzarella di Giovanni | 34.8 | 4 | 4 | 4 |
60 | Camembert Pierrot | 34 | 4 | 5 | 5 |
32 | Mascarpone Fabioli | 32 | 4 | 6 | 6 |
71 | Flotemysost | 21.5 | 4 | 7 | 7 |
11 | Queso Cabrales | 21 | 4 | 8 | 8 |
31 | Gorgonzola Telino | 12.5 | 4 | 9 | 9 |
33 | Geitost | 2.5 | 4 | 10 | 10 |
56 | Gnocchi di nonna Alice | 38 | 5 | 1 | 1 |
64 | Wimmers gute Semmelknödel | 33.25 | 5 | 2 | 2 |
22 | Gustaf's Knäckebröd | 21 | 5 | 3 | 3 |
57 | Ravioli Angelo | 19.5 | 5 | 4 | 4 |
23 | Tunnbröd | 9 | 5 | 5 | 5 |
52 | Filo Mix | 7 | 5 | 6 | 6 |
55 | Pâté chinois | 24 | 6 | 1 | 1 |
54 | Tourtière | 7.45 | 6 | 2 | 2 |
51 | Manjimup Dried Apples | 53 | 7 | 1 | 1 |
7 | Uncle Bob's Organic Dried Pears | 30 | 7 | 2 | 2 |
14 | Tofu | 23.25 | 7 | 3 | 3 |
74 | Longlife Tofu | 10 | 7 | 4 | 4 |
18 | Carnarvon Tigers | 62.5 | 8 | 1 | 1 |
10 | Ikura | 31 | 8 | 2 | 2 |
37 | Gravad lax | 26 | 8 | 3 | 3 |
30 | Nord-Ost Matjeshering | 25.89 | 8 | 4 | 4 |
36 | Inlagd Sill | 19 | 8 | 5 | 5 |
40 | Boston Crab Meat | 18.4 | 8 | 6 | 6 |
73 | Röd Kaviar | 15 | 8 | 7 | 7 |
58 | Escargots de Bourgogne | 13.25 | 8 | 8 | 8 |
46 | Spegesild | 12 | 8 | 9 | 9 |
41 | Jack's New England Clam Chowder | 9.65 | 8 | 10 | 10 |
45 | Rogede sild | 9.5 | 8 | 11 | 11 |
13 | Konbu | 6 | 8 | 12 | 12 |
By checking the last two columns we can see that the difference lies on the ranking.
ROW_NUMBER()
When we simple need a row ordering within the partition we can use ROW_NUMBER()
. This will simple follow the ordering and provide a “ranking”.
SELECT product_id, product_name, unit_price, category_id, RANK() OVER (PARTITION BY category_id ORDER BY unit_price DESC ) as product_price_ranked_in_category, DENSE_RANK() OVER (PARTITION BY category_id ORDER BY unit_price DESC ) as dense_product_price_ranked_in_category, ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY unit_price DESC ) as row_number_in_category FROM products WHERE not discontinued::bool;
Check the last three columns to see how RANK(), DENSE_RANK(), and ROW_NUMBER() behave over the same partitioning.
product_id | product_name | unit_price | category_id | product_price_ranked_in_category | dense_product_price_ranked_in_category | row_number_in_category |
---|---|---|---|---|---|---|
38 | Côte de Blaye | 263.5 | 1 | 1 | 1 | 1 |
43 | Ipoh Coffee | 46 | 1 | 2 | 2 | 2 |
35 | Steeleye Stout | 18 | 1 | 3 | 3 | 3 |
76 | Lakkalikööri | 18 | 1 | 3 | 3 | 4 |
39 | Chartreuse verte | 18 | 1 | 3 | 3 | 5 |
70 | Outback Lager | 15 | 1 | 6 | 4 | 6 |
67 | Laughing Lumberjack Lager | 14 | 1 | 7 | 5 | 7 |
34 | Sasquatch Ale | 14 | 1 | 7 | 5 | 8 |
75 | Rhönbräu Klosterbier | 7.75 | 1 | 9 | 6 | 9 |
63 | Vegie-spread | 43.9 | 2 | 1 | 1 | 1 |
8 | Northwoods Cranberry Sauce | 40 | 2 | 2 | 2 | 2 |
61 | Sirop d'érable | 28.5 | 2 | 3 | 3 | 3 |
6 | Grandma's Boysenberry Spread | 25 | 2 | 4 | 4 | 4 |
4 | Chef Anton's Cajun Seasoning | 22 | 2 | 5 | 5 | 5 |
65 | Louisiana Fiery Hot Pepper Sauce | 21.05 | 2 | 6 | 6 | 6 |
44 | Gula Malacca | 19.45 | 2 | 7 | 7 | 7 |
66 | Louisiana Hot Spiced Okra | 17 | 2 | 8 | 8 | 8 |
77 | Original Frankfurter grüne Soße | 13 | 2 | 9 | 9 | 9 |
15 | Genen Shouyu | 13 | 2 | 9 | 9 | 10 |
3 | Aniseed Syrup | 10 | 2 | 11 | 10 | 11 |
20 | Sir Rodney's Marmalade | 81 | 3 | 1 | 1 | 1 |
62 | Tarte au sucre | 49.3 | 3 | 2 | 2 | 2 |
27 | Schoggi Schokolade | 43.9 | 3 | 3 | 3 | 3 |
26 | Gumbär Gummibärchen | 31.23 | 3 | 4 | 4 | 4 |
49 | Maxilaku | 20 | 3 | 5 | 5 | 5 |
16 | Pavlova | 17.45 | 3 | 6 | 6 | 6 |
50 | Valkoinen suklaa | 16.25 | 3 | 7 | 7 | 7 |
25 | NuNuCa Nuß-Nougat-Creme | 14 | 3 | 8 | 8 | 8 |
48 | Chocolade | 12.75 | 3 | 9 | 9 | 9 |
68 | Scottish Longbreads | 12.5 | 3 | 10 | 10 | 10 |
21 | Sir Rodney's Scones | 10 | 3 | 11 | 11 | 11 |
47 | Zaanse koeken | 9.5 | 3 | 12 | 12 | 12 |
19 | Teatime Chocolate Biscuits | 9.2 | 3 | 13 | 13 | 13 |
59 | Raclette Courdavault | 55 | 4 | 1 | 1 | 1 |
12 | Queso Manchego La Pastora | 38 | 4 | 2 | 2 | 2 |
69 | Gudbrandsdalsost | 36 | 4 | 3 | 3 | 3 |
72 | Mozzarella di Giovanni | 34.8 | 4 | 4 | 4 | 4 |
60 | Camembert Pierrot | 34 | 4 | 5 | 5 | 5 |
32 | Mascarpone Fabioli | 32 | 4 | 6 | 6 | 6 |
71 | Flotemysost | 21.5 | 4 | 7 | 7 | 7 |
11 | Queso Cabrales | 21 | 4 | 8 | 8 | 8 |
31 | Gorgonzola Telino | 12.5 | 4 | 9 | 9 | 9 |
33 | Geitost | 2.5 | 4 | 10 | 10 | 10 |
56 | Gnocchi di nonna Alice | 38 | 5 | 1 | 1 | 1 |
64 | Wimmers gute Semmelknödel | 33.25 | 5 | 2 | 2 | 2 |
22 | Gustaf's Knäckebröd | 21 | 5 | 3 | 3 | 3 |
57 | Ravioli Angelo | 19.5 | 5 | 4 | 4 | 4 |
23 | Tunnbröd | 9 | 5 | 5 | 5 | 5 |
52 | Filo Mix | 7 | 5 | 6 | 6 | 6 |
55 | Pâté chinois | 24 | 6 | 1 | 1 | 1 |
54 | Tourtière | 7.45 | 6 | 2 | 2 | 2 |
51 | Manjimup Dried Apples | 53 | 7 | 1 | 1 | 1 |
7 | Uncle Bob's Organic Dried Pears | 30 | 7 | 2 | 2 | 2 |
14 | Tofu | 23.25 | 7 | 3 | 3 | 3 |
74 | Longlife Tofu | 10 | 7 | 4 | 4 | 4 |
18 | Carnarvon Tigers | 62.5 | 8 | 1 | 1 | 1 |
10 | Ikura | 31 | 8 | 2 | 2 | 2 |
37 | Gravad lax | 26 | 8 | 3 | 3 | 3 |
30 | Nord-Ost Matjeshering | 25.89 | 8 | 4 | 4 | 4 |
36 | Inlagd Sill | 19 | 8 | 5 | 5 | 5 |
40 | Boston Crab Meat | 18.4 | 8 | 6 | 6 | 6 |
73 | Röd Kaviar | 15 | 8 | 7 | 7 | 7 |
58 | Escargots de Bourgogne | 13.25 | 8 | 8 | 8 | 8 |
46 | Spegesild | 12 | 8 | 9 | 9 | 9 |
41 | Jack's New England Clam Chowder | 9.65 | 8 | 10 | 10 | 10 |
45 | Rogede sild | 9.5 | 8 | 11 | 11 | 11 |
13 | Konbu | 6 | 8 | 12 | 12 | 12 |
PERCENT_RANK()
The PERCENT_RANK()
function returns a percentile ranking number which ranges from zero to one and calculates the percentile ranking of rows in a result set.
Syntax is similar, let’s still use the same example with unit price and categories.
SELECT product_id, product_name, unit_price, category_id, RANK() OVER (PARTITION BY category_id ORDER BY unit_price DESC ) as product_price_ranked_in_category, PERCENT_RANK() OVER (PARTITION BY category_id ORDER BY unit_price DESC ) as percent_rank FROM products WHERE not discontinued::bool;
This will produce the following:
product_id | product_name | unit_price | category_id | product_price_ranked_in_category | percent_rank |
---|---|---|---|---|---|
38 | Côte de Blaye | 263.5 | 1 | 1 | 0 |
43 | Ipoh Coffee | 46 | 1 | 2 | 0.125 |
35 | Steeleye Stout | 18 | 1 | 3 | 0.25 |
76 | Lakkalikööri | 18 | 1 | 3 | 0.25 |
39 | Chartreuse verte | 18 | 1 | 3 | 0.25 |
70 | Outback Lager | 15 | 1 | 6 | 0.625 |
67 | Laughing Lumberjack Lager | 14 | 1 | 7 | 0.75 |
34 | Sasquatch Ale | 14 | 1 | 7 | 0.75 |
75 | Rhönbräu Klosterbier | 7.75 | 1 | 9 | 1 |
63 | Vegie-spread | 43.9 | 2 | 1 | 0 |
8 | Northwoods Cranberry Sauce | 40 | 2 | 2 | 0.1 |
61 | Sirop d'érable | 28.5 | 2 | 3 | 0.2 |
6 | Grandma's Boysenberry Spread | 25 | 2 | 4 | 0.3 |
4 | Chef Anton's Cajun Seasoning | 22 | 2 | 5 | 0.4 |
65 | Louisiana Fiery Hot Pepper Sauce | 21.05 | 2 | 6 | 0.5 |
44 | Gula Malacca | 19.45 | 2 | 7 | 0.6 |
66 | Louisiana Hot Spiced Okra | 17 | 2 | 8 | 0.7 |
77 | Original Frankfurter grüne Soße | 13 | 2 | 9 | 0.8 |
15 | Genen Shouyu | 13 | 2 | 9 | 0.8 |
3 | Aniseed Syrup | 10 | 2 | 11 | 1 |
20 | Sir Rodney's Marmalade | 81 | 3 | 1 | 0 |
62 | Tarte au sucre | 49.3 | 3 | 2 | 0.08333333333333333 |
27 | Schoggi Schokolade | 43.9 | 3 | 3 | 0.16666666666666666 |
26 | Gumbär Gummibärchen | 31.23 | 3 | 4 | 0.25 |
49 | Maxilaku | 20 | 3 | 5 | 0.3333333333333333 |
16 | Pavlova | 17.45 | 3 | 6 | 0.4166666666666667 |
50 | Valkoinen suklaa | 16.25 | 3 | 7 | 0.5 |
25 | NuNuCa Nuß-Nougat-Creme | 14 | 3 | 8 | 0.5833333333333334 |
48 | Chocolade | 12.75 | 3 | 9 | 0.6666666666666666 |
68 | Scottish Longbreads | 12.5 | 3 | 10 | 0.75 |
21 | Sir Rodney's Scones | 10 | 3 | 11 | 0.8333333333333334 |
47 | Zaanse koeken | 9.5 | 3 | 12 | 0.9166666666666666 |
19 | Teatime Chocolate Biscuits | 9.2 | 3 | 13 | 1 |
59 | Raclette Courdavault | 55 | 4 | 1 | 0 |
12 | Queso Manchego La Pastora | 38 | 4 | 2 | 0.1111111111111111 |
69 | Gudbrandsdalsost | 36 | 4 | 3 | 0.2222222222222222 |
72 | Mozzarella di Giovanni | 34.8 | 4 | 4 | 0.3333333333333333 |
60 | Camembert Pierrot | 34 | 4 | 5 | 0.4444444444444444 |
32 | Mascarpone Fabioli | 32 | 4 | 6 | 0.5555555555555556 |
71 | Flotemysost | 21.5 | 4 | 7 | 0.6666666666666666 |
11 | Queso Cabrales | 21 | 4 | 8 | 0.7777777777777778 |
31 | Gorgonzola Telino | 12.5 | 4 | 9 | 0.8888888888888888 |
33 | Geitost | 2.5 | 4 | 10 | 1 |
56 | Gnocchi di nonna Alice | 38 | 5 | 1 | 0 |
64 | Wimmers gute Semmelknödel | 33.25 | 5 | 2 | 0.2 |
22 | Gustaf's Knäckebröd | 21 | 5 | 3 | 0.4 |
57 | Ravioli Angelo | 19.5 | 5 | 4 | 0.6 |
23 | Tunnbröd | 9 | 5 | 5 | 0.8 |
52 | Filo Mix | 7 | 5 | 6 | 1 |
55 | Pâté chinois | 24 | 6 | 1 | 0 |
54 | Tourtière | 7.45 | 6 | 2 | 1 |
51 | Manjimup Dried Apples | 53 | 7 | 1 | 0 |
7 | Uncle Bob's Organic Dried Pears | 30 | 7 | 2 | 0.3333333333333333 |
14 | Tofu | 23.25 | 7 | 3 | 0.6666666666666666 |
74 | Longlife Tofu | 10 | 7 | 4 | 1 |
18 | Carnarvon Tigers | 62.5 | 8 | 1 | 0 |
10 | Ikura | 31 | 8 | 2 | 0.09090909090909091 |
37 | Gravad lax | 26 | 8 | 3 | 0.18181818181818182 |
30 | Nord-Ost Matjeshering | 25.89 | 8 | 4 | 0.2727272727272727 |
36 | Inlagd Sill | 19 | 8 | 5 | 0.36363636363636365 |
40 | Boston Crab Meat | 18.4 | 8 | 6 | 0.45454545454545453 |
73 | Röd Kaviar | 15 | 8 | 7 | 0.5454545454545454 |
58 | Escargots de Bourgogne | 13.25 | 8 | 8 | 0.6363636363636364 |
46 | Spegesild | 12 | 8 | 9 | 0.7272727272727273 |
41 | Jack's New England Clam Chowder | 9.65 | 8 | 10 | 0.8181818181818182 |
45 | Rogede sild | 9.5 | 8 | 11 | 0.9090909090909091 |
13 | Konbu | 6 | 8 | 12 | 1 |
Let’s examine category 1 for example. What this tells us is that the item with ID=38 is cheapest than 0% of the items in this category. The item with ID=75 is cheapest than 100% of the items in this category. The items with IDS 34 and 67 are cheapest that 75% of the items in this category and so on so forth.
CUME_DIST()
CUME_DIST()
is a window function which calculates the cumulative distribution of a row value within the partition. The output of this function is a number which represents the number of rows with values less than or equal to the current row’s value divided by the total number of rows.
Assume the example below where in the CTE
we simple calculate the order per country, where country here is the customer’s country.
WITH country_orders (country, num_of_orders) AS ( SELECT country, count(order_id) FROM orders JOIN customers c on orders.customer_id = c.customer_id GROUP BY country ) SELECT country, num_of_orders, CUME_DIST() OVER ( ORDER BY num_of_orders ) FROM country_orders;
Note: We are skipping PARTITION_BY
here since we already have created the subgroups in CTE
. We could of course do the same with PARTITION_BY
and a DISTINCT
without the CTE
.
The output is:
country | num_of_orders | cume_dist |
---|---|---|
Norway | 6 | 0.047619047619047616 |
Poland | 7 | 0.09523809523809523 |
Portugal | 13 | 0.14285714285714285 |
Argentina | 16 | 0.19047619047619047 |
Denmark | 18 | 0.2857142857142857 |
Switzerland | 18 | 0.2857142857142857 |
Belgium | 19 | 0.38095238095238093 |
Ireland | 19 | 0.38095238095238093 |
Finland | 22 | 0.42857142857142855 |
Spain | 23 | 0.47619047619047616 |
Mexico | 28 | 0.5714285714285714 |
Italy | 28 | 0.5714285714285714 |
Canada | 30 | 0.6190476190476191 |
Sweden | 37 | 0.6666666666666666 |
Austria | 40 | 0.7142857142857143 |
Venezuela | 46 | 0.7619047619047619 |
UK | 56 | 0.8095238095238095 |
France | 77 | 0.8571428571428571 |
Brazil | 83 | 0.9047619047619048 |
Germany | 122 | 1 |
USA | 122 | 1 |
Norway has 6 orders and is the only country with 6 orders (1 record). The total number of rows in result set is 21. The CUME_DIST()
will perform: 1 / 21 = 0.04 …
Poland has 7 orders. The countries that have equal or less orders than 7 are 2 (Norway and Poland). Thus the calculation will be : 2 / 21 = 0.09….
Same logic applies to the rest of the rows in the result set.
NTILE()
This function allows as to do some bucketing/binning in the result-set. The number of buckets is provided as argument. It will attempt to break the results/or partition of the results into a specified number of buckets, which will have approximately the same number of rows.
Let us go back to the unit price example.
SELECT product_id, product_name, unit_price, category_id, NTILE(4) OVER (PARTITION BY category_id ORDER BY unit_price DESC ) as price_group FROM products WHERE not discontinued::bool;
For each category we want here to create subgroups (4 in our case) which will be specified from the ordering of unit price.
product_id | product_name | unit_price | category_id | price_group |
---|---|---|---|---|
38 | Côte de Blaye | 263.5 | 1 | 1 |
43 | Ipoh Coffee | 46 | 1 | 1 |
35 | Steeleye Stout | 18 | 1 | 1 |
76 | Lakkalikööri | 18 | 1 | 2 |
39 | Chartreuse verte | 18 | 1 | 2 |
70 | Outback Lager | 15 | 1 | 3 |
67 | Laughing Lumberjack Lager | 14 | 1 | 3 |
34 | Sasquatch Ale | 14 | 1 | 4 |
75 | Rhönbräu Klosterbier | 7.75 | 1 | 4 |
63 | Vegie-spread | 43.9 | 2 | 1 |
8 | Northwoods Cranberry Sauce | 40 | 2 | 1 |
61 | Sirop d'érable | 28.5 | 2 | 1 |
6 | Grandma's Boysenberry Spread | 25 | 2 | 2 |
4 | Chef Anton's Cajun Seasoning | 22 | 2 | 2 |
65 | Louisiana Fiery Hot Pepper Sauce | 21.05 | 2 | 2 |
44 | Gula Malacca | 19.45 | 2 | 3 |
66 | Louisiana Hot Spiced Okra | 17 | 2 | 3 |
77 | Original Frankfurter grüne Soße | 13 | 2 | 3 |
15 | Genen Shouyu | 13 | 2 | 4 |
3 | Aniseed Syrup | 10 | 2 | 4 |
20 | Sir Rodney's Marmalade | 81 | 3 | 1 |
62 | Tarte au sucre | 49.3 | 3 | 1 |
27 | Schoggi Schokolade | 43.9 | 3 | 1 |
26 | Gumbär Gummibärchen | 31.23 | 3 | 1 |
49 | Maxilaku | 20 | 3 | 2 |
16 | Pavlova | 17.45 | 3 | 2 |
50 | Valkoinen suklaa | 16.25 | 3 | 2 |
25 | NuNuCa Nuß-Nougat-Creme | 14 | 3 | 3 |
48 | Chocolade | 12.75 | 3 | 3 |
68 | Scottish Longbreads | 12.5 | 3 | 3 |
21 | Sir Rodney's Scones | 10 | 3 | 4 |
47 | Zaanse koeken | 9.5 | 3 | 4 |
19 | Teatime Chocolate Biscuits | 9.2 | 3 | 4 |
59 | Raclette Courdavault | 55 | 4 | 1 |
12 | Queso Manchego La Pastora | 38 | 4 | 1 |
69 | Gudbrandsdalsost | 36 | 4 | 1 |
72 | Mozzarella di Giovanni | 34.8 | 4 | 2 |
60 | Camembert Pierrot | 34 | 4 | 2 |
32 | Mascarpone Fabioli | 32 | 4 | 2 |
71 | Flotemysost | 21.5 | 4 | 3 |
11 | Queso Cabrales | 21 | 4 | 3 |
31 | Gorgonzola Telino | 12.5 | 4 | 4 |
33 | Geitost | 2.5 | 4 | 4 |
56 | Gnocchi di nonna Alice | 38 | 5 | 1 |
64 | Wimmers gute Semmelknödel | 33.25 | 5 | 1 |
22 | Gustaf's Knäckebröd | 21 | 5 | 2 |
57 | Ravioli Angelo | 19.5 | 5 | 2 |
23 | Tunnbröd | 9 | 5 | 3 |
52 | Filo Mix | 7 | 5 | 4 |
55 | Pâté chinois | 24 | 6 | 1 |
54 | Tourtière | 7.45 | 6 | 2 |
51 | Manjimup Dried Apples | 53 | 7 | 1 |
7 | Uncle Bob's Organic Dried Pears | 30 | 7 | 2 |
14 | Tofu | 23.25 | 7 | 3 |
74 | Longlife Tofu | 10 | 7 | 4 |
18 | Carnarvon Tigers | 62.5 | 8 | 1 |
10 | Ikura | 31 | 8 | 1 |
37 | Gravad lax | 26 | 8 | 1 |
30 | Nord-Ost Matjeshering | 25.89 | 8 | 2 |
36 | Inlagd Sill | 19 | 8 | 2 |
40 | Boston Crab Meat | 18.4 | 8 | 2 |
73 | Röd Kaviar | 15 | 8 | 3 |
58 | Escargots de Bourgogne | 13.25 | 8 | 3 |
46 | Spegesild | 12 | 8 | 3 |
41 | Jack's New England Clam Chowder | 9.65 | 8 | 4 |
45 | Rogede sild | 9.5 | 8 | 4 |
13 | Konbu | 6 | 8 | 4 |
Checking the price_group column we can see SQL attempts to make 4 groups of similar size for each category.
LAG()
Very often used in interview questions, LAG()
allows us access the previous row of the current row within a working set. Simply putted we can access data from the previous row. This is extremely powerful when we want to find differences between current and previous rows.
It can accept an offset where we can define the number of previous rows from which to access data, defaults to 1 if skipped, and it can also accept a default value which is useful for the records that previous rows does not exist (first row in the working set), if skipped it will return NULL
. We should be careful with the default since this will affect the calculation which we want to perform later.
Let us attempt to calculate how much time is passing on average for each customer to make an order.
Note: We are making the assumption, that the company opened at 01-01-1995 and all the customers were registered on this day. That means that for every client’s first order we should calculate from 01-01-1995 the passed days.
SELECT customer_id, order_date, LAG(order_date, 1 ,'1995-01-01') OVER (PARTITION BY customer_id ORDER BY order_date) AS previous_order, order_date - LAG(order_date, 1 ,'1995-01-01') OVER (PARTITION BY customer_id ORDER BY order_date) as difference_in_days FROM orders ORDER BY customer_id;
The second and third column are not needed for our example. We display them for demo purposes and to have LAG()
a bit more readable.
We are getting the order_date and we deduct the previous (LAG()
with 1 offset) order_date of the same customer (PARTITION_BY
) based on the order of order_date
. In the case we do not have a previous record we will assign 01-01-1995 as the default value. The output of the above is:
customer_id | order_date | previous_order | difference_in_days |
---|---|---|---|
ALFKI | 1997-08-25 | 1995-01-01 | 967 |
ALFKI | 1997-10-03 | 1997-08-25 | 39 |
ALFKI | 1997-10-13 | 1997-10-03 | 10 |
ALFKI | 1998-01-15 | 1997-10-13 | 94 |
ALFKI | 1998-03-16 | 1998-01-15 | 60 |
ALFKI | 1998-04-09 | 1998-03-16 | 24 |
ANATR | 1996-09-18 | 1995-01-01 | 626 |
ANATR | 1997-08-08 | 1996-09-18 | 324 |
ANATR | 1997-11-28 | 1997-08-08 | 112 |
ANATR | 1998-03-04 | 1997-11-28 | 96 |
ANTON | 1996-11-27 | 1995-01-01 | 696 |
ANTON | 1997-04-15 | 1996-11-27 | 139 |
ANTON | 1997-05-13 | 1997-04-15 | 28 |
ANTON | 1997-06-19 | 1997-05-13 | 37 |
ANTON | 1997-09-22 | 1997-06-19 | 95 |
ANTON | 1997-09-25 | 1997-09-22 | 3 |
ANTON | 1998-01-28 | 1997-09-25 | 125 |
AROUT | 1996-11-15 | 1995-01-01 | 684 |
AROUT | 1996-12-16 | 1996-11-15 | 31 |
AROUT | 1997-02-21 | 1996-12-16 | 67 |
AROUT | 1997-06-04 | 1997-02-21 | 103 |
AROUT | 1997-10-16 | 1997-06-04 | 134 |
AROUT | 1997-11-14 | 1997-10-16 | 29 |
AROUT | 1997-11-17 | 1997-11-14 | 3 |
AROUT | 1997-12-08 | 1997-11-17 | 21 |
AROUT | 1997-12-24 | 1997-12-08 | 16 |
AROUT | 1998-02-02 | 1997-12-24 | 40 |
AROUT | 1998-03-03 | 1998-02-02 | 29 |
AROUT | 1998-03-16 | 1998-03-03 | 13 |
AROUT | 1998-04-10 | 1998-03-16 | 25 |
BERGS | 1996-08-12 | 1995-01-01 | 589 |
BERGS | 1996-08-14 | 1996-08-12 | 2 |
BERGS | 1996-12-16 | 1996-08-14 | 124 |
BERGS | 1997-02-12 | 1996-12-16 | 58 |
BERGS | 1997-02-13 | 1997-02-12 | 1 |
BERGS | 1997-05-01 | 1997-02-13 | 77 |
BERGS | 1997-06-18 | 1997-05-01 | 48 |
BERGS | 1997-08-11 | 1997-06-18 | 54 |
BERGS | 1997-09-02 | 1997-08-11 | 22 |
BERGS | 1997-09-17 | 1997-09-02 | 15 |
BERGS | 1997-10-01 | 1997-09-17 | 14 |
BERGS | 1997-11-07 | 1997-10-01 | 37 |
BERGS | 1997-12-16 | 1997-11-07 | 39 |
BERGS | 1998-01-16 | 1997-12-16 | 31 |
BERGS | 1998-01-28 | 1998-01-16 | 12 |
BERGS | 1998-02-03 | 1998-01-28 | 6 |
BERGS | 1998-02-06 | 1998-02-03 | 3 |
BERGS | 1998-03-04 | 1998-02-06 | 26 |
BLAUS | 1997-04-09 | 1995-01-01 | 829 |
BLAUS | 1997-04-17 | 1997-04-09 | 8 |
BLAUS | 1997-06-27 | 1997-04-17 | 71 |
BLAUS | 1997-07-29 | 1997-06-27 | 32 |
BLAUS | 1998-01-27 | 1997-07-29 | 182 |
BLAUS | 1998-03-17 | 1998-01-27 | 49 |
BLAUS | 1998-04-29 | 1998-03-17 | 43 |
BLONP | 1996-07-25 | 1995-01-01 | 571 |
BLONP | 1996-09-04 | 1996-07-25 | 41 |
BLONP | 1996-11-22 | 1996-09-04 | 79 |
BLONP | 1997-02-05 | 1996-11-22 | 75 |
BLONP | 1997-02-18 | 1997-02-05 | 13 |
BLONP | 1997-06-05 | 1997-02-18 | 107 |
BLONP | 1997-06-12 | 1997-06-05 | 7 |
BLONP | 1997-06-30 | 1997-06-12 | 18 |
BLONP | 1997-08-12 | 1997-06-30 | 43 |
BLONP | 1997-09-23 | 1997-08-12 | 42 |
BLONP | 1998-01-12 | 1997-09-23 | 111 |
BOLID | 1996-10-10 | 1995-01-01 | 648 |
BOLID | 1997-12-29 | 1996-10-10 | 445 |
BOLID | 1998-03-24 | 1997-12-29 | 85 |
BONAP | 1996-10-16 | 1995-01-01 | 654 |
BONAP | 1996-10-29 | 1996-10-16 | 13 |
BONAP | 1996-11-25 | 1996-10-29 | 27 |
BONAP | 1997-03-11 | 1996-11-25 | 106 |
BONAP | 1997-04-18 | 1997-03-11 | 38 |
BONAP | 1997-05-02 | 1997-04-18 | 14 |
BONAP | 1997-09-10 | 1997-05-02 | 131 |
BONAP | 1997-10-23 | 1997-09-10 | 43 |
BONAP | 1997-11-05 | 1997-10-23 | 13 |
BONAP | 1997-11-06 | 1997-11-05 | 1 |
BONAP | 1997-11-26 | 1997-11-06 | 20 |
BONAP | 1998-01-12 | 1997-11-26 | 47 |
BONAP | 1998-02-05 | 1998-01-12 | 24 |
BONAP | 1998-02-09 | 1998-02-05 | 4 |
BONAP | 1998-03-06 | 1998-02-09 | 25 |
BONAP | 1998-03-11 | 1998-03-06 | 5 |
BONAP | 1998-05-06 | 1998-03-11 | 56 |
BOTTM | 1996-12-20 | 1995-01-01 | 719 |
BOTTM | 1997-01-10 | 1996-12-20 | 21 |
BOTTM | 1997-01-10 | 1997-01-10 | 0 |
BOTTM | 1997-01-30 | 1997-01-10 | 20 |
BOTTM | 1997-04-01 | 1997-01-30 | 61 |
BOTTM | 1997-11-14 | 1997-04-01 | 227 |
BOTTM | 1998-03-02 | 1997-11-14 | 108 |
BOTTM | 1998-03-12 | 1998-03-02 | 10 |
BOTTM | 1998-03-13 | 1998-03-12 | 1 |
BOTTM | 1998-03-25 | 1998-03-13 | 12 |
BOTTM | 1998-03-27 | 1998-03-25 | 2 |
BOTTM | 1998-04-16 | 1998-03-27 | 20 |
BOTTM | 1998-04-23 | 1998-04-16 | 7 |
BOTTM | 1998-04-24 | 1998-04-23 | 1 |
BSBEV | 1996-08-26 | 1995-01-01 | 603 |
BSBEV | 1997-03-11 | 1996-08-26 | 197 |
BSBEV | 1997-03-24 | 1997-03-11 | 13 |
BSBEV | 1997-05-15 | 1997-03-24 | 52 |
BSBEV | 1997-05-16 | 1997-05-15 | 1 |
BSBEV | 1997-06-24 | 1997-05-16 | 39 |
BSBEV | 1997-07-15 | 1997-06-24 | 21 |
BSBEV | 1998-03-11 | 1997-07-15 | 239 |
BSBEV | 1998-03-13 | 1998-03-11 | 2 |
BSBEV | 1998-04-14 | 1998-03-13 | 32 |
CACTU | 1997-04-29 | 1995-01-01 | 849 |
CACTU | 1997-12-17 | 1997-04-29 | 232 |
CACTU | 1998-01-07 | 1997-12-17 | 21 |
CACTU | 1998-02-11 | 1998-01-07 | 35 |
CACTU | 1998-03-10 | 1998-02-11 | 27 |
CACTU | 1998-04-28 | 1998-03-10 | 49 |
CENTC | 1996-07-18 | 1995-01-01 | 564 |
CHOPS | 1996-07-11 | 1995-01-01 | 557 |
CHOPS | 1996-12-03 | 1996-07-11 | 145 |
CHOPS | 1997-04-28 | 1996-12-03 | 146 |
CHOPS | 1997-11-06 | 1997-04-28 | 192 |
CHOPS | 1997-11-19 | 1997-11-06 | 13 |
CHOPS | 1998-03-20 | 1997-11-19 | 121 |
CHOPS | 1998-04-16 | 1998-03-20 | 27 |
CHOPS | 1998-04-22 | 1998-04-16 | 6 |
COMMI | 1996-08-27 | 1995-01-01 | 604 |
COMMI | 1997-03-06 | 1996-08-27 | 191 |
COMMI | 1997-04-02 | 1997-03-06 | 27 |
COMMI | 1998-03-23 | 1997-04-02 | 355 |
COMMI | 1998-04-22 | 1998-03-23 | 30 |
CONSH | 1997-02-04 | 1995-01-01 | 765 |
CONSH | 1997-03-03 | 1997-02-04 | 27 |
CONSH | 1998-01-23 | 1997-03-03 | 326 |
DRACD | 1996-11-26 | 1995-01-01 | 695 |
DRACD | 1996-12-23 | 1996-11-26 | 27 |
DRACD | 1997-12-25 | 1996-12-23 | 367 |
DRACD | 1998-01-09 | 1997-12-25 | 15 |
DRACD | 1998-04-20 | 1998-01-09 | 101 |
DRACD | 1998-05-04 | 1998-04-20 | 14 |
DUMON | 1996-09-20 | 1995-01-01 | 628 |
DUMON | 1997-07-24 | 1996-09-20 | 307 |
DUMON | 1997-09-26 | 1997-07-24 | 64 |
DUMON | 1998-02-16 | 1997-09-26 | 143 |
EASTC | 1996-11-26 | 1995-01-01 | 695 |
EASTC | 1997-01-01 | 1996-11-26 | 36 |
EASTC | 1997-05-09 | 1997-01-01 | 128 |
EASTC | 1997-11-03 | 1997-05-09 | 178 |
EASTC | 1998-03-31 | 1997-11-03 | 148 |
EASTC | 1998-04-15 | 1998-03-31 | 15 |
EASTC | 1998-04-24 | 1998-04-15 | 9 |
EASTC | 1998-04-28 | 1998-04-24 | 4 |
ERNSH | 1996-07-17 | 1995-01-01 | 563 |
ERNSH | 1996-07-23 | 1996-07-17 | 6 |
ERNSH | 1996-11-11 | 1996-07-23 | 111 |
ERNSH | 1996-11-29 | 1996-11-11 | 18 |
ERNSH | 1996-12-13 | 1996-11-29 | 14 |
ERNSH | 1996-12-23 | 1996-12-13 | 10 |
ERNSH | 1997-01-02 | 1996-12-23 | 10 |
ERNSH | 1997-01-03 | 1997-01-02 | 1 |
ERNSH | 1997-01-30 | 1997-01-03 | 27 |
ERNSH | 1997-02-11 | 1997-01-30 | 12 |
ERNSH | 1997-04-22 | 1997-02-11 | 70 |
ERNSH | 1997-06-17 | 1997-04-22 | 56 |
ERNSH | 1997-07-10 | 1997-06-17 | 23 |
ERNSH | 1997-08-15 | 1997-07-10 | 36 |
ERNSH | 1997-09-12 | 1997-08-15 | 28 |
ERNSH | 1997-10-09 | 1997-09-12 | 27 |
ERNSH | 1997-12-03 | 1997-10-09 | 55 |
ERNSH | 1997-12-10 | 1997-12-03 | 7 |
ERNSH | 1997-12-11 | 1997-12-10 | 1 |
ERNSH | 1997-12-15 | 1997-12-11 | 4 |
ERNSH | 1997-12-24 | 1997-12-15 | 9 |
ERNSH | 1998-01-16 | 1997-12-24 | 23 |
ERNSH | 1998-01-27 | 1998-01-16 | 11 |
ERNSH | 1998-02-18 | 1998-01-27 | 22 |
ERNSH | 1998-03-23 | 1998-02-18 | 33 |
ERNSH | 1998-03-26 | 1998-03-23 | 3 |
ERNSH | 1998-04-01 | 1998-03-26 | 6 |
ERNSH | 1998-04-08 | 1998-04-01 | 7 |
ERNSH | 1998-04-13 | 1998-04-08 | 5 |
ERNSH | 1998-05-05 | 1998-04-13 | 22 |
FAMIA | 1996-11-06 | 1995-01-01 | 675 |
FAMIA | 1996-12-18 | 1996-11-06 | 42 |
FAMIA | 1997-01-14 | 1996-12-18 | 27 |
FAMIA | 1997-04-21 | 1997-01-14 | 97 |
FAMIA | 1997-06-26 | 1997-04-21 | 66 |
FAMIA | 1997-08-29 | 1997-06-26 | 64 |
FAMIA | 1997-10-31 | 1997-08-29 | 63 |
FOLIG | 1997-01-08 | 1995-01-01 | 738 |
FOLIG | 1997-03-20 | 1997-01-08 | 71 |
FOLIG | 1997-08-15 | 1997-03-20 | 148 |
FOLIG | 1997-12-03 | 1997-08-15 | 110 |
FOLIG | 1997-12-22 | 1997-12-03 | 19 |
FOLKO | 1996-07-24 | 1995-01-01 | 570 |
FOLKO | 1996-10-11 | 1996-07-24 | 79 |
FOLKO | 1996-12-10 | 1996-10-11 | 60 |
FOLKO | 1997-02-03 | 1996-12-10 | 55 |
FOLKO | 1997-02-28 | 1997-02-03 | 25 |
FOLKO | 1997-05-12 | 1997-02-28 | 73 |
FOLKO | 1997-06-06 | 1997-05-12 | 25 |
FOLKO | 1997-10-14 | 1997-06-06 | 130 |
FOLKO | 1997-12-02 | 1997-10-14 | 49 |
FOLKO | 1997-12-11 | 1997-12-02 | 9 |
FOLKO | 1998-01-09 | 1997-12-11 | 29 |
FOLKO | 1998-02-10 | 1998-01-09 | 32 |
FOLKO | 1998-02-23 | 1998-02-10 | 13 |
FOLKO | 1998-03-17 | 1998-02-23 | 22 |
FOLKO | 1998-03-26 | 1998-03-17 | 9 |
FOLKO | 1998-03-27 | 1998-03-26 | 1 |
FOLKO | 1998-04-01 | 1998-03-27 | 5 |
FOLKO | 1998-04-06 | 1998-04-01 | 5 |
FOLKO | 1998-04-27 | 1998-04-06 | 21 |
FRANK | 1996-07-29 | 1995-01-01 | 575 |
FRANK | 1996-10-24 | 1996-07-29 | 87 |
FRANK | 1996-10-30 | 1996-10-24 | 6 |
FRANK | 1996-12-27 | 1996-10-30 | 58 |
FRANK | 1997-03-27 | 1996-12-27 | 90 |
FRANK | 1997-06-06 | 1997-03-27 | 71 |
FRANK | 1997-08-07 | 1997-06-06 | 62 |
FRANK | 1997-09-02 | 1997-08-07 | 26 |
FRANK | 1997-09-16 | 1997-09-02 | 14 |
FRANK | 1997-09-19 | 1997-09-16 | 3 |
FRANK | 1997-10-24 | 1997-09-19 | 35 |
FRANK | 1997-12-23 | 1997-10-24 | 60 |
FRANK | 1998-01-29 | 1997-12-23 | 37 |
FRANK | 1998-03-05 | 1998-01-29 | 35 |
FRANK | 1998-04-09 | 1998-03-05 | 35 |
FRANR | 1997-09-17 | 1995-01-01 | 990 |
FRANR | 1998-01-29 | 1997-09-17 | 134 |
FRANR | 1998-03-24 | 1998-01-29 | 54 |
FRANS | 1997-01-22 | 1995-01-01 | 752 |
FRANS | 1997-10-20 | 1997-01-22 | 271 |
FRANS | 1997-11-25 | 1997-10-20 | 36 |
FRANS | 1997-12-31 | 1997-11-25 | 36 |
FRANS | 1998-04-15 | 1997-12-31 | 105 |
FRANS | 1998-04-30 | 1998-04-15 | 15 |
FURIB | 1996-10-14 | 1995-01-01 | 652 |
FURIB | 1996-11-12 | 1996-10-14 | 29 |
FURIB | 1997-03-04 | 1996-11-12 | 112 |
FURIB | 1997-03-31 | 1997-03-04 | 27 |
FURIB | 1997-05-28 | 1997-03-31 | 58 |
FURIB | 1997-07-18 | 1997-05-28 | 51 |
FURIB | 1997-09-10 | 1997-07-18 | 54 |
FURIB | 1998-03-19 | 1997-09-10 | 190 |
GALED | 1996-11-28 | 1995-01-01 | 697 |
GALED | 1997-01-27 | 1996-11-28 | 60 |
GALED | 1997-06-13 | 1997-01-27 | 137 |
GALED | 1998-02-13 | 1997-06-13 | 245 |
GALED | 1998-03-05 | 1998-02-13 | 20 |
GODOS | 1996-09-11 | 1995-01-01 | 619 |
GODOS | 1997-05-28 | 1996-09-11 | 259 |
GODOS | 1997-08-12 | 1997-05-28 | 76 |
GODOS | 1998-02-05 | 1997-08-12 | 177 |
GODOS | 1998-02-06 | 1998-02-05 | 1 |
GODOS | 1998-02-16 | 1998-02-06 | 10 |
GODOS | 1998-02-26 | 1998-02-16 | 10 |
GODOS | 1998-03-13 | 1998-02-26 | 15 |
GODOS | 1998-04-08 | 1998-03-13 | 26 |
GODOS | 1998-04-21 | 1998-04-08 | 13 |
GOURL | 1997-01-23 | 1995-01-01 | 753 |
GOURL | 1997-09-01 | 1997-01-23 | 221 |
GOURL | 1997-09-29 | 1997-09-01 | 28 |
GOURL | 1997-10-17 | 1997-09-29 | 18 |
GOURL | 1997-11-07 | 1997-10-17 | 21 |
GOURL | 1997-12-15 | 1997-11-07 | 38 |
GOURL | 1997-12-22 | 1997-12-15 | 7 |
GOURL | 1998-03-18 | 1997-12-22 | 86 |
GOURL | 1998-04-24 | 1998-03-18 | 37 |
GREAL | 1997-05-06 | 1995-01-01 | 856 |
GREAL | 1997-07-04 | 1997-05-06 | 59 |
GREAL | 1997-07-31 | 1997-07-04 | 27 |
GREAL | 1997-07-31 | 1997-07-31 | 0 |
GREAL | 1997-09-04 | 1997-07-31 | 35 |
GREAL | 1997-09-25 | 1997-09-04 | 21 |
GREAL | 1998-01-06 | 1997-09-25 | 103 |
GREAL | 1998-03-09 | 1998-01-06 | 62 |
GREAL | 1998-04-07 | 1998-03-09 | 29 |
GREAL | 1998-04-22 | 1998-04-07 | 15 |
GREAL | 1998-04-30 | 1998-04-22 | 8 |
GROSR | 1996-07-30 | 1995-01-01 | 576 |
GROSR | 1997-12-18 | 1996-07-30 | 506 |
HANAR | 1996-07-08 | 1995-01-01 | 554 |
HANAR | 1996-07-10 | 1996-07-08 | 2 |
HANAR | 1997-05-19 | 1996-07-10 | 313 |
HANAR | 1997-08-26 | 1997-05-19 | 99 |
HANAR | 1997-10-02 | 1997-08-26 | 37 |
HANAR | 1997-12-09 | 1997-10-02 | 68 |
HANAR | 1997-12-18 | 1997-12-09 | 9 |
HANAR | 1998-02-13 | 1997-12-18 | 57 |
HANAR | 1998-02-24 | 1998-02-13 | 11 |
HANAR | 1998-03-03 | 1998-02-24 | 7 |
HANAR | 1998-03-04 | 1998-03-03 | 1 |
HANAR | 1998-03-27 | 1998-03-04 | 23 |
HANAR | 1998-04-14 | 1998-03-27 | 18 |
HANAR | 1998-04-27 | 1998-04-14 | 13 |
HILAA | 1996-07-16 | 1995-01-01 | 562 |
HILAA | 1996-12-26 | 1996-07-16 | 163 |
HILAA | 1997-03-17 | 1996-12-26 | 81 |
HILAA | 1997-03-26 | 1997-03-17 | 9 |
HILAA | 1997-03-31 | 1997-03-26 | 5 |
HILAA | 1997-04-07 | 1997-03-31 | 7 |
HILAA | 1997-05-29 | 1997-04-07 | 52 |
HILAA | 1997-07-16 | 1997-05-29 | 48 |
HILAA | 1997-07-29 | 1997-07-16 | 13 |
HILAA | 1997-08-22 | 1997-07-29 | 24 |
HILAA | 1997-10-15 | 1997-08-22 | 54 |
HILAA | 1997-12-25 | 1997-10-15 | 71 |
HILAA | 1998-02-02 | 1997-12-25 | 39 |
HILAA | 1998-02-23 | 1998-02-02 | 21 |
HILAA | 1998-03-18 | 1998-02-23 | 23 |
HILAA | 1998-03-19 | 1998-03-18 | 1 |
HILAA | 1998-03-25 | 1998-03-19 | 6 |
HILAA | 1998-04-28 | 1998-03-25 | 34 |
HUNGC | 1996-12-06 | 1995-01-01 | 705 |
HUNGC | 1996-12-25 | 1996-12-06 | 19 |
HUNGC | 1997-01-15 | 1996-12-25 | 21 |
HUNGC | 1997-07-16 | 1997-01-15 | 182 |
HUNGC | 1997-09-08 | 1997-07-16 | 54 |
HUNGO | 1996-09-05 | 1995-01-01 | 613 |
HUNGO | 1996-09-19 | 1996-09-05 | 14 |
HUNGO | 1996-10-22 | 1996-09-19 | 33 |
HUNGO | 1996-12-05 | 1996-10-22 | 44 |
HUNGO | 1996-12-12 | 1996-12-05 | 7 |
HUNGO | 1997-01-29 | 1996-12-12 | 48 |
HUNGO | 1997-04-11 | 1997-01-29 | 72 |
HUNGO | 1997-04-24 | 1997-04-11 | 13 |
HUNGO | 1997-06-12 | 1997-04-24 | 49 |
HUNGO | 1997-08-27 | 1997-06-12 | 76 |
HUNGO | 1997-09-09 | 1997-08-27 | 13 |
HUNGO | 1997-09-30 | 1997-09-09 | 21 |
HUNGO | 1997-10-13 | 1997-09-30 | 13 |
HUNGO | 1997-10-21 | 1997-10-13 | 8 |
HUNGO | 1997-11-11 | 1997-10-21 | 21 |
HUNGO | 1998-02-19 | 1997-11-11 | 100 |
HUNGO | 1998-02-26 | 1998-02-19 | 7 |
HUNGO | 1998-03-30 | 1998-02-26 | 32 |
HUNGO | 1998-04-30 | 1998-03-30 | 31 |
ISLAT | 1996-09-26 | 1995-01-01 | 634 |
ISLAT | 1996-10-01 | 1996-09-26 | 5 |
ISLAT | 1996-10-03 | 1996-10-01 | 2 |
ISLAT | 1997-03-13 | 1996-10-03 | 161 |
ISLAT | 1997-08-05 | 1997-03-13 | 145 |
ISLAT | 1997-09-18 | 1997-08-05 | 44 |
ISLAT | 1997-11-20 | 1997-09-18 | 63 |
ISLAT | 1997-12-26 | 1997-11-20 | 36 |
ISLAT | 1998-01-13 | 1997-12-26 | 18 |
ISLAT | 1998-03-06 | 1998-01-13 | 52 |
KOENE | 1996-10-07 | 1995-01-01 | 645 |
KOENE | 1996-10-09 | 1996-10-07 | 2 |
KOENE | 1997-02-25 | 1996-10-09 | 139 |
KOENE | 1997-02-25 | 1997-02-25 | 0 |
KOENE | 1997-03-07 | 1997-02-25 | 10 |
KOENE | 1997-04-15 | 1997-03-07 | 39 |
KOENE | 1997-05-20 | 1997-04-15 | 35 |
KOENE | 1997-08-13 | 1997-05-20 | 85 |
KOENE | 1997-10-27 | 1997-08-13 | 75 |
KOENE | 1997-12-26 | 1997-10-27 | 60 |
KOENE | 1998-01-06 | 1997-12-26 | 11 |
KOENE | 1998-01-23 | 1998-01-06 | 17 |
KOENE | 1998-02-18 | 1998-01-23 | 26 |
KOENE | 1998-04-16 | 1998-02-18 | 57 |
LACOR | 1998-01-29 | 1995-01-01 | 1124 |
LACOR | 1998-03-05 | 1998-01-29 | 35 |
LACOR | 1998-03-24 | 1998-03-05 | 19 |
LACOR | 1998-03-24 | 1998-03-24 | 0 |
LAMAI | 1996-11-11 | 1995-01-01 | 680 |
LAMAI | 1996-11-20 | 1996-11-11 | 9 |
LAMAI | 1996-12-03 | 1996-11-20 | 13 |
LAMAI | 1997-01-14 | 1996-12-03 | 42 |
LAMAI | 1997-01-24 | 1997-01-14 | 10 |
LAMAI | 1997-02-21 | 1997-01-24 | 28 |
LAMAI | 1997-04-02 | 1997-02-21 | 40 |
LAMAI | 1997-04-09 | 1997-04-02 | 7 |
LAMAI | 1997-07-25 | 1997-04-09 | 107 |
LAMAI | 1997-08-14 | 1997-07-25 | 20 |
LAMAI | 1997-12-19 | 1997-08-14 | 127 |
LAMAI | 1998-01-14 | 1997-12-19 | 26 |
LAMAI | 1998-03-03 | 1998-01-14 | 48 |
LAMAI | 1998-04-27 | 1998-03-03 | 55 |
LAUGB | 1997-04-03 | 1995-01-01 | 823 |
LAUGB | 1997-08-05 | 1997-04-03 | 124 |
LAUGB | 1998-01-01 | 1997-08-05 | 149 |
LAZYK | 1997-03-21 | 1995-01-01 | 810 |
LAZYK | 1997-05-22 | 1997-03-21 | 62 |
LEHMS | 1996-08-13 | 1995-01-01 | 590 |
LEHMS | 1996-08-19 | 1996-08-13 | 6 |
LEHMS | 1996-10-31 | 1996-08-19 | 73 |
LEHMS | 1997-04-04 | 1996-10-31 | 155 |
LEHMS | 1997-04-30 | 1997-04-04 | 26 |
LEHMS | 1997-05-12 | 1997-04-30 | 12 |
LEHMS | 1997-05-14 | 1997-05-12 | 2 |
LEHMS | 1997-06-03 | 1997-05-14 | 20 |
LEHMS | 1997-07-08 | 1997-06-03 | 35 |
LEHMS | 1997-07-09 | 1997-07-08 | 1 |
LEHMS | 1997-12-10 | 1997-07-09 | 154 |
LEHMS | 1998-01-30 | 1997-12-10 | 51 |
LEHMS | 1998-02-17 | 1998-01-30 | 18 |
LEHMS | 1998-03-09 | 1998-02-17 | 20 |
LEHMS | 1998-05-05 | 1998-03-09 | 57 |
LETSS | 1997-06-25 | 1995-01-01 | 906 |
LETSS | 1997-10-27 | 1997-06-25 | 124 |
LETSS | 1997-11-10 | 1997-10-27 | 14 |
LETSS | 1998-02-12 | 1997-11-10 | 94 |
LILAS | 1996-08-16 | 1995-01-01 | 593 |
LILAS | 1996-09-03 | 1996-08-16 | 18 |
LILAS | 1996-10-16 | 1996-09-03 | 43 |
LILAS | 1996-11-19 | 1996-10-16 | 34 |
LILAS | 1996-12-12 | 1996-11-19 | 23 |
LILAS | 1997-02-28 | 1996-12-12 | 78 |
LILAS | 1997-04-08 | 1997-02-28 | 39 |
LILAS | 1997-05-21 | 1997-04-08 | 43 |
LILAS | 1997-12-16 | 1997-05-21 | 209 |
LILAS | 1998-01-09 | 1997-12-16 | 24 |
LILAS | 1998-02-20 | 1998-01-09 | 42 |
LILAS | 1998-04-03 | 1998-02-20 | 42 |
LILAS | 1998-05-01 | 1998-04-03 | 28 |
LILAS | 1998-05-05 | 1998-05-01 | 4 |
LINOD | 1997-01-06 | 1995-01-01 | 736 |
LINOD | 1997-03-25 | 1997-01-06 | 78 |
LINOD | 1997-08-20 | 1997-03-25 | 148 |
LINOD | 1997-10-08 | 1997-08-20 | 49 |
LINOD | 1997-11-04 | 1997-10-08 | 27 |
LINOD | 1998-01-02 | 1997-11-04 | 59 |
LINOD | 1998-01-19 | 1998-01-02 | 17 |
LINOD | 1998-01-19 | 1998-01-19 | 0 |
LINOD | 1998-03-02 | 1998-01-19 | 42 |
LINOD | 1998-03-17 | 1998-03-02 | 15 |
LINOD | 1998-04-10 | 1998-03-17 | 24 |
LINOD | 1998-04-21 | 1998-04-10 | 11 |
LONEP | 1996-09-17 | 1995-01-01 | 625 |
LONEP | 1996-09-30 | 1996-09-17 | 13 |
LONEP | 1997-05-21 | 1996-09-30 | 233 |
LONEP | 1997-09-09 | 1997-05-21 | 111 |
LONEP | 1997-09-11 | 1997-09-09 | 2 |
LONEP | 1998-02-03 | 1997-09-11 | 145 |
LONEP | 1998-02-12 | 1998-02-03 | 9 |
LONEP | 1998-04-13 | 1998-02-12 | 60 |
MAGAA | 1996-08-07 | 1995-01-01 | 584 |
MAGAA | 1996-09-09 | 1996-08-07 | 33 |
MAGAA | 1997-01-03 | 1996-09-09 | 116 |
MAGAA | 1997-03-06 | 1997-01-03 | 62 |
MAGAA | 1997-08-18 | 1997-03-06 | 165 |
MAGAA | 1997-11-25 | 1997-08-18 | 99 |
MAGAA | 1997-12-18 | 1997-11-25 | 23 |
MAGAA | 1998-01-07 | 1997-12-18 | 20 |
MAGAA | 1998-03-10 | 1998-01-07 | 62 |
MAGAA | 1998-03-16 | 1998-03-10 | 6 |
MAISD | 1997-05-07 | 1995-01-01 | 857 |
MAISD | 1997-08-28 | 1997-05-07 | 113 |
MAISD | 1997-12-01 | 1997-08-28 | 95 |
MAISD | 1998-02-17 | 1997-12-01 | 78 |
MAISD | 1998-02-19 | 1998-02-17 | 2 |
MAISD | 1998-03-26 | 1998-02-19 | 35 |
MAISD | 1998-04-07 | 1998-03-26 | 12 |
MEREP | 1996-10-17 | 1995-01-01 | 655 |
MEREP | 1996-10-28 | 1996-10-17 | 11 |
MEREP | 1996-12-09 | 1996-10-28 | 42 |
MEREP | 1997-01-23 | 1996-12-09 | 45 |
MEREP | 1997-02-07 | 1997-01-23 | 15 |
MEREP | 1997-04-14 | 1997-02-07 | 66 |
MEREP | 1997-06-11 | 1997-04-14 | 58 |
MEREP | 1997-06-17 | 1997-06-11 | 6 |
MEREP | 1997-07-07 | 1997-06-17 | 20 |
MEREP | 1997-07-21 | 1997-07-07 | 14 |
MEREP | 1997-08-01 | 1997-07-21 | 11 |
MEREP | 1997-08-04 | 1997-08-01 | 3 |
MEREP | 1997-10-30 | 1997-08-04 | 87 |
MORGK | 1996-08-09 | 1995-01-01 | 586 |
MORGK | 1997-06-20 | 1996-08-09 | 315 |
MORGK | 1997-10-09 | 1997-06-20 | 111 |
MORGK | 1997-12-16 | 1997-10-09 | 68 |
MORGK | 1998-03-12 | 1997-12-16 | 86 |
NORTS | 1997-04-24 | 1995-01-01 | 844 |
NORTS | 1997-11-24 | 1997-04-24 | 214 |
NORTS | 1998-04-29 | 1997-11-24 | 156 |
OCEAN | 1997-01-09 | 1995-01-01 | 739 |
OCEAN | 1997-05-08 | 1997-01-09 | 119 |
OCEAN | 1998-02-20 | 1997-05-08 | 288 |
OCEAN | 1998-03-18 | 1998-02-20 | 26 |
OCEAN | 1998-03-30 | 1998-03-18 | 12 |
OLDWO | 1996-09-13 | 1995-01-01 | 621 |
OLDWO | 1996-10-25 | 1996-09-13 | 42 |
OLDWO | 1997-02-10 | 1996-10-25 | 108 |
OLDWO | 1997-07-09 | 1997-02-10 | 149 |
OLDWO | 1997-09-24 | 1997-07-09 | 77 |
OLDWO | 1997-10-16 | 1997-09-24 | 22 |
OLDWO | 1998-01-01 | 1997-10-16 | 77 |
OLDWO | 1998-01-27 | 1998-01-01 | 26 |
OLDWO | 1998-03-20 | 1998-01-27 | 52 |
OLDWO | 1998-04-20 | 1998-03-20 | 31 |
OTTIK | 1996-07-19 | 1995-01-01 | 565 |
OTTIK | 1997-01-07 | 1996-07-19 | 172 |
OTTIK | 1997-04-16 | 1997-01-07 | 99 |
OTTIK | 1997-05-30 | 1997-04-16 | 44 |
OTTIK | 1997-06-26 | 1997-05-30 | 27 |
OTTIK | 1997-09-26 | 1997-06-26 | 92 |
OTTIK | 1997-12-05 | 1997-09-26 | 70 |
OTTIK | 1998-01-15 | 1997-12-05 | 41 |
OTTIK | 1998-04-03 | 1998-01-15 | 78 |
OTTIK | 1998-04-14 | 1998-04-03 | 11 |
PERIC | 1996-10-04 | 1995-01-01 | 642 |
PERIC | 1996-11-14 | 1996-10-04 | 41 |
PERIC | 1997-03-13 | 1996-11-14 | 119 |
PERIC | 1997-04-10 | 1997-03-13 | 28 |
PERIC | 1998-04-02 | 1997-04-10 | 357 |
PERIC | 1998-05-05 | 1998-04-02 | 33 |
PICCO | 1996-11-13 | 1995-01-01 | 682 |
PICCO | 1996-12-24 | 1996-11-13 | 41 |
PICCO | 1997-01-27 | 1996-12-24 | 34 |
PICCO | 1997-03-28 | 1997-01-27 | 60 |
PICCO | 1997-05-08 | 1997-03-28 | 41 |
PICCO | 1997-07-11 | 1997-05-08 | 64 |
PICCO | 1997-09-30 | 1997-07-11 | 81 |
PICCO | 1997-11-19 | 1997-09-30 | 50 |
PICCO | 1998-01-21 | 1997-11-19 | 63 |
PICCO | 1998-04-27 | 1998-01-21 | 96 |
PRINI | 1996-10-23 | 1995-01-01 | 661 |
PRINI | 1996-12-27 | 1996-10-23 | 65 |
PRINI | 1997-02-03 | 1996-12-27 | 38 |
PRINI | 1997-03-17 | 1997-02-03 | 42 |
PRINI | 1998-04-08 | 1997-03-17 | 387 |
QUEDE | 1996-07-19 | 1995-01-01 | 565 |
QUEDE | 1996-08-27 | 1996-07-19 | 39 |
QUEDE | 1996-12-11 | 1996-08-27 | 106 |
QUEDE | 1997-01-21 | 1996-12-11 | 41 |
QUEDE | 1997-07-02 | 1997-01-21 | 162 |
QUEDE | 1997-08-27 | 1997-07-02 | 56 |
QUEDE | 1997-10-28 | 1997-08-27 | 62 |
QUEDE | 1997-12-24 | 1997-10-28 | 57 |
QUEDE | 1998-03-31 | 1997-12-24 | 97 |
QUEEN | 1996-12-04 | 1995-01-01 | 703 |
QUEEN | 1997-01-07 | 1996-12-04 | 34 |
QUEEN | 1997-03-26 | 1997-01-07 | 78 |
QUEEN | 1997-08-19 | 1997-03-26 | 146 |
QUEEN | 1997-09-05 | 1997-08-19 | 17 |
QUEEN | 1997-10-14 | 1997-09-05 | 39 |
QUEEN | 1997-11-04 | 1997-10-14 | 21 |
QUEEN | 1997-12-19 | 1997-11-04 | 45 |
QUEEN | 1998-02-04 | 1997-12-19 | 47 |
QUEEN | 1998-02-26 | 1998-02-04 | 22 |
QUEEN | 1998-02-27 | 1998-02-26 | 1 |
QUEEN | 1998-03-19 | 1998-02-27 | 20 |
QUEEN | 1998-05-04 | 1998-03-19 | 46 |
QUICK | 1996-08-05 | 1995-01-01 | 582 |
QUICK | 1996-08-20 | 1996-08-05 | 15 |
QUICK | 1996-08-21 | 1996-08-20 | 1 |
QUICK | 1996-09-24 | 1996-08-21 | 34 |
QUICK | 1996-11-04 | 1996-09-24 | 41 |
QUICK | 1996-11-22 | 1996-11-04 | 18 |
QUICK | 1997-01-17 | 1996-11-22 | 56 |
QUICK | 1997-02-19 | 1997-01-17 | 33 |
QUICK | 1997-04-23 | 1997-02-19 | 63 |
QUICK | 1997-05-05 | 1997-04-23 | 12 |
QUICK | 1997-05-19 | 1997-05-05 | 14 |
QUICK | 1997-05-27 | 1997-05-19 | 8 |
QUICK | 1997-07-03 | 1997-05-27 | 37 |
QUICK | 1997-09-05 | 1997-07-03 | 64 |
QUICK | 1997-10-03 | 1997-09-05 | 28 |
QUICK | 1997-10-06 | 1997-10-03 | 3 |
QUICK | 1997-10-29 | 1997-10-06 | 23 |
QUICK | 1997-11-18 | 1997-10-29 | 20 |
QUICK | 1997-12-04 | 1997-11-18 | 16 |
QUICK | 1997-12-22 | 1997-12-04 | 18 |
QUICK | 1998-01-21 | 1997-12-22 | 30 |
QUICK | 1998-02-02 | 1998-01-21 | 12 |
QUICK | 1998-02-10 | 1998-02-02 | 8 |
QUICK | 1998-03-10 | 1998-02-10 | 28 |
QUICK | 1998-03-19 | 1998-03-10 | 9 |
QUICK | 1998-04-01 | 1998-03-19 | 13 |
QUICK | 1998-04-02 | 1998-04-01 | 1 |
QUICK | 1998-04-14 | 1998-04-02 | 12 |
RANCH | 1997-02-17 | 1995-01-01 | 778 |
RANCH | 1997-10-24 | 1997-02-17 | 249 |
RANCH | 1998-01-13 | 1997-10-24 | 81 |
RANCH | 1998-02-27 | 1998-01-13 | 45 |
RANCH | 1998-04-13 | 1998-02-27 | 45 |
RATTC | 1996-07-22 | 1995-01-01 | 568 |
RATTC | 1996-08-02 | 1996-07-22 | 11 |
RATTC | 1996-08-30 | 1996-08-02 | 28 |
RATTC | 1996-09-25 | 1996-08-30 | 26 |
RATTC | 1996-09-27 | 1996-09-25 | 2 |
RATTC | 1996-11-05 | 1996-09-27 | 39 |
RATTC | 1997-01-01 | 1996-11-05 | 57 |
RATTC | 1997-03-19 | 1997-01-01 | 77 |
RATTC | 1997-06-10 | 1997-03-19 | 83 |
RATTC | 1997-06-16 | 1997-06-10 | 6 |
RATTC | 1997-07-14 | 1997-06-16 | 28 |
RATTC | 1997-12-02 | 1997-07-14 | 141 |
RATTC | 1998-01-07 | 1997-12-02 | 36 |
RATTC | 1998-01-26 | 1998-01-07 | 19 |
RATTC | 1998-02-16 | 1998-01-26 | 21 |
RATTC | 1998-03-31 | 1998-02-16 | 43 |
RATTC | 1998-04-06 | 1998-03-31 | 6 |
RATTC | 1998-05-06 | 1998-04-06 | 30 |
REGGC | 1996-08-23 | 1995-01-01 | 600 |
REGGC | 1997-01-28 | 1996-08-23 | 158 |
REGGC | 1997-02-12 | 1997-01-28 | 15 |
REGGC | 1997-06-09 | 1997-02-12 | 117 |
REGGC | 1997-07-02 | 1997-06-09 | 23 |
REGGC | 1997-09-03 | 1997-07-02 | 63 |
REGGC | 1997-11-03 | 1997-09-03 | 61 |
REGGC | 1998-01-02 | 1997-11-03 | 60 |
REGGC | 1998-02-26 | 1998-01-02 | 55 |
REGGC | 1998-03-11 | 1998-02-26 | 13 |
REGGC | 1998-04-09 | 1998-03-11 | 29 |
REGGC | 1998-04-30 | 1998-04-09 | 21 |
RICAR | 1996-08-22 | 1995-01-01 | 599 |
RICAR | 1996-09-06 | 1996-08-22 | 15 |
RICAR | 1997-02-14 | 1996-09-06 | 161 |
RICAR | 1997-03-20 | 1997-02-14 | 34 |
RICAR | 1997-06-10 | 1997-03-20 | 82 |
RICAR | 1997-08-06 | 1997-06-10 | 57 |
RICAR | 1997-08-28 | 1997-08-06 | 22 |
RICAR | 1998-01-05 | 1997-08-28 | 130 |
RICAR | 1998-01-26 | 1998-01-05 | 21 |
RICAR | 1998-02-09 | 1998-01-26 | 14 |
RICAR | 1998-04-29 | 1998-02-09 | 79 |
RICSU | 1996-07-12 | 1995-01-01 | 558 |
RICSU | 1997-01-20 | 1996-07-12 | 192 |
RICSU | 1997-05-14 | 1997-01-20 | 114 |
RICSU | 1997-09-12 | 1997-05-14 | 121 |
RICSU | 1997-11-24 | 1997-09-12 | 73 |
RICSU | 1997-11-28 | 1997-11-24 | 4 |
RICSU | 1998-03-06 | 1997-11-28 | 98 |
RICSU | 1998-03-16 | 1998-03-06 | 10 |
RICSU | 1998-04-17 | 1998-03-16 | 32 |
RICSU | 1998-05-06 | 1998-04-17 | 19 |
ROMEY | 1996-08-14 | 1995-01-01 | 591 |
ROMEY | 1996-08-15 | 1996-08-14 | 1 |
ROMEY | 1996-09-16 | 1996-08-15 | 32 |
ROMEY | 1998-03-02 | 1996-09-16 | 532 |
ROMEY | 1998-04-09 | 1998-03-02 | 38 |
SANTG | 1996-12-18 | 1995-01-01 | 717 |
SANTG | 1997-04-29 | 1996-12-18 | 132 |
SANTG | 1997-08-20 | 1997-04-29 | 113 |
SANTG | 1998-01-14 | 1997-08-20 | 147 |
SANTG | 1998-02-26 | 1998-01-14 | 43 |
SANTG | 1998-04-10 | 1998-02-26 | 43 |
SAVEA | 1996-10-08 | 1995-01-01 | 646 |
SAVEA | 1996-12-25 | 1996-10-08 | 78 |
SAVEA | 1996-12-30 | 1996-12-25 | 5 |
SAVEA | 1997-02-10 | 1996-12-30 | 42 |
SAVEA | 1997-02-20 | 1997-02-10 | 10 |
SAVEA | 1997-04-18 | 1997-02-20 | 57 |
SAVEA | 1997-06-02 | 1997-04-18 | 45 |
SAVEA | 1997-07-18 | 1997-06-02 | 46 |
SAVEA | 1997-07-22 | 1997-07-18 | 4 |
SAVEA | 1997-07-28 | 1997-07-22 | 6 |
SAVEA | 1997-08-11 | 1997-07-28 | 14 |
SAVEA | 1997-09-04 | 1997-08-11 | 24 |
SAVEA | 1997-09-23 | 1997-09-04 | 19 |
SAVEA | 1997-10-10 | 1997-09-23 | 17 |
SAVEA | 1997-10-21 | 1997-10-10 | 11 |
SAVEA | 1997-10-22 | 1997-10-21 | 1 |
SAVEA | 1997-10-22 | 1997-10-22 | 0 |
SAVEA | 1997-10-29 | 1997-10-22 | 7 |
SAVEA | 1997-11-20 | 1997-10-29 | 22 |
SAVEA | 1997-11-27 | 1997-11-20 | 7 |
SAVEA | 1998-01-05 | 1997-11-27 | 39 |
SAVEA | 1998-01-22 | 1998-01-05 | 17 |
SAVEA | 1998-02-11 | 1998-01-22 | 20 |
SAVEA | 1998-02-18 | 1998-02-11 | 7 |
SAVEA | 1998-03-11 | 1998-02-18 | 21 |
SAVEA | 1998-03-27 | 1998-03-11 | 16 |
SAVEA | 1998-03-30 | 1998-03-27 | 3 |
SAVEA | 1998-04-06 | 1998-03-30 | 7 |
SAVEA | 1998-04-17 | 1998-04-06 | 11 |
SAVEA | 1998-04-17 | 1998-04-17 | 0 |
SAVEA | 1998-05-01 | 1998-04-17 | 14 |
SEVES | 1996-11-21 | 1995-01-01 | 690 |
SEVES | 1996-12-09 | 1996-11-21 | 18 |
SEVES | 1996-12-19 | 1996-12-09 | 10 |
SEVES | 1997-03-12 | 1996-12-19 | 83 |
SEVES | 1997-05-01 | 1997-03-12 | 50 |
SEVES | 1997-05-23 | 1997-05-01 | 22 |
SEVES | 1997-12-26 | 1997-05-23 | 217 |
SEVES | 1997-12-30 | 1997-12-26 | 4 |
SEVES | 1998-02-04 | 1997-12-30 | 36 |
SIMOB | 1996-10-29 | 1995-01-01 | 667 |
SIMOB | 1997-01-16 | 1996-10-29 | 79 |
SIMOB | 1997-06-03 | 1997-01-16 | 138 |
SIMOB | 1997-08-22 | 1997-06-03 | 80 |
SIMOB | 1997-09-15 | 1997-08-22 | 24 |
SIMOB | 1997-12-29 | 1997-09-15 | 105 |
SIMOB | 1998-05-06 | 1997-12-29 | 128 |
SPECD | 1997-11-12 | 1995-01-01 | 1046 |
SPECD | 1998-02-25 | 1997-11-12 | 105 |
SPECD | 1998-03-20 | 1998-02-25 | 23 |
SPECD | 1998-04-22 | 1998-03-20 | 33 |
SPLIR | 1996-08-01 | 1995-01-01 | 578 |
SPLIR | 1996-10-15 | 1996-08-01 | 75 |
SPLIR | 1996-11-08 | 1996-10-15 | 24 |
SPLIR | 1996-12-02 | 1996-11-08 | 24 |
SPLIR | 1996-12-17 | 1996-12-02 | 15 |
SPLIR | 1997-01-31 | 1996-12-17 | 45 |
SPLIR | 1997-11-27 | 1997-01-31 | 300 |
SPLIR | 1998-01-08 | 1997-11-27 | 42 |
SPLIR | 1998-03-25 | 1998-01-08 | 76 |
SUPRD | 1996-07-09 | 1995-01-01 | 555 |
SUPRD | 1996-09-10 | 1996-07-09 | 63 |
SUPRD | 1997-02-26 | 1996-09-10 | 169 |
SUPRD | 1997-03-04 | 1997-02-26 | 6 |
SUPRD | 1997-03-14 | 1997-03-04 | 10 |
SUPRD | 1997-12-05 | 1997-03-14 | 266 |
SUPRD | 1998-01-20 | 1997-12-05 | 46 |
SUPRD | 1998-01-22 | 1998-01-20 | 2 |
SUPRD | 1998-02-12 | 1998-01-22 | 21 |
SUPRD | 1998-03-06 | 1998-02-12 | 22 |
SUPRD | 1998-04-20 | 1998-03-06 | 45 |
SUPRD | 1998-04-21 | 1998-04-20 | 1 |
THEBI | 1996-09-20 | 1995-01-01 | 628 |
THEBI | 1997-10-17 | 1996-09-20 | 392 |
THEBI | 1997-12-30 | 1997-10-17 | 74 |
THEBI | 1998-04-01 | 1997-12-30 | 92 |
THECR | 1997-08-07 | 1995-01-01 | 949 |
THECR | 1997-12-12 | 1997-08-07 | 127 |
THECR | 1998-04-06 | 1997-12-12 | 115 |
TOMSP | 1996-07-05 | 1995-01-01 | 551 |
TOMSP | 1997-02-06 | 1996-07-05 | 216 |
TOMSP | 1997-02-14 | 1997-02-06 | 8 |
TOMSP | 1997-05-26 | 1997-02-14 | 101 |
TOMSP | 1997-07-23 | 1997-05-26 | 58 |
TOMSP | 1998-03-23 | 1997-07-23 | 243 |
TORTU | 1996-08-08 | 1995-01-01 | 585 |
TORTU | 1996-08-29 | 1996-08-08 | 21 |
TORTU | 1996-09-12 | 1996-08-29 | 14 |
TORTU | 1996-10-02 | 1996-09-12 | 20 |
TORTU | 1997-04-25 | 1996-10-02 | 205 |
TORTU | 1997-06-23 | 1997-04-25 | 59 |
TORTU | 1997-09-22 | 1997-06-23 | 91 |
TORTU | 1998-01-20 | 1997-09-22 | 120 |
TORTU | 1998-02-27 | 1998-01-20 | 38 |
TORTU | 1998-05-04 | 1998-02-27 | 66 |
TRADH | 1996-08-28 | 1995-01-01 | 605 |
TRADH | 1997-04-04 | 1996-08-28 | 219 |
TRADH | 1997-07-22 | 1997-04-04 | 109 |
TRADH | 1998-01-13 | 1997-07-22 | 175 |
TRADH | 1998-01-15 | 1998-01-13 | 2 |
TRADH | 1998-01-19 | 1998-01-15 | 4 |
TRAIH | 1997-06-19 | 1995-01-01 | 900 |
TRAIH | 1997-06-23 | 1997-06-19 | 4 |
TRAIH | 1998-01-08 | 1997-06-23 | 199 |
VAFFE | 1996-11-28 | 1995-01-01 | 697 |
VAFFE | 1996-12-31 | 1996-11-28 | 33 |
VAFFE | 1997-03-05 | 1996-12-31 | 64 |
VAFFE | 1997-07-07 | 1997-03-05 | 124 |
VAFFE | 1997-07-17 | 1997-07-07 | 10 |
VAFFE | 1997-10-01 | 1997-07-17 | 76 |
VAFFE | 1997-11-17 | 1997-10-01 | 47 |
VAFFE | 1997-12-08 | 1997-11-17 | 21 |
VAFFE | 1998-03-03 | 1997-12-08 | 85 |
VAFFE | 1998-03-12 | 1998-03-03 | 9 |
VAFFE | 1998-04-02 | 1998-03-12 | 21 |
VICTE | 1996-07-08 | 1995-01-01 | 554 |
VICTE | 1996-10-21 | 1996-07-08 | 105 |
VICTE | 1997-02-19 | 1996-10-21 | 121 |
VICTE | 1997-02-27 | 1997-02-19 | 8 |
VICTE | 1997-03-18 | 1997-02-27 | 19 |
VICTE | 1997-05-23 | 1997-03-18 | 66 |
VICTE | 1997-12-31 | 1997-05-23 | 222 |
VICTE | 1998-01-05 | 1997-12-31 | 5 |
VICTE | 1998-01-21 | 1998-01-05 | 16 |
VICTE | 1998-01-23 | 1998-01-21 | 2 |
VINET | 1996-07-04 | 1995-01-01 | 550 |
VINET | 1996-08-06 | 1996-07-04 | 33 |
VINET | 1996-09-02 | 1996-08-06 | 27 |
VINET | 1997-11-11 | 1996-09-02 | 435 |
VINET | 1997-11-12 | 1997-11-11 | 1 |
WANDK | 1996-09-09 | 1995-01-01 | 617 |
WANDK | 1996-09-23 | 1996-09-09 | 14 |
WANDK | 1996-11-07 | 1996-09-23 | 45 |
WANDK | 1996-11-18 | 1996-11-07 | 11 |
WANDK | 1997-04-22 | 1996-11-18 | 155 |
WANDK | 1997-08-14 | 1997-04-22 | 114 |
WANDK | 1997-08-21 | 1997-08-14 | 7 |
WANDK | 1997-09-01 | 1997-08-21 | 11 |
WANDK | 1997-09-15 | 1997-09-01 | 14 |
WANDK | 1998-04-23 | 1997-09-15 | 220 |
WARTH | 1996-07-26 | 1995-01-01 | 572 |
WARTH | 1996-08-01 | 1996-07-26 | 6 |
WARTH | 1996-10-03 | 1996-08-01 | 63 |
WARTH | 1996-10-18 | 1996-10-03 | 15 |
WARTH | 1997-01-13 | 1996-10-18 | 87 |
WARTH | 1997-01-16 | 1997-01-13 | 3 |
WARTH | 1997-02-05 | 1997-01-16 | 20 |
WARTH | 1997-02-24 | 1997-02-05 | 19 |
WARTH | 1997-05-05 | 1997-02-24 | 70 |
WARTH | 1997-05-30 | 1997-05-05 | 25 |
WARTH | 1997-06-30 | 1997-05-30 | 31 |
WARTH | 1997-08-19 | 1997-06-30 | 50 |
WARTH | 1997-11-21 | 1997-08-19 | 94 |
WARTH | 1997-12-17 | 1997-11-21 | 26 |
WARTH | 1998-04-15 | 1997-12-17 | 119 |
WELLI | 1996-07-15 | 1995-01-01 | 561 |
WELLI | 1997-01-21 | 1996-07-15 | 190 |
WELLI | 1997-07-01 | 1997-01-21 | 161 |
WELLI | 1997-08-25 | 1997-07-01 | 55 |
WELLI | 1997-12-30 | 1997-08-25 | 127 |
WELLI | 1998-01-01 | 1997-12-30 | 2 |
WELLI | 1998-02-20 | 1998-01-01 | 50 |
WELLI | 1998-02-24 | 1998-02-20 | 4 |
WELLI | 1998-03-09 | 1998-02-24 | 13 |
WHITC | 1996-07-31 | 1995-01-01 | 577 |
WHITC | 1996-11-01 | 1996-07-31 | 93 |
WHITC | 1997-03-10 | 1996-11-01 | 129 |
WHITC | 1997-03-24 | 1997-03-10 | 14 |
WHITC | 1997-04-11 | 1997-03-24 | 18 |
WHITC | 1997-07-11 | 1997-04-11 | 91 |
WHITC | 1997-10-06 | 1997-07-11 | 87 |
WHITC | 1997-10-08 | 1997-10-06 | 2 |
WHITC | 1997-10-30 | 1997-10-08 | 22 |
WHITC | 1997-11-13 | 1997-10-30 | 14 |
WHITC | 1998-01-30 | 1997-11-13 | 78 |
WHITC | 1998-02-24 | 1998-01-30 | 25 |
WHITC | 1998-04-17 | 1998-02-24 | 52 |
WHITC | 1998-05-01 | 1998-04-17 | 14 |
WILMK | 1997-07-30 | 1995-01-01 | 941 |
WILMK | 1997-09-18 | 1997-07-30 | 50 |
WILMK | 1997-10-07 | 1997-09-18 | 19 |
WILMK | 1998-02-06 | 1997-10-07 | 122 |
WILMK | 1998-02-10 | 1998-02-06 | 4 |
WILMK | 1998-02-26 | 1998-02-10 | 16 |
WILMK | 1998-04-07 | 1998-02-26 | 40 |
WOLZA | 1996-12-05 | 1995-01-01 | 704 |
WOLZA | 1997-07-25 | 1996-12-05 | 232 |
WOLZA | 1997-12-23 | 1997-07-25 | 151 |
WOLZA | 1998-02-04 | 1997-12-23 | 43 |
WOLZA | 1998-02-25 | 1998-02-04 | 21 |
WOLZA | 1998-04-03 | 1998-02-25 | 37 |
WOLZA | 1998-04-23 | 1998-04-03 | 20 |
From this point it is pretty straight forward to get the average day span for each customer to perform an order. We can use either some CTE
either sub-queries. We will also add the days of the latest and earliest orders, and the LAG()
calculation without default value to demonstrate how this may affect the output.
Sub-query:
SELECT customer_id, max(order_date) as latest_order, min(order_date) as earliest_order, avg(difference_in_days_with_default) as avg_difference_in_days_with_default, avg(difference_in_days) as avg_difference_in_days FROM ( SELECT customer_id, order_date, order_date - LAG(order_date, 1 ,'1995-01-01') OVER (PARTITION BY customer_id ORDER BY order_date) as difference_in_days_with_default, order_date - LAG(order_date) OVER (PARTITION BY customer_id ORDER BY order_date) as difference_in_days FROM orders ORDER BY customer_id ) t GROUP BY customer_id;
CTE:
WITH customer_order_stats (customer_id, order_date, difference_in_days_with_default, difference_in_days) AS ( SELECT customer_id, order_date, order_date - LAG(order_date, 1 ,'1995-01-01') OVER (PARTITION BY customer_id ORDER BY order_date) as difference_in_days_with_default, order_date - LAG(order_date) OVER (PARTITION BY customer_id ORDER BY order_date) as difference_in_days FROM orders ORDER BY customer_id ) SELECT customer_id, max(order_date) as latest_order, min(order_date) as earliest_order, avg(difference_in_days_with_default) as avg_difference_in_days_with_default, avg(difference_in_days) as avg_difference_in_days FROM customer_order_stats GROUP BY customer_id;
Both of which produce:
customer_id | latest_order | earliest_order | avg_difference_in_days_with_default | avg_difference_in_days |
---|---|---|---|---|
ALFKI | 1998-04-09 | 1997-08-25 | 199 | 45.4 |
ANATR | 1998-03-04 | 1996-09-18 | 289.5 | 177.3333333333333333 |
ANTON | 1998-01-28 | 1996-11-27 | 160.4285714285714286 | 71.1666666666666667 |
AROUT | 1998-04-10 | 1996-11-15 | 91.9230769230769231 | 42.5833333333333333 |
BERGS | 1998-03-04 | 1996-08-12 | 64.3333333333333333 | 33.4705882352941176 |
BLAUS | 1998-04-29 | 1997-04-09 | 173.4285714285714286 | 64.1666666666666667 |
BLONP | 1998-01-12 | 1996-07-25 | 100.6363636363636364 | 53.6 |
BOLID | 1998-03-24 | 1996-10-10 | 392.6666666666666667 | 265 |
BONAP | 1998-05-06 | 1996-10-16 | 71.8235294117647059 | 35.4375 |
BOTTM | 1998-04-24 | 1996-12-20 | 86.3571428571428571 | 37.6923076923076923 |
BSBEV | 1998-04-14 | 1996-08-26 | 119.9 | 66.2222222222222222 |
CACTU | 1998-04-28 | 1997-04-29 | 202.1666666666666667 | 72.8 |
CENTC | 1996-07-18 | 1996-07-18 | 564 | |
CHOPS | 1998-04-22 | 1996-07-11 | 150.875 | 92.8571428571428571 |
COMMI | 1998-04-22 | 1996-08-27 | 241.4 | 150.75 |
CONSH | 1998-01-23 | 1997-02-04 | 372.6666666666666667 | 176.5 |
DRACD | 1998-05-04 | 1996-11-26 | 203.1666666666666667 | 104.8 |
DUMON | 1998-02-16 | 1996-09-20 | 285.5 | 171.3333333333333333 |
EASTC | 1998-04-28 | 1996-11-26 | 151.625 | 74 |
ERNSH | 1998-05-05 | 1996-07-17 | 40.6666666666666667 | 22.6551724137931034 |
FAMIA | 1997-10-31 | 1996-11-06 | 147.7142857142857143 | 59.8333333333333333 |
FOLIG | 1997-12-22 | 1997-01-08 | 217.2 | 87 |
FOLKO | 1998-04-27 | 1996-07-24 | 63.7894736842105263 | 35.6666666666666667 |
FRANK | 1998-04-09 | 1996-07-29 | 79.6 | 44.2142857142857143 |
FRANR | 1998-03-24 | 1997-09-17 | 392.6666666666666667 | 94 |
FRANS | 1998-04-30 | 1997-01-22 | 202.5 | 92.6 |
FURIB | 1998-03-19 | 1996-10-14 | 146.625 | 74.4285714285714286 |
GALED | 1998-03-05 | 1996-11-28 | 231.8 | 115.5 |
GODOS | 1998-04-21 | 1996-09-11 | 120.6 | 65.2222222222222222 |
GOURL | 1998-04-24 | 1997-01-23 | 134.3333333333333333 | 57 |
GREAL | 1998-04-30 | 1997-05-06 | 110.4545454545454545 | 35.9 |
GROSR | 1997-12-18 | 1996-07-30 | 541 | 506 |
HANAR | 1998-04-27 | 1996-07-08 | 86.5714285714285714 | 50.6153846153846154 |
HILAA | 1998-04-28 | 1996-07-16 | 67.3888888888888889 | 38.2941176470588235 |
HUNGC | 1997-09-08 | 1996-12-06 | 196.2 | 69 |
HUNGO | 1998-04-30 | 1996-09-05 | 63.9473684210526316 | 33.4444444444444444 |
ISLAT | 1998-03-06 | 1996-09-26 | 116 | 58.4444444444444444 |
KOENE | 1998-04-16 | 1996-10-07 | 85.7857142857142857 | 42.7692307692307692 |
LACOR | 1998-03-24 | 1998-01-29 | 294.5 | 18 |
LAMAI | 1998-04-27 | 1996-11-11 | 86.5714285714285714 | 40.9230769230769231 |
LAUGB | 1998-01-01 | 1997-04-03 | 365.3333333333333333 | 136.5 |
LAZYK | 1997-05-22 | 1997-03-21 | 436 | 62 |
LEHMS | 1998-05-05 | 1996-08-13 | 81.3333333333333333 | 45 |
LETSS | 1998-02-12 | 1997-06-25 | 284.5 | 77.3333333333333333 |
LILAS | 1998-05-05 | 1996-08-16 | 87.1428571428571429 | 48.2307692307692308 |
LINOD | 1998-04-21 | 1997-01-06 | 100.5 | 42.7272727272727273 |
LONEP | 1998-04-13 | 1996-09-17 | 149.75 | 81.8571428571428571 |
MAGAA | 1998-03-16 | 1996-08-07 | 117 | 65.1111111111111111 |
MAISD | 1998-04-07 | 1997-05-07 | 170.2857142857142857 | 55.8333333333333333 |
MEREP | 1997-10-30 | 1996-10-17 | 79.4615384615384615 | 31.5 |
MORGK | 1998-03-12 | 1996-08-09 | 233.2 | 145 |
NORTS | 1998-04-29 | 1997-04-24 | 404.6666666666666667 | 185 |
OCEAN | 1998-03-30 | 1997-01-09 | 236.8 | 111.25 |
OLDWO | 1998-04-20 | 1996-09-13 | 120.5 | 64.8888888888888889 |
OTTIK | 1998-04-14 | 1996-07-19 | 119.9 | 70.4444444444444444 |
PERIC | 1998-05-05 | 1996-10-04 | 203.3333333333333333 | 115.6 |
PICCO | 1998-04-27 | 1996-11-13 | 121.2 | 58.8888888888888889 |
PRINI | 1998-04-08 | 1996-10-23 | 238.6 | 133 |
QUEDE | 1998-03-31 | 1996-07-19 | 131.6666666666666667 | 77.5 |
QUEEN | 1998-05-04 | 1996-12-04 | 93.7692307692307692 | 43 |
QUICK | 1998-04-14 | 1996-08-05 | 42.8214285714285714 | 22.8518518518518519 |
RANCH | 1998-04-13 | 1997-02-17 | 239.6 | 105 |
RATTC | 1998-05-06 | 1996-07-22 | 67.8333333333333333 | 38.4117647058823529 |
REGGC | 1998-04-30 | 1996-08-23 | 101.25 | 55.9090909090909091 |
RICAR | 1998-04-29 | 1996-08-22 | 110.3636363636363636 | 61.5 |
RICSU | 1998-05-06 | 1996-07-12 | 122.1 | 73.6666666666666667 |
ROMEY | 1998-04-09 | 1996-08-14 | 238.8 | 150.75 |
SANTG | 1998-04-10 | 1996-12-18 | 199.1666666666666667 | 95.6 |
SAVEA | 1998-05-01 | 1996-10-08 | 39.2258064516129032 | 19 |
SEVES | 1998-02-04 | 1996-11-21 | 125.5555555555555556 | 55 |
SIMOB | 1998-05-06 | 1996-10-29 | 174.4285714285714286 | 92.3333333333333333 |
SPECD | 1998-04-22 | 1997-11-12 | 301.75 | 53.6666666666666667 |
SPLIR | 1998-03-25 | 1996-08-01 | 131 | 75.125 |
SUPRD | 1998-04-21 | 1996-07-09 | 100.5 | 59.1818181818181818 |
THEBI | 1998-04-01 | 1996-09-20 | 296.5 | 186 |
THECR | 1998-04-06 | 1997-08-07 | 397 | 121 |
TOMSP | 1998-03-23 | 1996-07-05 | 196.1666666666666667 | 125.2 |
TORTU | 1998-05-04 | 1996-08-08 | 121.9 | 70.4444444444444444 |
TRADH | 1998-01-19 | 1996-08-28 | 185.6666666666666667 | 101.8 |
TRAIH | 1998-01-08 | 1997-06-19 | 367.6666666666666667 | 101.5 |
VAFFE | 1998-04-02 | 1996-11-28 | 107.9090909090909091 | 49 |
VICTE | 1998-01-23 | 1996-07-08 | 111.8 | 62.6666666666666667 |
VINET | 1997-11-12 | 1996-07-04 | 209.2 | 124 |
WANDK | 1998-04-23 | 1996-09-09 | 120.8 | 65.6666666666666667 |
WARTH | 1998-04-15 | 1996-07-26 | 80 | 44.8571428571428571 |
WELLI | 1998-03-09 | 1996-07-15 | 129.2222222222222222 | 75.25 |
WHITC | 1998-05-01 | 1996-07-31 | 86.8571428571428571 | 49.1538461538461538 |
WILMK | 1998-04-07 | 1997-07-30 | 170.2857142857142857 | 41.8333333333333333 |
WOLZA | 1998-04-23 | 1996-12-05 | 172.5714285714285714 | 84 |
FIRST_VALUE(), LAST_VALUE(), AND nth_VALUE
As the name implies those function will return the first, last or the n value (based on order) within the working set.
Those functions can also accept a frame clause. This defines the subset of the partition where we want to do the calculations. Typically we would want to use the whole partition and this will look like this:
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
This means that we want to work with the whole working set. By default if we do not add a this range each function will return the result related to the current record. The following demonstrates both cases to make it easier for understanding .
WITH total_sales_per_product (product_id, unit_total_sales) AS ( SELECT p.product_id, SUM(quantity) as sales FROM order_details JOIN products p on order_details.product_id = p.product_id GROUP BY p.product_id ) SELECT p.product_name, category_name, unit_total_sales, FIRST_VALUE(product_name) OVER ( PARTITION BY category_name ORDER BY unit_total_sales RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) as lowest_sales_per_category, NTH_VALUE(product_name, 2) OVER ( PARTITION BY category_name ORDER BY unit_total_sales RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as second_lowest_sales_per_category, LAST_VALUE(product_name) OVER ( PARTITION BY category_name ORDER BY unit_total_sales RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as highest_sales_per_category, LAST_VALUE(product_name) OVER ( PARTITION BY category_name ORDER BY unit_total_sales) as highest_sales_per_category_unbound_no_frame FROM products p JOIN total_sales_per_product ON total_sales_per_product.product_id = p.product_id JOIN categories c on p.category_id = c.category_id;
Here we are calculating the total units sold for each product. Then we are partitioning per category and we want to see the products with the lowest sales, the second lowest sales, and the highest sales for the particular category. Notice how the two last columns with LAST_VALUE()
behave with and without the frame definition.
product_name | category_name | unit_total_sales | lowest_sales_per_category | second_lowest_sales_per_category | highest_sales_per_category | highest_sales_per_category_unbound_no_frame |
---|---|---|---|---|---|---|
Laughing Lumberjack Lager | Beverages | 184 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Laughing Lumberjack Lager |
Sasquatch Ale | Beverages | 506 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Sasquatch Ale |
Ipoh Coffee | Beverages | 580 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Ipoh Coffee |
Côte de Blaye | Beverages | 623 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Côte de Blaye |
Chartreuse verte | Beverages | 793 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Chartreuse verte |
Outback Lager | Beverages | 817 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Outback Lager |
Chai | Beverages | 828 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Chai |
Steeleye Stout | Beverages | 883 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Steeleye Stout |
Lakkalikööri | Beverages | 981 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Lakkalikööri |
Chang | Beverages | 1057 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Chang |
Guaraná Fantástica | Beverages | 1125 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Guaraná Fantástica |
Rhönbräu Klosterbier | Beverages | 1155 | Laughing Lumberjack Lager | Sasquatch Ale | Rhönbräu Klosterbier | Rhönbräu Klosterbier |
Genen Shouyu | Condiments | 122 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Genen Shouyu |
Louisiana Hot Spiced Okra | Condiments | 239 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Louisiana Hot Spiced Okra |
Chef Anton's Gumbo Mix | Condiments | 298 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Chef Anton's Gumbo Mix |
Grandma's Boysenberry Spread | Condiments | 301 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Grandma's Boysenberry Spread |
Aniseed Syrup | Condiments | 328 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Aniseed Syrup |
Northwoods Cranberry Sauce | Condiments | 372 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Northwoods Cranberry Sauce |
Vegie-spread | Condiments | 445 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Vegie-spread |
Chef Anton's Cajun Seasoning | Condiments | 453 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Chef Anton's Cajun Seasoning |
Gula Malacca | Condiments | 601 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Gula Malacca |
Sirop d'érable | Condiments | 603 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Sirop d'érable |
Louisiana Fiery Hot Pepper Sauce | Condiments | 745 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Louisiana Fiery Hot Pepper Sauce |
Original Frankfurter grüne Soße | Condiments | 791 | Genen Shouyu | Louisiana Hot Spiced Okra | Original Frankfurter grüne Soße | Original Frankfurter grüne Soße |
Chocolade | Confections | 138 | Chocolade | Valkoinen suklaa | Pavlova | Chocolade |
Valkoinen suklaa | Confections | 235 | Chocolade | Valkoinen suklaa | Pavlova | Valkoinen suklaa |
Sir Rodney's Marmalade | Confections | 313 | Chocolade | Valkoinen suklaa | Pavlova | Sir Rodney's Marmalade |
NuNuCa Nuß-Nougat-Creme | Confections | 318 | Chocolade | Valkoinen suklaa | Pavlova | NuNuCa Nuß-Nougat-Creme |
Schoggi Schokolade | Confections | 365 | Chocolade | Valkoinen suklaa | Pavlova | Schoggi Schokolade |
Zaanse koeken | Confections | 485 | Chocolade | Valkoinen suklaa | Pavlova | Zaanse koeken |
Maxilaku | Confections | 520 | Chocolade | Valkoinen suklaa | Pavlova | Maxilaku |
Teatime Chocolate Biscuits | Confections | 723 | Chocolade | Valkoinen suklaa | Pavlova | Teatime Chocolate Biscuits |
Gumbär Gummibärchen | Confections | 753 | Chocolade | Valkoinen suklaa | Pavlova | Gumbär Gummibärchen |
Scottish Longbreads | Confections | 799 | Chocolade | Valkoinen suklaa | Pavlova | Scottish Longbreads |
Sir Rodney's Scones | Confections | 1016 | Chocolade | Valkoinen suklaa | Pavlova | Sir Rodney's Scones |
Tarte au sucre | Confections | 1083 | Chocolade | Valkoinen suklaa | Pavlova | Tarte au sucre |
Pavlova | Confections | 1158 | Chocolade | Valkoinen suklaa | Pavlova | Pavlova |
Mascarpone Fabioli | Dairy Products | 297 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Mascarpone Fabioli |
Queso Manchego La Pastora | Dairy Products | 344 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Queso Manchego La Pastora |
Queso Cabrales | Dairy Products | 706 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Queso Cabrales |
Gudbrandsdalsost | Dairy Products | 714 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Gudbrandsdalsost |
Geitost | Dairy Products | 755 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Geitost |
Mozzarella di Giovanni | Dairy Products | 806 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Mozzarella di Giovanni |
Flotemysost | Dairy Products | 1057 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Flotemysost |
Gorgonzola Telino | Dairy Products | 1397 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Gorgonzola Telino |
Raclette Courdavault | Dairy Products | 1496 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Raclette Courdavault |
Camembert Pierrot | Dairy Products | 1577 | Mascarpone Fabioli | Queso Manchego La Pastora | Camembert Pierrot | Camembert Pierrot |
Gustaf's Knäckebröd | Grains/Cereals | 348 | Gustaf's Knäckebröd | Ravioli Angelo | Gnocchi di nonna Alice | Gustaf's Knäckebröd |
Ravioli Angelo | Grains/Cereals | 434 | Gustaf's Knäckebröd | Ravioli Angelo | Gnocchi di nonna Alice | Ravioli Angelo |
Filo Mix | Grains/Cereals | 500 | Gustaf's Knäckebröd | Ravioli Angelo | Gnocchi di nonna Alice | Filo Mix |
Tunnbröd | Grains/Cereals | 580 | Gustaf's Knäckebröd | Ravioli Angelo | Gnocchi di nonna Alice | Tunnbröd |
Singaporean Hokkien Fried Mee | Grains/Cereals | 697 | Gustaf's Knäckebröd | Ravioli Angelo | Gnocchi di nonna Alice | Singaporean Hokkien Fried Mee |
Wimmers gute Semmelknödel | Grains/Cereals | 740 | Gustaf's Knäckebröd | Ravioli Angelo | Gnocchi di nonna Alice | Wimmers gute Semmelknödel |
Gnocchi di nonna Alice | Grains/Cereals | 1263 | Gustaf's Knäckebröd | Ravioli Angelo | Gnocchi di nonna Alice | Gnocchi di nonna Alice |
Mishi Kobe Niku | Meat/Poultry | 95 | Mishi Kobe Niku | Perth Pasties | Alice Mutton | Mishi Kobe Niku |
Perth Pasties | Meat/Poultry | 722 | Mishi Kobe Niku | Perth Pasties | Alice Mutton | Perth Pasties |
Thüringer Rostbratwurst | Meat/Poultry | 746 | Mishi Kobe Niku | Perth Pasties | Alice Mutton | Thüringer Rostbratwurst |
Tourtière | Meat/Poultry | 755 | Mishi Kobe Niku | Perth Pasties | Alice Mutton | Tourtière |
Pâté chinois | Meat/Poultry | 903 | Mishi Kobe Niku | Perth Pasties | Alice Mutton | Pâté chinois |
Alice Mutton | Meat/Poultry | 978 | Mishi Kobe Niku | Perth Pasties | Alice Mutton | Alice Mutton |
Longlife Tofu | Produce | 297 | Longlife Tofu | Tofu | Manjimup Dried Apples | Longlife Tofu |
Tofu | Produce | 404 | Longlife Tofu | Tofu | Manjimup Dried Apples | Tofu |
Rössle Sauerkraut | Produce | 640 | Longlife Tofu | Tofu | Manjimup Dried Apples | Rössle Sauerkraut |
Uncle Bob's Organic Dried Pears | Produce | 763 | Longlife Tofu | Tofu | Manjimup Dried Apples | Uncle Bob's Organic Dried Pears |
Manjimup Dried Apples | Produce | 886 | Longlife Tofu | Tofu | Manjimup Dried Apples | Manjimup Dried Apples |
Gravad lax | Seafood | 125 | Gravad lax | Röd Kaviar | Boston Crab Meat | Gravad lax |
Röd Kaviar | Seafood | 293 | Gravad lax | Röd Kaviar | Boston Crab Meat | Röd Kaviar |
Rogede sild | Seafood | 508 | Gravad lax | Röd Kaviar | Boston Crab Meat | Rogede sild |
Escargots de Bourgogne | Seafood | 534 | Gravad lax | Röd Kaviar | Boston Crab Meat | Escargots de Bourgogne |
Carnarvon Tigers | Seafood | 539 | Gravad lax | Röd Kaviar | Boston Crab Meat | Carnarvon Tigers |
Spegesild | Seafood | 548 | Gravad lax | Röd Kaviar | Boston Crab Meat | Spegesild |
Nord-Ost Matjeshering | Seafood | 612 | Gravad lax | Röd Kaviar | Boston Crab Meat | Nord-Ost Matjeshering |
Ikura | Seafood | 742 | Gravad lax | Röd Kaviar | Boston Crab Meat | Ikura |
Inlagd Sill | Seafood | 805 | Gravad lax | Röd Kaviar | Boston Crab Meat | Inlagd Sill |
Konbu | Seafood | 891 | Gravad lax | Röd Kaviar | Boston Crab Meat | Konbu |
Jack's New England Clam Chowder | Seafood | 981 | Gravad lax | Röd Kaviar | Boston Crab Meat | Jack's New England Clam Chowder |
Boston Crab Meat | Seafood | 1103 | Gravad lax | Röd Kaviar | Boston Crab Meat | Boston Crab Meat |
Rolling Averages
Now that we discussed a bit about frames, it is a good opportunity to see how we can implement rolling averages with window function syntax in PostgreSQL.
We can use the frames for this. A frame is the subset of the current partition. To define a frame, we can use:
- RANGE (example above): the offset of the current row and frame rows are row values.
- ROWS (number of rows to include): the offsets of the current row and frame rows are row numbers.
For every frame we need to define a START and an END.
- START:
- N PRECEDING-> the frame starts at nth rows before the current row.
- UNBOUND PRECEDING -> the frame starts at the first row of the partition.
- CURRENT ROW -> the row that is being evaluated
- END:
- CURRENT ROW -> the row that is being evaluated
- UNBOUND FOLLOWING-> the frame ends at the final row in the partition.
- N FOLLOWING-> the frame ends at the nth row after the current row.
This may be confusing in the beginning but with some practice it will become easier. SQL being an expressive language helps as well. Check the example with LAST_VALUE
for example, where we essentially specify a BETWEEN
.
Let us see a simple example with a rolling average for the current row and 3 rows preceding the current row.
SELECT product_id, product_name, unit_price, category_id, AVG(unit_price) OVER(PARTITION BY category_id) AS average_unit_price_in_category, AVG(unit_price) OVER(PARTITION BY category_id ROWS 3 PRECEDING) AS avg_3_rows_preceding FROM products WHERE not discontinued::bool;
Check the values in the output:
product_name | unit_price | category_id | average_unit_price_in_category | avg_3_rows_preceding |
---|---|---|---|---|
Rhönbräu Klosterbier | 7.75 | 1 | 46.02777777777778 | 7.75 |
Sasquatch Ale | 14 | 1 | 46.02777777777778 | 10.875 |
Laughing Lumberjack Lager | 14 | 1 | 46.02777777777778 | 11.916666666666666 |
Outback Lager | 15 | 1 | 46.02777777777778 | 12.6875 |
Steeleye Stout | 18 | 1 | 46.02777777777778 | 15.25 |
Lakkalikööri | 18 | 1 | 46.02777777777778 | 16.25 |
Chartreuse verte | 18 | 1 | 46.02777777777778 | 17.25 |
Ipoh Coffee | 46 | 1 | 46.02777777777778 | 25 |
Côte de Blaye | 263.5 | 1 | 46.02777777777778 | 86.375 |
Aniseed Syrup | 10 | 2 | 22.990909229625355 | 10 |
Original Frankfurter grüne Soße | 13 | 2 | 22.990909229625355 | 11.5 |
Genen Shouyu | 13 | 2 | 22.990909229625355 | 12 |
Louisiana Hot Spiced Okra | 17 | 2 | 22.990909229625355 | 13.25 |
Gula Malacca | 19.45 | 2 | 22.990909229625355 | 15.612500190734863 |
Louisiana Fiery Hot Pepper Sauce | 21.05 | 2 | 22.990909229625355 | 17.625 |
Chef Anton's Cajun Seasoning | 22 | 2 | 22.990909229625355 | 19.875 |
Grandma's Boysenberry Spread | 25 | 2 | 22.990909229625355 | 21.875 |
Sirop d'érable | 28.5 | 2 | 22.990909229625355 | 24.137499809265137 |
Northwoods Cranberry Sauce | 40 | 2 | 22.990909229625355 | 28.875 |
Vegie-spread | 43.9 | 2 | 22.990909229625355 | 34.35000038146973 |
Teatime Chocolate Biscuits | 9.2 | 3 | 25.1600000674908 | 9.199999809265137 |
Zaanse koeken | 9.5 | 3 | 25.1600000674908 | 9.349999904632568 |
Sir Rodney's Scones | 10 | 3 | 25.1600000674908 | 9.566666603088379 |
Scottish Longbreads | 12.5 | 3 | 25.1600000674908 | 10.299999952316284 |
Chocolade | 12.75 | 3 | 25.1600000674908 | 11.1875 |
NuNuCa Nuß-Nougat-Creme | 14 | 3 | 25.1600000674908 | 12.3125 |
Valkoinen suklaa | 16.25 | 3 | 25.1600000674908 | 13.875 |
Pavlova | 17.45 | 3 | 25.1600000674908 | 15.112500190734863 |
Maxilaku | 20 | 3 | 25.1600000674908 | 16.925000190734863 |
Gumbär Gummibärchen | 31.23 | 3 | 25.1600000674908 | 21.232500076293945 |
Schoggi Schokolade | 43.9 | 3 | 25.1600000674908 | 28.145000457763672 |
Tarte au sucre | 49.3 | 3 | 25.1600000674908 | 36.107500076293945 |
Sir Rodney's Marmalade | 81 | 3 | 25.1600000674908 | 51.357500076293945 |
Geitost | 2.5 | 4 | 28.729999923706053 | 2.5 |
Gorgonzola Telino | 12.5 | 4 | 28.729999923706053 | 7.5 |
Queso Cabrales | 21 | 4 | 28.729999923706053 | 12 |
Flotemysost | 21.5 | 4 | 28.729999923706053 | 14.375 |
Mascarpone Fabioli | 32 | 4 | 28.729999923706053 | 21.75 |
Camembert Pierrot | 34 | 4 | 28.729999923706053 | 27.125 |
Mozzarella di Giovanni | 34.8 | 4 | 28.729999923706053 | 30.574999809265137 |
Gudbrandsdalsost | 36 | 4 | 28.729999923706053 | 34.19999980926514 |
Queso Manchego La Pastora | 38 | 4 | 28.729999923706053 | 35.69999980926514 |
Raclette Courdavault | 55 | 4 | 28.729999923706053 | 40.94999980926514 |
Filo Mix | 7 | 5 | 21.291666666666668 | 7 |
Tunnbröd | 9 | 5 | 21.291666666666668 | 8 |
Ravioli Angelo | 19.5 | 5 | 21.291666666666668 | 11.833333333333334 |
Gustaf's Knäckebröd | 21 | 5 | 21.291666666666668 | 14.125 |
Wimmers gute Semmelknödel | 33.25 | 5 | 21.291666666666668 | 20.6875 |
Gnocchi di nonna Alice | 38 | 5 | 21.291666666666668 | 27.9375 |
Tourtière | 7.45 | 6 | 15.724999904632568 | 7.449999809265137 |
Pâté chinois | 24 | 6 | 15.724999904632568 | 15.724999904632568 |
Longlife Tofu | 10 | 7 | 29.0625 | 10 |
Tofu | 23.25 | 7 | 29.0625 | 16.625 |
Uncle Bob's Organic Dried Pears | 30 | 7 | 29.0625 | 21.083333333333332 |
Manjimup Dried Apples | 53 | 7 | 29.0625 | 29.0625 |
Konbu | 6 | 8 | 20.682499885559082 | 6 |
Rogede sild | 9.5 | 8 | 20.682499885559082 | 7.75 |
Jack's New England Clam Chowder | 9.65 | 8 | 20.682499885559082 | 8.383333206176758 |
Spegesild | 12 | 8 | 20.682499885559082 | 9.287499904632568 |
Escargots de Bourgogne | 13.25 | 8 | 20.682499885559082 | 11.099999904632568 |
Röd Kaviar | 15 | 8 | 20.682499885559082 | 12.474999904632568 |
Boston Crab Meat | 18.4 | 8 | 20.682499885559082 | 14.662499904632568 |
Inlagd Sill | 19 | 8 | 20.682499885559082 | 16.41249990463257 |
Nord-Ost Matjeshering | 25.89 | 8 | 20.682499885559082 | 19.572499752044678 |
Gravad lax | 26 | 8 | 20.682499885559082 | 22.322499752044678 |
Ikura | 31 | 8 | 20.682499885559082 | 25.47249984741211 |
Carnarvon Tigers | 62.5 | 8 | 20.682499885559082 | 36.34749984741211 |
For each row we calculate the general average and the rolling average of the current row based on current row’s price and the prices of the three previous rows.
That would be all. We covered all the available window functions in PostgreSQL and we discussed introductory about create sub groups within the same partition with frames. As we saw they are very powerful constructs that occasionally can save us a ton of extra work to reach the desired outcome.
Window functions is possibly one of the most advanced topics when studying SQL and getting to understand them will add an extremely useful tool under your belt.