Thanks, I hadn't realised that db.table.on() could be passed more complex 
queries. I'd tried feeding a list of queries - the online book mentions 
that left=  can take an iterable - but each list item creates a separate 
left join statement. Being able to pass a single query including qualifiers 
is exactly what I needed.

I particularly wanted to be able to create the db.table.on() dynamically, 
to add a set of filters if requested and that turns out to be easy -  
create the main left join as a query object and then &= on filter if there 
are any, before passing that to db.table.on()

filters = (db.audio.start_time > '12:00:00')

qry = (db.audio.site_id == db.sites.id)

if filters is not None:
    qry &= filters

data = db().select(db.sites.ALL,
                   db.audio.id.count().with_alias('n_audio'),
                   left=db.audio.on(qry),
                   groupby=db.sites.id)

Thanks again,
David

On Saturday, 24 November 2018 23:20:31 UTC, Val K wrote:
>
> Try to move db.audio.start_time > '12:00:00'  in the left join ON:
> left=db.audio.on((db.audio.site_id == db.sites.id) & (db.audio.start_time 
> > '12:00:00'))
>
>
> On Sunday, November 25, 2018 at 1:34:54 AM UTC+3, David Orme wrote:
>>
>> Thanks for the suggestion. I've actually tried that and get exactly the 
>> same results - I read somewhere that using an empty db() could be 
>> problematic, so tried both.
>>
>> It doesn't affect the result without any audio queries, but any audio 
>> queries added into the selected set (qry in my code), cause the left join 
>> to get reduced. I have to admit I'm not completely sure why, but the SQL 
>> examples show it happening!
>>
>> David
>>
>>
>> On Sat, 24 Nov 2018, 22:18 Val K <valq...@gmail.com wrote:
>>
>>> try remove db.sites from query (just db().select(...))
>>>  db(db.sites) is shortcut for  db(db.sites.id>0) which turns into  
>>> WHERE ((sites.id IS NOT NULL) 
>>>
>>>
>>> On Sunday, November 25, 2018 at 1:00:56 AM UTC+3, David Orme wrote:
>>>>
>>>> Hi,
>>>>
>>>> I've got a table 'sites' and a table 'audio', where sites.id = 
>>>> audio.site_id. I'm trying to create a service that returns a list of sites 
>>>> with the number of audio recordings at each site, including zero counts. 
>>>> That's easily achieved using:
>>>>
>>>> sitedata = db(db.sites).select(db.sites.ALL,
>>>>                                db.audio.id.count().with_alias('n_audio'
>>>> ),
>>>>                                left=db.audio.on(db.audio.site_id == db.
>>>> sites.id),
>>>>                                groupby=db.sites.id)
>>>>
>>>> The problem arises when I want to count only a subset of the audio 
>>>> table, controlled by variables passed in with the call. At the moment, I'm 
>>>> trying to implement that by chaining together queries to add in filters. 
>>>> So 
>>>> for example:
>>>>
>>>> qry = db(db.sites)
>>>>
>>>> # code modifies qry, such as:
>>>> qry = qry(db.audio.start_time > '12:00:00')
>>>>
>>>> sitedata = qry.select(db.sites.ALL,
>>>>                       db.audio.id.count().with_alias('n_audio'),
>>>>                       left=db.audio.on(db.audio.site_id == db.sites.id
>>>> ),
>>>>                       groupby=db.sites.id)
>>>>
>>>> Now that runs, but it loses the entry for each site, retaining only 
>>>> those where some data is present. The filtered example above produces:
>>>>
>>>> SELECT  sites.id, ... , COUNT(audio.id) AS n_audio 
>>>>     FROM sites LEFT JOIN audio ON (audio.site_id = sites.id) 
>>>>     WHERE ((sites.id IS NOT NULL) 
>>>>         AND (audio.start_time > '12:00:00')) 
>>>>     GROUP BY sites.id;"
>>>>
>>>> As I understand it, that where clause outside of the Left Join filters 
>>>> the result of the join, dropping rows, and what I need to achieve is to 
>>>> move the filter clauses inside the left join. The filters are going to 
>>>> need 
>>>> to include > < as shown but also an option using .belongs() to test for 
>>>> particular values.
>>>>
>>>> SELECT  sites.id, ..., COUNT(audio.id) AS n_audio 
>>>> FROM sites LEFT JOIN audio 
>>>> ON (audio.site_id = sites.id) 
>>>> AND ((sites.id IS NOT NULL) 
>>>> AND (audio.start_time > '12:00:00')) 
>>>> GROUP BY sites.id;
>>>>
>>>> That last query generates the output I need but I can't figure out how 
>>>> to pass them into the DAL. Any suggestions? I'm keen on the concept of 
>>>> passing request.vars to a handler that can be shared by different calls 
>>>> and 
>>>> returns a suitably tweaked subset of audio to be searched, but it seems 
>>>> like I need to pass the filters in somewhere else.
>>>>
>>>> Thanks,
>>>> David
>>>>
>>>>
>>>>
>>>> -- 
>>> Resources:
>>> - http://web2py.com
>>> - http://web2py.com/book (Documentation)
>>> - http://github.com/web2py/web2py (Source code)
>>> - https://code.google.com/p/web2py/issues/list (Report Issues)
>>> --- 
>>> You received this message because you are subscribed to a topic in the 
>>> Google Groups "web2py-users" group.
>>> To unsubscribe from this topic, visit 
>>> https://groups.google.com/d/topic/web2py/RIeIVoLbGy8/unsubscribe.
>>> To unsubscribe from this group and all its topics, send an email to 
>>> web2py+un...@googlegroups.com.
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>

-- 
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
--- 
You received this message because you are subscribed to the Google Groups 
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to web2py+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to