0

Ok, so I have two tables.

locations:

+----+-----------+
| id |   name    |
+----+-----------+
|  1 | Location1 |
|  2 | Location2 |
|  3 | Location3 |
+----+-----------+

location_ratings
+----+-------------+-----------+--------+
| id | location_id |   date    | rating |
+----+-------------+-----------+--------+
|  1 |           1 | 4/7/2017  |      1 |
|  2 |           1 | 7/3/2017  |      2 |
|  3 |           1 | 9/9/2017  |      5 |
|  4 |           1 | 11/2/2017 |      4 |
|  5 |           2 | 1/3/2017  |      3 |
|  9 |           2 | 3/7/2017  |      1 |
| 12 |           3 | 2/7/2017  |      2 |
| 13 |           3 | 3/4/2017  |      4 |
| 15 |           3 | 10/1/2017 |      1 |
+----+-------------+-----------+--------+

Locations get rated at random times and they keep that rating until they are rated again. The rating of a location that has not yet been rated is considered to be 0. So for Location1, it was a 0 until 4/7/01, then it was a 1 until 7/3, etc, etc.

I need to calculate the number of locations per rating per month, where a locations rating for the month is whatever it's rating was on the 1st day of the month.

So basically I want to find the rating of each farm on the first day of each month. So using the example data above, this would be the rating for each farm on the first of every month:

+---------------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+-----------+-----------+-----------+
| Location ID / Month | 1/1/2017 | 2/1/2017 | 3/1/2017 | 4/1/2017 | 5/1/2017 | 6/1/2017 | 7/1/2017 | 8/1/2017 | 9/1/2017 | 10/1/2017 | 11/1/2017 | 12/1/2017 |
+---------------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+-----------+-----------+-----------+
|                   1 |        0 |        0 |        0 |        0 |        1 |        1 |        1 |        2 |        2 |         5 |         5 |         5 |
|                   2 |        0 |        3 |        3 |        1 |        1 |        1 |        1 |        1 |        1 |         1 |         1 |         1 |
|                   3 |        0 |        0 |        2 |        4 |        4 |        4 |        4 |        4 |        4 |         4 |         1 |         1 |
+---------------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+-----------+-----------+-----------+

And then this would be the final result (number of locations at each rating per month):

+----------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+-----------+-----------+-----------+
| Rating / Month | 1/1/2017 | 2/1/2017 | 3/1/2017 | 4/1/2017 | 5/1/2017 | 6/1/2017 | 7/1/2017 | 8/1/2017 | 9/1/2017 | 10/1/2017 | 11/1/2017 | 12/1/2017 |
+----------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+-----------+-----------+-----------+
|              0 |        3 |        2 |        1 |        1 |        0 |        0 |        0 |        0 |        0 |         0 |         0 |         0 |
|              1 |        0 |        0 |        0 |        1 |        2 |        2 |        2 |        1 |        1 |         1 |         2 |         2 |
|              2 |        0 |        0 |        1 |        0 |        0 |        0 |        0 |        1 |        1 |         0 |         0 |         0 |
|              3 |        0 |        1 |        1 |        0 |        0 |        0 |        0 |        0 |        0 |         0 |         0 |         0 |
|              4 |        0 |        0 |        0 |        1 |        1 |        1 |        1 |        1 |        1 |         1 |         0 |         0 |
|              5 |        0 |        0 |        0 |        0 |        0 |        0 |        0 |        0 |        0 |         1 |         1 |         1 |
+----------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+-----------+-----------+-----------+

So I'm trying to figure out the best way to get to that final result. Not sure if I can basically do it all in a query or if I need to do some calculations after I pull all the data (I'm using Postgres and Ruby on Rails).I also should mention that I (eventually) need to be able to do this not just for month, but also for week, quarter, and year. Any suggestions would be greatly appreciated, thanks!

zeke
  • 3,603
  • 2
  • 26
  • 41

1 Answers1

0

Here's one approach. This does not include zero records which your tables have. Easiest way to do that would be to make sure they're represented in the base data.

create table location_ratings as select * from ( values
    (1, 1, '2017-4-7'::date, 1),
    (2, 1, '2017-7-3'::date, 2),
    (3, 1, '2017-9-9'::date, 5),
    (4, 1, '2017-11-2'::date, 4),
    (5, 2, '2017-1-3'::date, 3),
    (9, 2, '2017-3-7'::date, 1),
    (12, 3, '2017-2-7'::date, 2),
    (13, 3, '2017-3-4'::date, 4),
    (15, 3, '2017-10-1'::date, 1)
) as t(id, location_id, date, rating);

with months as (
    select generate_series(date_trunc('month', min("date")), 
                           date_trunc('month', max("date")+'1 month'::interval),
                           '1 month') as mon
    from location_ratings
),
month_ratings as (
    select distinct on (l.location_id, m.mon)
        m.mon, l.location_id, l.rating, l.date as rating_date 
    from months m
    left join location_ratings l on m.mon >= l.date
    where l.location_id is not null
    order by l.location_id, m.mon, l.date desc
)
--select * from month_ratings;
select mon, rating, count(*)
from month_ratings
group by 1,2 order by 1 asc,2 asc;

The month_ratings result is:

    mon         location_id rating  rating_date
1   01.05.2017 00:00:00 1   1   07.04.2017 00:00:00
2   01.06.2017 00:00:00 1   1   07.04.2017 00:00:00
3   01.07.2017 00:00:00 1   1   07.04.2017 00:00:00
4   01.08.2017 00:00:00 1   2   03.07.2017 00:00:00
5   01.09.2017 00:00:00 1   2   03.07.2017 00:00:00
6   01.10.2017 00:00:00 1   5   09.09.2017 00:00:00
7   01.11.2017 00:00:00 1   5   09.09.2017 00:00:00
8   01.12.2017 00:00:00 1   4   02.11.2017 00:00:00
9   01.02.2017 00:00:00 2   3   03.01.2017 00:00:00
10  01.03.2017 00:00:00 2   3   03.01.2017 00:00:00
11  01.04.2017 00:00:00 2   1   07.03.2017 00:00:00
12  01.05.2017 00:00:00 2   1   07.03.2017 00:00:00
13  01.06.2017 00:00:00 2   1   07.03.2017 00:00:00
14  01.07.2017 00:00:00 2   1   07.03.2017 00:00:00
15  01.08.2017 00:00:00 2   1   07.03.2017 00:00:00
16  01.09.2017 00:00:00 2   1   07.03.2017 00:00:00
17  01.10.2017 00:00:00 2   1   07.03.2017 00:00:00
18  01.11.2017 00:00:00 2   1   07.03.2017 00:00:00
19  01.12.2017 00:00:00 2   1   07.03.2017 00:00:00
20  01.03.2017 00:00:00 3   2   07.02.2017 00:00:00
21  01.04.2017 00:00:00 3   4   04.03.2017 00:00:00
22  01.05.2017 00:00:00 3   4   04.03.2017 00:00:00
23  01.06.2017 00:00:00 3   4   04.03.2017 00:00:00
24  01.07.2017 00:00:00 3   4   04.03.2017 00:00:00
25  01.08.2017 00:00:00 3   4   04.03.2017 00:00:00
26  01.09.2017 00:00:00 3   4   04.03.2017 00:00:00
27  01.10.2017 00:00:00 3   1   01.10.2017 00:00:00
28  01.11.2017 00:00:00 3   1   01.10.2017 00:00:00
29  01.12.2017 00:00:00 3   1   01.10.2017 00:00:00

http://rextester.com/YFNUD43648

And for final:

    mon            rating   count
1   01.02.2017 00:00:00 3   1
2   01.03.2017 00:00:00 2   1
3   01.03.2017 00:00:00 3   1
4   01.04.2017 00:00:00 1   1
5   01.04.2017 00:00:00 4   1
6   01.05.2017 00:00:00 1   2
7   01.05.2017 00:00:00 4   1
8   01.06.2017 00:00:00 1   2
9   01.06.2017 00:00:00 4   1
10  01.07.2017 00:00:00 1   2
11  01.07.2017 00:00:00 4   1
12  01.08.2017 00:00:00 1   1
13  01.08.2017 00:00:00 2   1
14  01.08.2017 00:00:00 4   1
15  01.09.2017 00:00:00 1   1
16  01.09.2017 00:00:00 2   1
17  01.09.2017 00:00:00 4   1
18  01.10.2017 00:00:00 1   2
19  01.10.2017 00:00:00 5   1
20  01.11.2017 00:00:00 1   2
21  01.11.2017 00:00:00 5   1
22  01.12.2017 00:00:00 1   2
23  01.12.2017 00:00:00 4   1

http://rextester.com/NYMA93544

systemjack
  • 2,815
  • 17
  • 26