{"id":7032,"date":"2023-06-05T00:00:00","date_gmt":"2023-06-05T04:00:00","guid":{"rendered":"https:\/\/www.sisense.com\/rolling-average\/"},"modified":"2024-09-23T15:25:29","modified_gmt":"2024-09-23T19:25:29","slug":"rolling-average","status":"publish","type":"post","link":"https:\/\/www.sisense.com\/blog\/rolling-average\/","title":{"rendered":"Rolling averages in MySQL and SQL server"},"content":{"rendered":"<p><\/p>\r\n<p>Previously we discussed how to write rolling averages in Postgres. By popular demand, we\u2019re showing you how to do the same in MySQL and SQL Server.<\/p>\r\n<p>We\u2019ll cover how to annotate noisy charts like this:<\/p>\r\n<figure class=\"wp-block-image fancybox\"><img decoding=\"async\" class=\"wp-image-73876\" src=\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/New-customers-rolling-blog.png\" alt=\"New customers chart\" \/><\/figure>\r\n<p>With a 7-day preceding average line like this:<\/p>\r\n<figure class=\"wp-block-image fancybox\"><img decoding=\"async\" class=\"wp-image-73881\" src=\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/New-customers-7-day-rolling-blog.png\" alt=\"New customers 7 day chart\" \/><\/figure>\r\n<h2>The big idea<\/h2>\r\n<p>Our first graph above is pretty noisy and hard to get useful information from. We can smooth it out by plotting a 7-day average on top of the underlying data. This can be done with window functions, self-joins, or correlated subqueries \u2014 we\u2019ll cover the first two.<\/p>\r\n<p>We\u2019ll start with a preceding average, which means that the average point on the 7th of the month is the average of the first seven days.<\/p>\r\n<p>Visually this shifts the spikes in the graph to the right, as a big spike is averaged over the following seven days.<\/p>\r\n<h2>First, Create an intermediate count table<\/h2>\r\n<p>We want to compute an average over the total signups for each day. Assuming we have a typical users table with a row per new user and a timestamp created_at, we can create our aggregate signups table like so:<\/p>\r\n<pre class=\"wp-block-code\"><code>select\r\n  created_at::date as date,\r\n  count(1) as value\r\nfrom new_customers\r\ngroup by 1<\/code><\/pre>\r\n<p>In Postgres and SQL Server, you can use this as a CTE. In MySQL, you can save it as a temporary table.<\/p>\r\n<p><strong>Postgres Rolling Average<\/strong><\/p>\r\n<p>Fortunately Postgres has window functions which are the simplest way to compute a running average.<\/p>\r\n<pre class=\"wp-block-code\"><code>select\r\n  date,\r\n  value,\r\n  avg(value) \r\n    over (order by date asc\r\n          rows between 6 preceding and current row) as avg,\r\nfrom signups\r\norder by 1 desc<\/code><\/pre>\r\n<p>This query assumes that the dates do not have gaps. The query is averaging over the past seven rows, not the past seven dates. If your data has gaps, fill them in with generate_series or joining against a table with dense date rows.<\/p>\r\n<h2>MySQL rolling average<\/h2>\r\n<p>MySQL lacks window functions, but we can do a similar computation using self joins. For each row in our count table, we join every row that was within the past seven days and take the average.<\/p>\r\n<pre class=\"wp-block-code\"><code>select signups.date, signups.count, avg(signups_past.count)\r\nfrom signups\r\njoin signups as signups_past \r\n  on signups_past.date between signups.date - 6 and signups.date\r\ngroup by 1, 2<\/code><\/pre>\r\n<p>This query automatically handles date gaps, as we are looking at rows within a date range rather than the preceding N rows.<\/p>\r\n<h2>SQL server rolling average<\/h2>\r\n<p>SQL Server has window functions, so computing the rolling average can be done in either the Postgres style or MySQL style. For simplicity, we\u2019re using the MySQL version with a self join.<\/p>\r\n<p>This is conceptually the same as in MySQL. The only translations are the dateadd function and explicitly named group by columns.<\/p>\r\n<pre class=\"wp-block-code\"><code>select signups.date, signups.count, avg(signups_past.count)\r\nfrom signups\r\njoin signups as signups_past \r\n  on signups_past.date \r\n     between dateadd(day, -6, signups.date) and signups.date\r\ngroup by signups.date, signups.count<\/code><\/pre>\r\n<h2>Other averages<\/h2>\r\n<p>We focused on the 7-day trailing average in this post. If we wanted to look at the 7-day leading average, it\u2019s as simple as sorting the dates in the other direction. If we wanted to look at a centered average, we\u2019d use:<\/p>\r\n<ul>\r\n<li>Postgres: rows between 3 preceding and 3 following<\/li>\r\n<li>MySql: between signups.date &#8211; 3 and signups.date + 3 in MySQL<\/li>\r\n<li>SQL Server: between dateadd(day, -3, signups.date) and dateadd(day, 3, signups.date)<\/li>\r\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Previously we discussed how to write rolling averages in Postgres. By popular demand, we\u2019re showing you how to do the same in MySQL and SQL Server. We\u2019ll cover how to annotate noisy charts like this: With a 7-day preceding average&#8230;<\/p>\n","protected":false},"author":4,"featured_media":7218,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_searchwp_excluded":"","footnotes":"","_links_to":"","_links_to_target":""},"categories":[44],"tags":[472],"application":[46],"buyer-role":[],"buyer-stage":[],"department":[],"industry":[],"topic":[73],"class_list":["post-7032","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech-talk","tag-data-team","application-bi-analytics-teams","topic-sql-superstar"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v23.5 (Yoast SEO v23.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Rolling Averages in MySQL and SQL Server | Sisense<\/title>\n<meta name=\"description\" content=\"Read this guide on how to write rolling averages in MySQL and SQL Server and learn to annotate your noisy charts to get more out of your data.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.sisense.com\/blog\/rolling-average\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Rolling averages in MySQL and SQL server\" \/>\n<meta property=\"og:description\" content=\"Previously we discussed how to write rolling averages in Postgres. By popular demand, we\u2019re showing you how to do the same in MySQL and SQL Server. We\u2019ll\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sisense.com\/blog\/rolling-average\/\" \/>\n<meta property=\"og:site_name\" content=\"Sisense\" \/>\n<meta property=\"article:published_time\" content=\"2023-06-05T04:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-09-23T19:25:29+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/yoast-rolling-blog-min.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Sisense Team\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/yoast-rolling-blog-min.jpg\" \/>\n<meta name=\"twitter:creator\" content=\"@sisense\" \/>\n<meta name=\"twitter:site\" content=\"@sisense\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sisense Team\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/\"},\"author\":{\"name\":\"Sisense Team\",\"@id\":\"https:\/\/www.sisense.com\/#\/schema\/person\/e70aa3a7bbc471e4b7b8c5a7d2b36115\"},\"headline\":\"Rolling averages in MySQL and SQL server\",\"datePublished\":\"2023-06-05T04:00:00+00:00\",\"dateModified\":\"2024-09-23T19:25:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/\"},\"wordCount\":475,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.sisense.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/2014\/12\/10161802\/featured-rolling-blog-min.jpg\",\"keywords\":[\"data team\"],\"articleSection\":[\"Tech Talk\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.sisense.com\/blog\/rolling-average\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/\",\"url\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/\",\"name\":\"Rolling Averages in MySQL and SQL Server | Sisense\",\"isPartOf\":{\"@id\":\"https:\/\/www.sisense.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/2014\/12\/10161802\/featured-rolling-blog-min.jpg\",\"datePublished\":\"2023-06-05T04:00:00+00:00\",\"dateModified\":\"2024-09-23T19:25:29+00:00\",\"description\":\"Read this guide on how to write rolling averages in MySQL and SQL Server and learn to annotate your noisy charts to get more out of your data.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sisense.com\/blog\/rolling-average\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/#primaryimage\",\"url\":\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/2014\/12\/10161802\/featured-rolling-blog-min.jpg\",\"contentUrl\":\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/2014\/12\/10161802\/featured-rolling-blog-min.jpg\",\"width\":1200,\"height\":628,\"caption\":\"featured rolling blog min\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sisense.com\/blog\/rolling-average\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sisense.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Rolling averages in MySQL and SQL server\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sisense.com\/#website\",\"url\":\"https:\/\/www.sisense.com\/\",\"name\":\"Sisense\",\"description\":\"Build your business with anywhere-analytics\",\"publisher\":{\"@id\":\"https:\/\/www.sisense.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sisense.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.sisense.com\/#organization\",\"name\":\"Sisense\",\"url\":\"https:\/\/www.sisense.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sisense.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/sisense-yoast-og.jpg\",\"contentUrl\":\"https:\/\/cdn.sisense.com\/wp-content\/uploads\/sisense-yoast-og.jpg\",\"width\":1200,\"height\":600,\"caption\":\"Sisense\"},\"image\":{\"@id\":\"https:\/\/www.sisense.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/sisense\",\"https:\/\/www.linkedin.com\/company\/sisense\",\"https:\/\/github.com\/sisense\/\"],\"description\":\"Sisense accelerates product innovation through AI\/ML capabilities. Our global analytics platform lets customers drive better, faster decisions for their business and end users.\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sisense.com\/#\/schema\/person\/e70aa3a7bbc471e4b7b8c5a7d2b36115\",\"name\":\"Sisense Team\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sisense.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/213e415f47bc3c7f0155a0755b1cea8c?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/213e415f47bc3c7f0155a0755b1cea8c?s=96&d=mm&r=g\",\"caption\":\"Sisense Team\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Rolling Averages in MySQL and SQL Server | Sisense","description":"Read this guide on how to write rolling averages in MySQL and SQL Server and learn to annotate your noisy charts to get more out of your data.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.sisense.com\/blog\/rolling-average\/","og_locale":"en_US","og_type":"article","og_title":"Rolling averages in MySQL and SQL server","og_description":"Previously we discussed how to write rolling averages in Postgres. By popular demand, we\u2019re showing you how to do the same in MySQL and SQL Server. We\u2019ll","og_url":"https:\/\/www.sisense.com\/blog\/rolling-average\/","og_site_name":"Sisense","article_published_time":"2023-06-05T04:00:00+00:00","article_modified_time":"2024-09-23T19:25:29+00:00","og_image":[{"width":1200,"height":628,"url":"https:\/\/cdn.sisense.com\/wp-content\/uploads\/yoast-rolling-blog-min.jpg","type":"image\/jpeg"}],"author":"Sisense Team","twitter_card":"summary_large_image","twitter_image":"https:\/\/cdn.sisense.com\/wp-content\/uploads\/yoast-rolling-blog-min.jpg","twitter_creator":"@sisense","twitter_site":"@sisense","twitter_misc":{"Written by":"Sisense Team","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/#article","isPartOf":{"@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/"},"author":{"name":"Sisense Team","@id":"https:\/\/www.sisense.com\/#\/schema\/person\/e70aa3a7bbc471e4b7b8c5a7d2b36115"},"headline":"Rolling averages in MySQL and SQL server","datePublished":"2023-06-05T04:00:00+00:00","dateModified":"2024-09-23T19:25:29+00:00","mainEntityOfPage":{"@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/"},"wordCount":475,"commentCount":0,"publisher":{"@id":"https:\/\/www.sisense.com\/#organization"},"image":{"@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/#primaryimage"},"thumbnailUrl":"https:\/\/cdn.sisense.com\/wp-content\/uploads\/2014\/12\/10161802\/featured-rolling-blog-min.jpg","keywords":["data team"],"articleSection":["Tech Talk"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.sisense.com\/blog\/rolling-average\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/","url":"https:\/\/www.sisense.com\/blog\/rolling-average\/","name":"Rolling Averages in MySQL and SQL Server | Sisense","isPartOf":{"@id":"https:\/\/www.sisense.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/#primaryimage"},"image":{"@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/#primaryimage"},"thumbnailUrl":"https:\/\/cdn.sisense.com\/wp-content\/uploads\/2014\/12\/10161802\/featured-rolling-blog-min.jpg","datePublished":"2023-06-05T04:00:00+00:00","dateModified":"2024-09-23T19:25:29+00:00","description":"Read this guide on how to write rolling averages in MySQL and SQL Server and learn to annotate your noisy charts to get more out of your data.","breadcrumb":{"@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sisense.com\/blog\/rolling-average\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/#primaryimage","url":"https:\/\/cdn.sisense.com\/wp-content\/uploads\/2014\/12\/10161802\/featured-rolling-blog-min.jpg","contentUrl":"https:\/\/cdn.sisense.com\/wp-content\/uploads\/2014\/12\/10161802\/featured-rolling-blog-min.jpg","width":1200,"height":628,"caption":"featured rolling blog min"},{"@type":"BreadcrumbList","@id":"https:\/\/www.sisense.com\/blog\/rolling-average\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sisense.com\/"},{"@type":"ListItem","position":2,"name":"Rolling averages in MySQL and SQL server"}]},{"@type":"WebSite","@id":"https:\/\/www.sisense.com\/#website","url":"https:\/\/www.sisense.com\/","name":"Sisense","description":"Build your business with anywhere-analytics","publisher":{"@id":"https:\/\/www.sisense.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sisense.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.sisense.com\/#organization","name":"Sisense","url":"https:\/\/www.sisense.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sisense.com\/#\/schema\/logo\/image\/","url":"https:\/\/cdn.sisense.com\/wp-content\/uploads\/sisense-yoast-og.jpg","contentUrl":"https:\/\/cdn.sisense.com\/wp-content\/uploads\/sisense-yoast-og.jpg","width":1200,"height":600,"caption":"Sisense"},"image":{"@id":"https:\/\/www.sisense.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/sisense","https:\/\/www.linkedin.com\/company\/sisense","https:\/\/github.com\/sisense\/"],"description":"Sisense accelerates product innovation through AI\/ML capabilities. Our global analytics platform lets customers drive better, faster decisions for their business and end users."},{"@type":"Person","@id":"https:\/\/www.sisense.com\/#\/schema\/person\/e70aa3a7bbc471e4b7b8c5a7d2b36115","name":"Sisense Team","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sisense.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/213e415f47bc3c7f0155a0755b1cea8c?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/213e415f47bc3c7f0155a0755b1cea8c?s=96&d=mm&r=g","caption":"Sisense Team"}}]}},"_links":{"self":[{"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/posts\/7032"}],"collection":[{"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/comments?post=7032"}],"version-history":[{"count":0,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/posts\/7032\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/media\/7218"}],"wp:attachment":[{"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/media?parent=7032"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/categories?post=7032"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/tags?post=7032"},{"taxonomy":"application","embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/application?post=7032"},{"taxonomy":"buyer-role","embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/buyer-role?post=7032"},{"taxonomy":"buyer-stage","embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/buyer-stage?post=7032"},{"taxonomy":"department","embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/department?post=7032"},{"taxonomy":"industry","embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/industry?post=7032"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.sisense.com\/wp-json\/wp\/v2\/topic?post=7032"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}