> -----Original Message-----
> From: Zbigniew Lukasiak [mailto:[EMAIL PROTECTED]
> Sent: 15 November 2008 10:43
> To: DBIx::Class user and developer list
> Subject: Re: [Dbix-class] Restricting Result Sets
>
> On Sat, Nov 15, 2008 at 11:25 AM, Howe, Tom (IT)
> <[EMAIL PROTECTED]> wrote:
> > I've wanting something similar and ended up hacking
> dbix:class and added a subselect() method.
> >
> > Below is my previous post highlighting what I did
> > ----------------------------------------------------
> >
> > I'll give you a summary of what ive been doing and how I've
> tackled it.
> >
> > Essentially Ive been creating a reporting framework to
> allow users to create reports on various datasets held in
> sqlite databases.
> > The idea is that users can create reports on the raw data
> or based on existing reports.
>
> This is a very impressive goal!  I have just one question:
>
> >
> snip
> snip
>
> >  # apply search /paging
> >  # build whereclaus from cgi params
> >  my $whereClause = map { ... }  $self->cgi->params;
> >  $rs = $rs->subselect({ $whereClaus }.. { paging..} );   #
> search on resultset
>
> How this subselect is different from a normal search call?  I
> don't want to elaborate the obvious - but you can call search
> on any resultset - also one that is the output of another
> search - and it
> combines the where clauses in effect doing search on a search.   So
> what is the difference here?



As I understand it, if you have a table like

| col1 | col2 | col3 |

You can do
$rs2 = $rs->search( { col1 => { LIKE => 'foo'} } }, { select => [qw/col1, 
col2/] });

$rs3 = $rs2->search( {col2 => { LIKE => 'bar'} } }, { +select => [qw/col3/]);

This will combine the queries allowing you to restrict the resultset so you end 
up with SQL such as

"Select col1,col2,col3 from <table> where col1 like 'foo' and col2 like 'bar';"


But lets say you want to do the following...

$rs2 = $rs->search( { col1 => { LIKE => 'foo'} } }, { select => 
['substr(col1,1,10) as blah', 'substr(col2,1,10) as blah2', 'count(*) as 
count)] }, group_by  => ['col3']);

$rs3 = $rs2->search( {blah1 => { LIKE => 'bar'}, count => '1' } }, { select => 
[qw/blah1 blah2 count/]);


It would try to create SQL something like:

Select blah1,blah2,count(*) as count  from <table> where col1 like 'foo' and 
blah1 like 'bar' and count=1 group by col3;

This would fail because
 - The second select would override the first select and blah1, blah2 don't 
exist in the resultsource.


I think the only way you can currently do this is by setting up special 
result_sources with custom sql. I didn't know about this when I started out 
with my application but it doesn't seem ideal for my purposes anyhow.


Using my subselect() feature I would write it as

$rs2 = $rs->search( { col1 => { LIKE => 'foo'} } }, { select => 
['substr(col1,1,10) as blah', 'substr(col2,1,10) as blah2', 'count(*) as 
count)] }, group_by  => ['col3']);

$rs3 = $rs2->subselect( {blah1 => { LIKE => 'bar'}, count => '1' } }, { select 
=> [qw/blah1 blah2 count/]);


The SQL for $rs2 gets rendered and placed into the 'from' attribute for $rs3 to 
generate a nested select that would look like

Select blah1,blah2,count(*) as count  from (
  select col1 as blah1, col2 as blah2, count(*) as count from  <table> where 
col1 like 'foo' group by col3;
 ) where blah1 like 'bar' and count =1;


I also added an asSQL() method and a 'compound' attribute so you can do Unions, 
excepts and intersections.

So you can do things like

$rs = $rs->search( {}, {} )
$rs = $rs->subselect( {}, {} )
$rs = $rs->subselect( {}, {} )

$rs2 = $rs->search( {}, {} )
$rs2 = $rs2->subselect( {}, {} )
$rs2 = $rs2->subselect( {}, {} )

$deltaSQL = $rs2->asSQL

$rs->search({} { compound => ' UNION $deltaSQL' };

Admitedly it's a bit hacky, but you can end up with  complex queries like the 
following:

Select x1,x2,x3, x4 from (
  select y1 as x1,y2 as x2,y3 as x3,y4 as x4 from (
     select z1 as y1,z2 as y2,z3 as y3,z4 as y5 from table where ... Group by 
...
  ) where y1=.., y2=..   EXCEPT (select from ...)
) UNION
Select x1,x2,x3,x4 from (
   select ....
)

As far I as could see, my alternative was people creating these as views in the 
db,
but I don't want the users to have access to the db.


The tricky bit was getting the quoting right so that when you nest say:

select substr(col1,1,1) from table

It becomes

select "substr(col1,1,1)" from ( select substr(col1,1,1) from table );

But if you did

select substr(col1,1,1) as mystr from table

It needs to become

select mystr from ( select substr(col1,1,1) as mystr from table );



Tom
--------------------------------------------------------

NOTICE: If received in error, please destroy and notify sender. Sender does not 
intend to waive confidentiality or privilege. Use of this email is prohibited 
when received in error.

_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/[email protected]

Reply via email to