On Nov 11, 10:22 am, "Michael Bayer" <mike...@zzzcomputing.com> wrote:
> > On Tue, Nov 10, 2009 at 9:55 PM, jcm <jonmast...@gmail.com> wrote:
>
> >> Folks,
>
> >> I could do with some decent docs on subqueries. I've tried to play
>
> since you got some help here, I'll also note that I was surprised I didn't
> have "NOT IN" in the docs so I added that to the ORM tutorial.

Thanks. But there's still a problem preventing me from actually using
this. And it's the inability for sqlalchemy to insert correct
parentheses in the subquery it generates (which has come up here
before). I've wasted all night coming to the realization that the
problem is SQLA and not my code - it should add '(' ')' around the
select in the subquery. I tried having it return a statement and then
calling self_group, and recreating a new query based on that. But
there's just no getting around the fact that it won't generate the SQL
I want it to. Hopefully, there's some hacky way that we can get it to
DTRT at least for the moment.

For context, what I'm doing is writing a Linux kernel symbol tracking
database for a commercial Linux kernel. The Linux kernel contains
approximately 10,000 exported symbols (think software functions) that
third parties can consume. But not all of these symbols should be used
by third parties, and so it is necessary to limit the symbols to a
set. That set is determined through a collaborative voting process in
which people can vote for given proposed symbol entries in the
database. So we have Symbol (the symbol itself), SymbolList (a list
containing this symbol), SymbolListEntry (an entry on that list), and
other types (there are 54 in total). A Vote is requested from the user
against each SymbolListEntry that they have not voted on. In order to
only present entries that haven't been voted on before, I do things
like (simplified):

unvoted_proposed_add_symbollistentries = DBSession.query
(SymbolListEntry).from_statement("SELECT symbollistentries.* FROM
symbollistentries JOIN states ON
(states.state_id=symbollistentries.state_id) WHERE
symbollistentries.proposed_add=1 AND states.deleted=FALSE and
states.active=FALSE AND symbollistentries.symbollistentry_id NOT IN
(SELECT symbollistentries.symbollistentry_id FROM symbollistentries
JOIN votes ON
(votes.symbollistentry_id=symbollistentries.symbollistentry_id) JOIN
states ON (states.state_id=votes.state_id) JOIN users ON
(users.user_id=states.owner_id) WHERE users.user_id=:user_id AND
votes.revision=symbollistentries.revision)").params
(user_id=user.user_id).all()

Which is ugly. I've managed to kill the from_statements everywhere
else in the app now, but not here. I've since added a few more checks
of state in the above query (nothing is ever deleted, only recorded as
such in 'states', hence the weird stuff). Anyway, here's some example
code close to what I want to do, but MySQL balks on the code that SQLA
emits from this:

        symbolListEntryState = aliased(State)
        voteState = aliased(State)
        previous_votes = DBSession.query
(SymbolListEntry.symbollistentry_id).join
((symbolListEntryState,SymbolListEntry.state)).filter(and_
(symbolListEntryState.deleted==False,symbolListEntryState.active==False)).join
((Vote,SymbolListEntry.votes)).filter
(Vote.revision==SymbolListEntry.revision).join
((voteState,Vote.state)).filter(and_
(voteState.deleted==False,voteState.active==True)).join
((User,voteState.owner)).filter(User.user_id==user.user_id).subquery()

        symbollistentries = DBSession.query(SymbolListEntry).join
((symbolListEntryState,SymbolListEntry.state)).filter(and_
(symbolListEntryState.deleted==False,symbolListEntryState.active==False)).filter
(SymbolListEntry.proposed_add==True).filter
(~SymbolListEntry.symbollistentry_id.in_(previous_votes)).all()

        return symbollistentries

It generates this:

ProgrammingError: (ProgrammingError) (1064, "You have an error in your
SQL syntax; check the manual that corresponds to your MySQL server
version for the right syntax to use near 'SELECT
symbollistentries.symbollistentry_id \nFROM symbollistentries INNER
JOIN s' at line 5") u'SELECT symbollistentries.symbollistentry_id AS
symbollistentries_symbollistentry_id, symbollistentries.symbol_id AS
symbollistentries_symbol_id, symbollistentries.symbollist_id AS
symbollistentries_symbollist_id, symbollistentries.state_id AS
symbollistentries_state_id, symbollistentries.proposed_add AS
symbollistentries_proposed_add, symbollistentries.proposed_remove AS
symbollistentries_proposed_remove, symbollistentries.revision AS
symbollistentries_revision, symbollistentries.went_live AS
symbollistentries_went_live \nFROM (SELECT
symbollistentries.symbollistentry_id AS symbollistentry_id \nFROM
symbollistentries INNER JOIN states AS states_1 ON
symbollistentries.state_id = states_1.state_id INNER JOIN votes ON
votes.symbollistentry_id = symbollistentries.symbollistentry_id INNER
JOIN states AS states_2 ON votes.state_id = states_2.state_id INNER
JOIN users ON states_2.owner_id = users.user_id \nWHERE
states_1.deleted = %s AND states_1.active = %s AND votes.revision =
symbollistentries.revision AND states_2.deleted = %s AND
states_2.active = %s AND users.user_id = %s) AS anon_1,
symbollistentries INNER JOIN states AS states_1 ON
symbollistentries.state_id = states_1.state_id \nWHERE
states_1.deleted = %s AND states_1.active = %s AND
symbollistentries.proposed_add = %s AND
symbollistentries.symbollistentry_id NOT IN SELECT
symbollistentries.symbollistentry_id \nFROM symbollistentries INNER
JOIN states AS states_1 ON symbollistentries.state_id =
states_1.state_id INNER JOIN votes ON votes.symbollistentry_id =
symbollistentries.symbollistentry_id INNER JOIN states AS states_2 ON
votes.state_id = states_2.state_id INNER JOIN users ON
states_2.owner_id = users.user_id \nWHERE states_1.deleted = %s AND
states_1.active = %s AND votes.revision = symbollistentries.revision
AND states_2.deleted = %s AND states_2.active = %s AND users.user_id =
%s' [0, 0, 0, 1, 1L, 0, 0, 1, 0, 0, 0, 1, 1L]

Which is quite clearly incorrect, looking at the "NOT IN" generated.
I'm going to wind up with some raw SQL selects left in this app for
now because I've spent 12 hours trying to figure out a way to get SQLA
to do it, and that's probably more than enough for a kernel engineer
who doesn't usually write web apps, but if you happen to have a magic
answer, it would be appreciated. I enjoy some things about SQLAlchemy,
but sometimes (like right here), all I want to do is rip my hair
out :)

Jon.

--

You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=.


Reply via email to