1

I have two tables, prizes and prize_unlocks. I'm trying to write a query to find a prize that a user has not previously unlocked.

The idea is that there is a table of prizes that can be won by any user and there is a table tracking which users have won which prizes. I'm using flask-sqlalchemy and the tables are defined like this:

class Prize(db.Model):
  __tablename__ = 'prizes'
  id = db.Column(db.Integer, primary_key = True)
  # ... some other info about the prize...


class PrizeUnlock(db.Model):
  __tablename__ = 'prize_unlocks'
  id = db.Column(db.Integer, primary_key = True)

  # associated prize
  prize_id = db.Column(db.Integer, db.ForeignKey('prizes.id'))
  prize = db.relationship('Prize',
    backref=db.backref('prize_unlocks'))

  # associated user
  user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
  user = db.relationship('User',
    backref=db.backref('prize_unlocks'))

I am trying to write a single SqlAlchemy query to select a random prize from the prizes that a user has not previously won. As I understand, I need to write the query with an exists clause, but I'm unable to get it right.

Could anyone please help out with this?

If it's of any help, the corresponding sql query looks like this:

select p.id from prizes as p where not exists (select * from prize_unlocks where prize_unlocks.prize_id=r.id) order by rand() limit 1;

EDIT: Got the answer! metmirr was very close, but I'm just posting the final answer here in case it helps someone in the future.

db.session.query(Prize.id).filter(
  not_(
    db.session.query(PrizeUnlock)
      .filter(Prize.id == PrizeUnlock.prize_id)
      .exists()
  )
).order_by(Prize.id).limit(10).all()
1
  • What's the wrong query that you wrote? Perhaps we could help you fix it. Commented Feb 6, 2017 at 8:30

1 Answer 1

3

Use subquery in filter function:

db.session.query(Prize.id).filter(
    db.session.query(PrizeUnlock.id)
        .filter(Prize.id == PrizeUnlock)
        .exists()
).order_by(Prize.id).limit(1)
Sign up to request clarification or add additional context in comments.

1 Comment

Sweet, this was close enough to the answer that I found it. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.