[Dbix-class] join ON *AND*

Darren Duncan darren at darrenduncan.net
Tue Mar 18 20:17:17 GMT 2014


On 2014-02-21, 1:22 AM, Hartmaier Alexander wrote:
> On 2014-02-21 10:16, Carl Franks wrote:
>> SELECT me.id, me.title, count(response_comment.id)
>> FROM `query` me
>> LEFT JOIN `response_comment`
>> ON me.id = response_comment.query_id
>> AND response_comment.alert = 1
>> AND response_comment.status = 'posted'
>> GROUP BY me.id, me.title;
>>
>> This returns results such as:
>>
>> id | title | count(response_comment.id)
>> ---------------------------------------
>>   1 | one   | 0
>>   2 | two   | 1
>>   3 | three | 0
>>
>> So far I have:
>> my $rs = $schema->resultset('Query')->search(
>>      undef,
>>      {
>>          join => ['response_comments'],
>>          distinct => 1,
>>          '+select' => [ { count => 'response_comments.id' } ],
>>          '+as' => ['alerts'],
>>      },
>> );
>> Which gives me the count of the related response_comments - but I
>> can't figure out how to define the 'AND' clauses.
>> Any help?
> Just restrict the resultset:
> ->search({
>      'response_comments.alert' => 1,
>      'response_comments.status => 'posted',
> }, {
> ...
> });

That doesn't work in general because we're dealing with an OUTER JOIN here and 
not an INNER JOIN.

The join result still needs to have a row for each "query" row, and the effect 
of putting the filter in ON rather than WHERE is meant to make it as if an 
otherwise-matching "response_comment" row doesn't exist, in which case the join 
result would still supposed to have a row but columns from response_comment 
would be null.

Your proposed solution would eliminate "query" rows too because it is applied 
after the join, not before as expected.

Note that an alternative SQL syntax to using ON is to replace the 
"response_comment" with a FROM subquery that does the filtering.

-- Darren Duncan




More information about the DBIx-Class mailing list