{"id":239,"date":"2018-02-09T22:47:51","date_gmt":"2018-02-09T22:47:51","guid":{"rendered":"http:\/\/eipsoftware.com\/musings\/?p=239"},"modified":"2018-02-19T22:49:03","modified_gmt":"2018-02-19T22:49:03","slug":"oracle-pl-sql-more-aggregation-rank","status":"publish","type":"post","link":"https:\/\/eipsoftware.com\/musings\/oracle-pl-sql-more-aggregation-rank\/","title":{"rendered":"Oracle PL\/SQL More Aggregation &#8211; Rank"},"content":{"rendered":"<h4>Oracle PL\/SQL Aggregation\u00a0 &#8211; Rank<\/h4>\n<p>One of the more interesting aggregation functions is <strong>RANK<\/strong>.\u00a0 After doing a standard <strong>SELECT<\/strong> and <strong>GROUP BY<\/strong>; you can then have SQL rank the results using an aggregated value from another column.<\/p>\n<p>Let&#8217;s dive in and look at how <strong>RANK<\/strong> works and what can it do for us.<!--more--><\/p>\n<h5>Rank<\/h5>\n<p>When using the RANK you will need to specify which column you want to RANK on.<\/p>\n<pre class=\"lang:plsql decode:true \">SELECT      cust_vendor_dim.name\r\n            ,SUM(EXTCOST) AS sum_extcost\r\n            ,RANK() OVER (ORDER BY SUM(EXTCOST) DESC) AS rank_Customer\r\nFROM        inventory_fact\r\n            INNER JOIN cust_vendor_dim\r\n                ON inventory_fact.custvendorkey = cust_vendor_dim.custvendorkey\r\nWHERE       transtypekey = 5 -- 'Sales Order Shipment'\r\nGROUP BY    cust_vendor_dim.name\r\n;<\/pre>\n<p>Here we will rank the cust_vendor_dim.name by the <strong>SUM<\/strong> of the extcost column.\u00a0 In addition the results will be returned in <strong>DESC<\/strong> order. <strong>DESC<\/strong> means descending order, highest value listed first. We will still need to use the<strong> GROUP BY<\/strong> operator to group by cust_vendor_dim.name.<\/p>\n<h5>Rank Partition<\/h5>\n<p>One of the options we can do with <strong>RANK<\/strong> is to partition the ranking results.\u00a0 In other words when there is a change in value for a specified column, the ranking will restart.<\/p>\n<pre class=\"lang:plsql decode:true \">SELECT      cust_vendor_dim.state\r\n            ,cust_vendor_dim.name\r\n            ,SUM(EXTCOST) AS sum_extcost\r\n            ,RANK() OVER (  PARTITION BY cust_vendor_dim.state\r\n                            ORDER BY SUM(EXTCOST) DESC) AS rank_Customer\r\nFROM        inventory_fact\r\n            INNER JOIN cust_vendor_dim\r\n                ON inventory_fact.custvendorkey = cust_vendor_dim.custvendorkey\r\nWHERE       transtypekey = 5 -- 'Sales Order Shipment'\r\nGROUP BY    cust_vendor_dim.state\r\n            ,cust_vendor_dim.name\r\nORDER BY    cust_vendor_dim.state\r\n;\r\n<\/pre>\n<p>In this example the query will partition by cust_vendor_dim.state, therefore when the previous rows value in\u00a0cust_vendor_dim.state is different from the current rows value the ranking will restart with 1.\u00a0 The query needs to use the <strong>ORDER BY<\/strong> operator to get the correct results.<\/p>\n<h5><\/h5>\n<h5>Dense_Rank<\/h5>\n<p>A variation of <strong>RANK<\/strong> is <strong>DENSE_RANK<\/strong>, the primary difference is that <strong>DENSE_RANK<\/strong> will not skip sequential order of numbers when two rows have the same value.\u00a0 <strong>DENSE_RANK<\/strong> will show them as having the same rank and the next row will have the next sequential number.<\/p>\n<p>An example would be <strong>DENSE_RANK<\/strong> values of 1,2,3,3,3,4,5,5,6.\u00a0 Where RANK would show the same result as 1,2,3,3,3,6,7,7,9<\/p>\n<pre class=\"lang:plsql decode:true \">SELECT      cust_vendor_dim.name\r\n            ,COUNT(inventorykey)\r\n            ,RANK() OVER (ORDER BY COUNT(inventorykey) DESC) AS rank_Customer\r\n            ,DENSE_RANK() OVER (ORDER BY COUNT(inventorykey) DESC) AS dense_rank_Customer\r\nFROM        inventory_fact\r\n            INNER JOIN cust_vendor_dim\r\n                ON inventory_fact.custvendorkey = cust_vendor_dim.custvendorkey\r\nWHERE       transtypekey = 5 -- 'Sales Order Shipment'\r\nGROUP BY    cust_vendor_dim.name\r\n;<\/pre>\n<p>&nbsp;<\/p>\n<h5><strong>Cumulative Sum<\/strong><\/h5>\n<p>One of the most common tasks in grouping is to show a cumulative sum for the column values. with using aggregate <strong>SUM<\/strong> with the <strong>OVER<\/strong> option you can create a cumulative sum for the specified grouping levels.<\/p>\n<pre class=\"lang:plsql decode:true \">SELECT      zip\r\n            ,calyear\r\n            ,calmonth\r\n           ,SUM(EXTCOST) AS sum_extcost\r\n           ,SUM( SUM(EXTCOST)) OVER(ORDER BY zip,calyear,calmonth\r\n                                    ROWS UNBOUNDED PRECEDING\r\n                                ) AS cumulative_extcost\r\nFROM        inventory_fact\r\n            INNER JOIN date_dim\r\n                ON inventory_fact.datekey = date_dim.datekey\r\n            INNER JOIN cust_vendor_dim\r\n                ON inventory_fact.custvendorkey = cust_vendor_dim.custvendorkey\r\nWHERE       transtypekey = 5 -- 'Sales Order Shipment'\r\nGROUP BY    zip\r\n            ,calyear\r\n            ,calmonth\r\n;<\/pre>\n<p>In the example above query will produce a cumulative sum for each group of zip, calyear, calmonth. The ROWS option specifies to look at all preceding rows.<\/p>\n<p>I hope you found the above informative, let me know if you have any questions in the comments below.<\/p>\n<p><a href=\"mailto:michael.data@eipsoftware.com\">\u2014 michael.data@eipsoftware.com<\/a><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Oracle PL\/SQL Aggregation\u00a0 &#8211; Rank One of the more interesting aggregation functions is RANK.\u00a0 After doing a standard SELECT and GROUP BY; you can then have SQL rank the results using an aggregated value from another column. Let&#8217;s dive in and look at how RANK works and what can it do for us.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","footnotes":""},"categories":[4,44,6],"tags":[14,30,48,49],"series":[],"class_list":["post-239","post","type-post","status-publish","format-standard","hentry","category-code","category-oracle-pl-sql","category-sql","tag-sql","tag-code","tag-pl-sql","tag-oracle"],"_links":{"self":[{"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/posts\/239","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/comments?post=239"}],"version-history":[{"count":6,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/posts\/239\/revisions"}],"predecessor-version":[{"id":246,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/posts\/239\/revisions\/246"}],"wp:attachment":[{"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/media?parent=239"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/categories?post=239"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/tags?post=239"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/series?post=239"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}