Re: Notes on Join and what the Wiki says about it

[prev] [thread] [next] [Date index for 2004/07/05]

From: Rhesa Rozendaal
Subject: Re: Notes on Join and what the Wiki says about it
Date: 16:27 on 05 Jul 2004
Tony Bowden wrote:

> On Mon, Jul 05, 2004 at 03:17:54PM +0200, Rhesa Rozendaal wrote:
> 
>>I found the set_sql doesn't use the placeholder %s in
>>	set_sql( 'select __ESSENTIAL__ FROM __TABLE__ WHERE %s' );
> 
> 
> Set-sql always uses those placeholders. Can you show what you were doing
> that meant it didn't appear to be?

I tried this:
__PACKAGE__->set_sql( all_features => qq{
     SELECT __ESSENTIAL__
     FROM __TABLE__
     WHERE %s
});

and then call it with
	MDB->search_all_features( field => 'value');

Apparently I misread the docs somewhere, because this generates an SQL 
statement like:
	select f1,f2 from mdb where
where I expected at least
	select f1,f2 from mdb where field=?

The example from the manual says this:

Music::CD->set_sql(new_music => qq{
                 SELECT __ESSENTIAL__
                   FROM __TABLE__
                  WHERE year > ?
});
sub search_new_music {
         my ($class, @args) = @_;
         my $sth = $class->sql_new_music;
         $sth->execute(@args);
         return $class->sth_to_objects($sth);
}

Clearly it passes the arguments as bind values to the statement, so it 
does _not_ use the %s.

So let's try to call it like this:
	MDB->sql_all_features( field => 'value' );

This generates this SQL:
	select f1,f2 from mdb where field

So the sql_ only accepts one parameter (because it doesn't do anything 
with the 'value' parameter), and it must be a scalar as well.
Hmmm.
Ah, but it returns a DBIx::ContextualFetch::st!
Well, that makes things different, doesn't it?
It means I should do it like this:

__PACKAGE__->set_sql( my_albums => qq{
         SELECT DISTINCT c.id
         FROM   __TABLE(Music::CD=c)__
         LEFT JOIN
                __TABLE(Music::Artist=a)__
         ON
             __JOIN(c a)__
         LEFT JOIN
                __TABLE(Music::Track=t)__
         ON
             __JOIN(c t)__
	%s
});

sub query_my_album {
     my $class = shift;
     my $sql = new SQL::Abstract;
     my ($where, @bind) = $sql->where(@_);
     return $class->sth_to_objects(
		$class->sql_my_albums($where),
		\@bind
	);
}

LOL! Now it looks the same as on the Wiki, except for the use of 
SQL::Abstract. Maybe I should have thought this through a bit more 
before posting... (but then I wouldn't have had your comments)

> Class::DBI's JOIN in this case won't work for you if you're doing LEFT
> JOINs.

It seems it does though! The above works fine, as far as I can tell.

> $class->primary_column

Of course... I should have known that :-)

> ESSENTIAL(alias) will work in later versions.

That will make it even more transparent.

> Have a look at how transform_sql handles the JOIN in Class::DBI itself.
> It uses meta_info to build that all up itself.

I'm going to take a good look at this. It looks like I could create a 
generic query by introspecting the has_many relationships.
The only thing that still bugs me is the fact that userland code will 
have to use the table alias prefixes in the columns, but maybe I've won 
enough for one day.

Thanks for your input, and for making me think this through even 
further. And more generally, thank you for an excellent framework. It 
has saved me a tremendous amount of time, and made interfacing with the 
database fun again :-D

Rhesa

Notes on Join and what the Wiki says about it
Rhesa Rozendaal 13:17 on 05 Jul 2004

Re: Notes on Join and what the Wiki says about it
Rhesa Rozendaal 16:27 on 05 Jul 2004

Generated at 11:34 on 01 Dec 2004 by mariachi v0.52