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
> >     AND translation_1.title LIKE %s
> >     AND price_1.currency_id = %s
> >     AND price_1.netto < %s
>
> > with the bind args as:
> >     ['en', 'The%', 'rub', 25]
>
> > If it's not what you expected, let me know
> > """
>
> > #now when you access the results, SQLA issues no additional queries
> > for you
> > print [(book.isbn, book.translations[0].title,book.prices[0].netto,)
> > for book in books]
>
> > """
> > a helper application class used in this example (from common import
> > Application)
>
> > class Application(object):
>
> >     url =  URL( drivername = 'mysql',
> >             username = 'root',
> >             password = '',
> >             host = 'localhost',
> >             port = '3306',
> >             database = 'test',
> >             query = {'charset':'utf8'})
>
> >     def __init__(self,echo = True):
> >         engine = create_engine(Application.url,encoding = 'utf-8',echo
> > = echo)
> >         Session = sessionmaker(bind=engine)
> >         self.session = Session()
> >         self.metadata = MetaData()
> >         self.metadata.bind = self.session.connection()
>
> >     def close(self):
> >        
>
> ...
>
> więcej »
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected]
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