2

I realize this is a well known 'limitation', that you cannot straightforwardly filter on a window functions annotation, but I am looking for ways around that. I have seen an answer to this question that suggests using a subquery, but I cannot work out what the syntax should be without getting a *** django.db.utils.ProgrammingError: more than one row returned by a subquery used as an expression error.

The data represents a timeseries with discrete states. These states change over time. I need to get a list of timestamps (or indices) where the 'state' changes from one to the next. Using a Window Function, I can get a queryset with the state change, but cannot then filter on that to get the index/timestamp of when the change occurs.

Very simplified (non-working) code is:

*models.py

class MyModel(models.Model):
    parent = models.ForeignKey('MyParent')
    timestamp = models.DateTimeField()
    state = models.IntegerField()

*view

deltas = MyModel.objects.filter(parent=parent).annotate(
    previous_state=Window(
        expression=Lag('state', offset=1, default=0),
        order_by=F('timestamp').asc()
        ),
    delta=F('state')-F('previous_state')
).values('delta')

This gives a queryset of records with the diff value indicating a state change (e.g. where state goes from 0->1, diff = 1, where state goes from 3 -> 2, diff = -1, etc.), however I cannot filter on it to find where those state changes are. Ideally I could do deltas.filter(delta__gte=1) to find any increases in state, but of course this is not allowed.

Is there any other way to achieve this using Subqueries or similar? (db is PSQL)

Stuart Buckingham
  • 1,574
  • 16
  • 25

0 Answers0