[Dbix-class] SQL::Builder propaganda review
Sebastian
buddhahead at gmail.com
Tue Oct 25 09:29:21 CEST 2005
Howdy,
> 1. add HAVING
Currently there is HAVING support. SQL::Builder::Having. It's
available through SQL::Builder::Select, too
> 2. the ability to specify complex joins
Currently there is SQL::Builder::JoinGroup which would help with this,
but of course it's likely to change at some point because I'm not too
happy with how I've been dealing with JOINs so far.
> 3. a richer abstraction of partial queries
The SQL::Builder::Select object is relatively small because most of
its functionality relies on other modules representing smaller pieces
of SQL. SQL::Builder::Select is comprised of:
SQL::Builder::Distinct;
SQL::Builder::FromList;
SQL::Builder::Where;
SQL::Builder::GroupBy;
SQL::Builder::Having;
SQL::Builder::OrderBy;
SQL::Builder::Limit;
Most of which break down further to the Table, Column, ColumnList,
Join, et al... Point being it should be possible to represent partial
queries and basic SQL constructs without a fuss and hopefully the
finished API will make it easy to manipulate/create others.
Logically reusing views is a major goal. There are still a bit of work
to be done about how this can be done intelligently, though.
> Of course only someone writing ORMs would really prefer such a
> syntax over the Domain Specific Language for this task, SQL. I'm
> also assuming a Tangram::Expr-style simplification of writing
> complex expression ASTs using overloading. And only someone writing
> a high level tool like Tangram would be interested in many of the
> features of an API like that.
I think something like you suggest would have a broader application
rather than ORM writers. Even in non-ORM systems it'd be nice to alter
an existing view to return some aggregate function results and
slightly tweak a WHERE condition. I'm in favor of a
nice/abstract/overloaded interface as long as it's not a required part
of the API. I'd like to build a solid foundation, then apply a syntax.
Hopefully it'll be more flexible in the long run
I was wondering when someone would reply to my post!
- sebastian
On 10/25/05, Sam Vilain <sam at vilain.net> wrote:
> On Sat, 2005-10-22 at 04:43 -0700, Sebastian wrote:
> > Hi,
> >
> > For those that don't know, SQL::Builder is a collection of modules for
> > SQL manipulation. It's not "yet another SQL abstraction module" or ORM
> > so please read some of what I say before flaming. Currently it's under
> > development, but it's on its way. My next release (0.03alpha) next
> > week will have documentation and more complete functionality. The
> > source is available at
> > http://unf.be/~sili/projects/sqlbuilder/SQL-Builder/
> >
> > Anyhow, I've been revising the documentation and would like to get
> > some feedback on the following bit of propaganda extracted from
> > SQL::Builder's pod. Thanks in advance
>
> This looks like a good start, and is something I'll need when I shave
> off the dreadlocks of hairy code inside Tangram's internals, and
> SQL::Abstract is just not enough to express all that you can with Tangram.
>
> Let's go over some "corner cases" I don't think are easily described in
> your API.
>
> 1. add HAVING
>
> I see GROUP BY, but no HAVING (which is how you filter on aggregated
> columns without a subselect).
>
> 2. the ability to specify complex joins
>
> In essence, listing multiple tables and "where" conditions that just
> happen to form a 1:X or 1:1 relation between the selected tables, is
> a nasty hack way to perform an explicit JOIN. It's a nasty hack
> because the query optimiser has to figure it out from your query, or
> else fall back to cartesian product calculation.
>
> This is very important if you're doing complicated joins; say you
> have two tables, which need to be joined together to get the full
> "object". Then, you do an outer join on those. This is a nested
> join.
>
> Here's the example; I have two tables, "Person", and
> "NaturalPerson", which are joined on ID. I want to find all the
> people who either have no parent on file, or whose parent is older
> than 72. We assume that "age" is a property of "Person", and
> "parent" is a property of "NaturalPerson". Oh, and person 1 needs
> to have a name starting with "M".
>
> I would write;
>
> select
> p1.id,
> p2.id -- etc
> from
> (Person p1
> inner join NaturalPerson np1
> on (np1.id = p1.id))
> left join
> (Person p2
> inner join NaturalPerson np2
> on (np2.id = p2.id))
> on ( np2.id = np1.parent_id and
> p2.age > 72 )
> where
> p1.name like 'M%'
>
> 3. a richer abstraction of partial queries
>
> Note that each selection of data from a table is a view, and joining
> another table on (or making a cartesian product, for that matter)
> makes another view. I want to be able to use these views and
> logically combine them together to make subsequent views, and
> wherever possible, I want to avoid the necessity to do that with a
> sub-select - as most optimisers out there don't optimise out
> sub-selects to joins everywhere that they could.
>
> So, perhaps if you start with a logical element of a view, and make
> sure that these views can be represented cleanly without resorting
> to the "select()" function, then you can write select() in terms of
> it.
>
> In essence you have a heirarchy, each level builds on the one above
> it:
>
> FROM - (tables or views)
> T1.X,... - (expressions of tables or views)
> JOIN - (joins between tables or views)
> WHERE - (filtered views)
> GROUP BY - (aggregations)
> HAVING - (filtered aggregations)
> (SELECT) - (sub-select)
>
> Of course any element in an expression may be a very complicated
> object. Sub-selects may be used for tables in queries, as well as
> in expressions.
>
> So with such a system, the above query might look something like;
>
> my ($p1, $p2, $np1, $np2) = table( ("Person") x 2,
> ("NaturalPerson") x 2 );
>
> my $person1 = $p1->join($np1, $p1->{id} == $np1->{id});
> my $person2 = $p2->join($np2, $p2->{id} == $np2->{id});
>
> my $outer_join = $person1->left_join
> ($person2,
> ( ($person2->{id} == $person1->{parent_id}) &
> ($person2->{age} > 72) ) );
>
> my $final_view = $outer_join->where($person1->{name}->like("M%"));
>
> my $select_statement = $final_view->select
> ($person1->{id}, $person2->{id});
>
> Of course only someone writing ORMs would really prefer such a
> syntax over the Domain Specific Language for this task, SQL. I'm
> also assuming a Tangram::Expr-style simplification of writing
> complex expression ASTs using overloading. And only someone writing
> a high level tool like Tangram would be interested in many of the
> features of an API like that.
>
> Is this a direction you'd like to move SQL::Builder in ?
>
> Sam.
>
>
--
More information about the Dbix-class
mailing list