Goose
Goose

Reputation: 4821

How to get a rolling data set by week with sql

I had a sql query I would run that would get a rolling sum (or moving window) data set. I would run this query for every 7 days, increase the interval number by 7 (28 in example below) until I reached the start of the data. It would give me the data split by week so I can loop through it on the view to create a weekly graph.

  SELECT *
  FROM `table`
  WHERE `row_date` >= DATE_SUB(NOW(), INTERVAL 28 DAY)
  AND `row_date` <= DATE_SUB(NOW(), INTERVAL 28 DAY)

This is of course very slow once you have several weeks worth of data. I wanted to replace it with a single query. I came up with this.

  SELECT *
  CONCAT(YEAR(row_date), '/', WEEK(row_date)) as week_date
  FROM `table`
  GROUP BY week_date
  ORDER BY row_date DESC

It appeared mostly accurate, except I noticed the current week and the last week of 2015 was much lower than usual. That's because this query gets a week starting on Sunday (or Monday?) meaning that it resets weekly.

Here's a data set of employees that you can use to demonstrate the behavior.

CREATE TABLE employees (
    id          INT             NOT NULL,
    first_name  VARCHAR(14)     NOT NULL,
    last_name   VARCHAR(16)     NOT NULL,
    row_date    DATE            NOT NULL,
    PRIMARY KEY (id)
);

INSERT INTO `employees` VALUES
(1,'Bezalel','Simmel','2016-12-25'),
(2,'Bezalel','Simmel','2016-12-31'),
(3,'Bezalel','Simmel','2017-01-01'),
(4,'Bezalel','Simmel','2017-01-05')

This data will return the last 3 rows on the same data point on the old query (last 7 days) assuming you run it today 2017-01-06, but only the last 2 rows on the same data point on the new query (Sunday to Saturday).

For more information on what I mean by rolling or moving window, see this English stack exchange link.

https://english.stackexchange.com/questions/362791/word-for-graph-that-counts-backwards-vs-graph-that-counts-forwards

How can I write a query in MySQL that will bring me rolling data, where the last data point is the last 7 days of data, the previous point is the previous 7 days, and so on?

Upvotes: 0

Views: 5221

Answers (1)

I've had to interpret your question a lot so this answer might be unsuitable. It sounds like you are trying to get a graph showing data historically grouped into 7-day periods. Your current attempt does this by grouping on calendar week instead of by 7-day period leading to inconsistent size of periods.

So using a modification of your dataset on sql fiddle ( http://sqlfiddle.com/#!9/90f1f2 ) I have come up with this

  SELECT 
    -- Figure out how many periods of 7 days ago this record applies to
    FLOOR( DATEDIFF( CURRENT_DATE , row_date ) / 7 ) AS weeks_ago,
    -- Count the number of ids in this group
    COUNT( DISTINCT id ) AS number_in_week,
    -- Because this is grouped, make sure to have some consistency on what we select instead of leaving it to chance
    MIN( row_date ) AS min_date_in_week_in_dataset 
  FROM `sample_data`
  -- Groups by weeks ago because that's what you are interested in
  GROUP BY weeks_ago
  ORDER BY 
    min_date_in_week_in_dataset DESC;

Upvotes: 4

Related Questions