Here's the SQL I got : SELECT face.id AS face_id FROM face LEFT OUTER JOIN face_bookings__booking_faces AS face_bookings__booking_faces_1 ON face.id = face_bookings__booking_faces_1.face_id LEFT OUTER JOIN booking ON booking.id = face_bookings__booking_faces_1.booking_id JOIN time_period ON booking.time_period_id = time_period.id WHERE time_period.start_date > %(start_date_1)s OR time_period.end_date < %(end_date_1)s
With the following code : class Booking(BaseModel): """ """ using_options(tablename="booking") reprattr = "time_period" faces = ManyToMany("Face") # A client has one and only one booking per time period time_period = ManyToOne("TimePeriod") @classmethod def get_available_faces(self,time_period): """ Return faces that are not booked during the given time_period. """ from timeperiod import TimePeriod from face import Face start_date_cond = TimePeriod.start_date > time_period.end_date end_date_cond = TimePeriod.end_date < time_period.start_date unbooked = or_(start_date_cond,end_date_cond) # query = Face.query.filter(Face.bookings.any(Booking.time_period.has(unbooked))) # return query.all() query = Face.query.filter(unbooked) #return query.all() query = query.outerjoin(Face.bookings) #return query.all() query = query.join(Booking.time_period) return query.all() And still not the expected results (it should return faces with no bookings at all but it doesen't). Thanks for any help. Y.Chaouche --- On Wed, 10/13/10, chaouche yacine <yacinechaou...@yahoo.com> wrote: From: chaouche yacine <yacinechaou...@yahoo.com> Subject: Re: [sqlalchemy] Checking the availablity of a booked Item To: sqlalchemy@googlegroups.com Date: Wednesday, October 13, 2010, 5:25 AM Thank you Thadeus, I believe Face.query.filter(filter_cond).outerjoin(join_clause).all() does a full outerjoin, or is there another way to do it ? Y.Chaouche --- On Wed, 10/13/10, Thadeus Burgess <thade...@thadeusb.com> wrote: From: Thadeus Burgess <thade...@thadeusb.com> Subject: Re: [sqlalchemy] Checking the availablity of a booked Item To: sqlalchemy@googlegroups.com Date: Wednesday, October 13, 2010, 12:04 AM For outer joins you need a where clause on the joined tables. http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html Using a full outer join should return the expected results. -- Thadeus On Tue, Oct 12, 2010 at 1:41 PM, chaouche yacine <yacinechaou...@yahoo.com> wrote: Hello, Here's my simple model (For simplification, consider Face as a Billboard) : +-----+ +-----------+ +----------+ |Face |<...... |Campaign | ...>|TimePeriod| +-----+ . +-----------+ . +----------+ |code | . |time_period|.... |start_time| +-----+ . +-----------+ +----------+ ....|faces | |end_time | +-----------+ +----------+ One way to read this model is : A campaign can book multiple faces during a certain period of time. What I want to do is get all the available Faces for a given period of time, to see what faces can I book for a new campaign that longs for that particular period of time. I would typically have a Face.get_available(time_period) class method that does the job. This method would look for all the faces that don't have an ongoing booking. My question is : how to write such a method ? Here's how I figured it out (couldn't get it to work) : class Face(Entity): using_options(tablename="faces") �...@classmethod def get_available(self,time_period): """ Return faces that are not booked (not in any campaign) during the given time_period. """ # start_date_cond = TimePeriod.start_date > time_period.end_date # end_date_cond = TimePeriod.end_date < time_period.start_date # available_periods = Campaign.time_period.has(or_(start_date_cond,end_date_cond)) # unavailable_periods = not(available_periods) # I am pretty sure that the time conditions are good. # Here's a good way to convince yourself (read from bottom to top) : # L1 0----------------------------------------------- # L2 ------------------------------------------| # L3 0--------------------[--------------------]--------------------------> # L3 represents the desired period (passed as argument) going from "[" to "]" # place the start date of the booked face anywhere on L2 # place the end date of the booked face anywhere on L1 # of course, end date must be after start date... # Anyway you do it, your face isn't available for the period of time in L3. start_date_cond = TimePeriod.start_date <= time_period.end_date end_date_cond = TimePeriod.end_date >= time_period.start_date unavailable_periods = Campaign.time_period.has(and_(start_date_cond,end_date_cond)) # I am not sure about what follows... filter_cond = not_(unavailable_periods) join_clause = Campaign.faces return Face.query.filter(filter_cond).outerjoin(join_clause).all() This code returns only faces that have already been booked before or have a future booking, and are free for the moment. But faces with no bookings at all are not returned. This may be due to an incorrect outerjoin ? (I also tried a simple join with no success) Here's the generated sql for one query : 2010-10-12 19:34:22,837 INFO sqlalchemy.engine.base.Engine.0x...f4ec SELECT faces.id AS faces_id FROM campaigns LEFT OUTER JOIN campaigns_faces__faces AS campaigns_faces__faces_1 ON campaigns.id = campaigns_faces__faces_1.campaigns_id LEFT OUTER JOIN faces ON faces.id = campaigns_faces__faces_1.faces_id WHERE NOT (EXISTS (SELECT 1 FROM time_periods WHERE campaigns.time_period_id = time_periods.id AND time_periods.start_date <= %(start_date_1)s AND time_periods.end_date >= %(end_date_1)s)) 2010-10-12 19:34:22,837 INFO sqlalchemy.engine.base.Engine.0x...f4ec {'start_date_1': datetime.date(2010, 10, 30), 'end_date_1': datetime.date(2010, 10, 20)} [<Face id=1 at 0x932218c >] Any help would be very appreciated. Y.Chaouche PS : and please, don't give me that lame "it's elixir" excuse. The question is about how to construct the proper query for the desired operation in a sqlalchemy way. Elixir is only another Declarative approach + mapping, that's it. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.