Hello,

Actually, you can join on any condition, not only on the relation
condition,
In this case your query needs to evolve from:

.outerjoin((ATranslation,Book.translations))\

to:

.outerjoin((ATranslation,
               and_(ATranslation.book_id == Book.isbn,
                       ATranslation.language_id == 'en')))\

what will give you

LEFT OUTER JOIN translation AS translation_1
    ON book.isbn = translation_1.book_id
              AND
          translation_1.language_id = %s

what is probably what you want, you can also refer to
http://www.sqlalchemy.org/docs/05/sqlexpression.html#sql_joins
to get more info on this.

Alex

On 24 сент, 03:50, g00fy <[EMAIL PROTECTED]> wrote:
> One more thing,
>
> If i have just book and translations
>
> 1 Book has 3 translations
>
> this sql will create me 3 rows (due to the join)
>
> isbn translation_code translation_text
> 1    en               "The Book"
> 1    ru               "Книжка"
> 1    pl               "Ksiazka"
>
> so if i have 10 books i will have 30 rows.
>
> this is NxM,
> what if I just want to join by :
>
> LEFT OUTER JOIN translation AS translation_1
>             ON (book.isbn = translation_1.book_id ,
> translation_1.code="en")
>
> so i will only get the required information ?
> Limiting the results will also be a problem becouse simple LIMIT will
> not be enough.
>
> (consider having 30 multiple relations, it will generate huge ammount
> of data M*n*x*...)
>
> On 23 Wrz, 16:37, g00fy <[EMAIL PROTECTED]> wrote:
>
> > Thnx a lot Alex! I already love Pylons and SQLAlchemy!
>
> > On 23 Wrz, 12:16, Alex K <[EMAIL PROTECTED]> wrote:
>
> > > Hello, here is the answer:
>
> > > # -*- coding: utf-8 -*-
>
> > > from sqlalchemy import create_engine
> > > from sqlalchemy import Table, Column, Integer, String, Unicode,
> > > MetaData, ForeignKey
> > > from sqlalchemy.orm import sessionmaker, mapper,
> > > dynamic_loader,backref, relation, composite, comparable_property,
> > > contains_eager,aliased
> > > from sqlalchemy.sql import text, and_
> > > from orm.object.factory import make_papped_class
> > > from sqlalchemy.orm import PropComparator
>
> > > from common import Application
>
> > > app = Application()
> > > session = app.session
> > > metadata = app.metadata
>
> > > """
> > > Book :
> > > isbn -> integer
> > > translations -> many translations
> > > prices -> many prices
>
> > > Translation :
> > > book -> FK to book
> > > laguage -> FK to Language (oneTOone)
> > > title -> string
>
> > > Language :
> > > code -> string
> > > name  -> string
>
> > > Currency :
> > > code -> string
> > > name -> string
>
> > > Price :
> > > currency -> FK
> > > book ->FK
> > > brutto -> int
> > > netto -> int
>
> > > """
>
> > > book_table = Table('book', metadata,
> > >                     Column('isbn', Integer, primary_key=True)
> > >                     )
>
> > > language_table = Table('language', metadata,
> > >                     Column('code', String(5), primary_key=True),
> > >                     Column('name', Unicode(20)),
> > >                     )
>
> > > currency_table = Table('currency', metadata,
> > >                     Column('code', String(5), primary_key=True),
> > >                     Column('name', Unicode(20)),
> > >                     )
>
> > > translation_table = Table('translation', metadata,
> > >                     Column('book_id', Integer,
> > > ForeignKey(book_table.c.isbn)),
> > >                     Column('language_id', String(5),
> > > ForeignKey(language_table.c.code)),
> > >                     Column('title', Unicode(512)),
> > >                     )
>
> > > price_table = Table('price', metadata,
> > >                     Column('currency_id', String(5),
> > > ForeignKey(currency_table.c.code)),
> > >                     Column('book_id', Integer,
> > > ForeignKey(book_table.c.isbn)),
> > >                     Column('brutto', Integer),
> > >                     Column('netto', Integer)
> > >                     )
>
> > > metadata.create_all()
>
> > > #create objects
> > > class Book(object):
> > >     def __init__(self,isbn):
> > >         self.isbn = isbn
>
> > > class Language(object):
> > >     def __init__(self,code,name):
> > >         self.code = code
> > >         self.name = name
>
> > > class Currency(object):
> > >     def __init__(self,code,name):
> > >         self.code = code
> > >         self.name = name
>
> > > class Translation(object):
> > >     def __init__(self,book_id,language_id,title):
> > >         self.book_id = book_id
> > >         self.language_id = language_id
> > >         self.title = title
>
> > > class Price(object):
> > >     def __init__(self,currency_id,book_id,brutto,netto):
> > >         self.currency_id = currency_id
> > >         self.book_id = book_id
> > >         self.brutto = brutto
> > >         self.netto = netto
>
> > > mapper(Book,book_table)
> > > mapper(Language,language_table)
> > > mapper(Currency,currency_table)
>
> > > mapper(Translation,translation_table,properties = {
> > >     'book': relation(Book,
> > >                      lazy = False, #1 note lazy here, it means that
> > > we
> > >                                    # will use lazy loading (more
> > > details in the docs
> > >                      backref = backref('translations',lazy = False)),
> > >     'language': relation(Language,
> > >                          uselist = False,#2 note uselist, it means
> > >                                          #we use one-to-one instead of
> > > one-to-many
> > >                          lazy = False),},
>
> > > primary_key = [translation_table.c.book_id,
> > >                translation_table.c.language_id]
> > > #explicit primary key is needed when SQLA can not assemble the one for
> > > you automatically
> > > );
>
> > > mapper(Price,price_table,properties = {
> > >     'currency': relation(Currency,lazy = False),
> > >     'book': relation(Book,lazy = False, backref =
> > > backref('prices',lazy = False))
>
> > > },primary_key = [price_table.c.book_id,price_table.c.currency_id]);
>
> > > session = app.session
>
> > > if False: #change this to True to issue add statement
> > >     session.add(Language('en',u'English'))
> > >     session.add(Language('ru',u'Русский'))
>
> > >     session.add(Currency('usd',u'Dollar'))
> > >     session.add(Currency('rub',u'Рубль'))
>
> > >     session.add(Book(1))
> > >     session.add(Book(2))
>
> > >     session.flush()
>
> > >     session.add(Translation(book_id = 1, language_id = 'en', title =
> > > u'The book'))
> > >     session.add(Translation(book_id = 1, language_id = 'ru', title =
> > > u'Книжка'))
>
> > >     session.add(Translation(book_id = 2, language_id = 'en', title =
> > > u'Book'))
> > >     session.add(Translation(book_id = 2, language_id = 'ru', title =
> > > u'Книжка2'))
>
> > >     session.add(Price(book_id = 1, currency_id = 'usd', brutto = 12,
> > > netto = 20))
> > >     session.add(Price(book_id = 1, currency_id = 'rub', brutto = 250,
> > > netto = 500))
>
> > >     session.add(Price(book_id = 2, currency_id = 'usd', brutto = 10,
> > > netto = 18))
> > >     session.add(Price(book_id = 2, currency_id = 'rub', brutto = 200,
> > > netto = 440))
>
> > > """
> > >  would like now to get books that:
> > > isbn>1
> > > translation.title in english starts with "The" ( I don't need other
> > > languages for this select)
> > > price.netto < 100 USD ( I don't need other prices, only in USD for
> > > this select)
>
> > > There are 5 Tables to join.
> > > Lets say I have 100 objects maching,  I dont want to hit the db 100
> > > times.
> > > """
>
> > > # the common approach here, as Michael says,
> > > # is to construct the query as you would do it yourself
> > > # and to tel sql alchemy where to pick the data for objects from
>
> > > #aliases to control the query
> > > ATranslation =  aliased(Translation)
> > > APrice =  aliased(Price)
>
> > > books = session.query(Book)\
> > >             .outerjoin((ATranslation,Book.translations))\
> > >             .outerjoin((APrice,Book.prices))\
> > >             .filter(and_(
> > >                          Book.isbn >= 1,
> > >                          ATranslation.language_id == 'en',
> > >                          ATranslation.title.like(u'The%'),
> > >                          APrice.currency_id == 'usd',
> > >                          APrice.netto < 25,))\
> > >             .options(contains_eager('translations',alias =
> > > ATranslation))\
> > >             .options(contains_eager('prices',alias = APrice))
>
> > > """
> > >     .outerjoin((ATranslation,Book.translations)) - creates explicit
> > > join to the named alias,
> > >     and tells that this join implements Book.translations relation
>
> > >     ATranslation.language_id == 'en', - now we can use the named alias
> > > to issue filter statements
>
> > >     .options(contains_eager('translations',alias = ATranslation)) -
> > > now refer to the note #1,
> > >     this statement says to SQLA that it needs to load data for the
> > > translation relation from this alias
>
> > > """
>
> > > """
> > > at the end the query gives you the following statement (MySQL):
>
> > > SELECT  book.isbn AS book_isbn,
> > >         currency_1.code AS currency_1_code,
> > >         currency_1.name AS currency_1_name,
> > >         price_1.currency_id AS price_1_currency_id,
> > >         price_1.book_id AS price_1_book_id,
> > >         price_1.brutto AS price_1_brutto,
> > >         price_1.netto AS price_1_netto,
> > >         language_1.code AS language_1_code,
> > >         language_1.name AS language_1_name,
> > >         translation_1.book_id AS translation_1_book_id,
> > >         translation_1.language_id AS translation_1_language_id,
> > >         translation_1.title AS translation_1_title
> > > FROM book
> > >         LEFT OUTER JOIN translation AS translation_1
> > >             ON book.isbn = translation_1.book_id
> > >         LEFT OUTER JOIN price AS price_1
> > >             ON book.isbn = price_1.book_id
> > >         LEFT OUTER JOIN currency AS currency_1
> > >             ON currency_1.code = price_1.currency_id
> > >         LEFT OUTER JOIN language AS language_1
> > >             ON language_1.code = translation_1.language_id
> > > WHERE
> > >     translation_1.language_id = %s
> > >    
>
> ...
>
> продолжение >>
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to