2015-02-12 4 views
0

Я работаю с базой данных, которая имеет отношение, которое выглядит как:SQLAlchemy присоединиться и заказ по на нескольких таблиц

class Source(Model): 
     id = Identifier() 

    class SourceA(Source): 
     source_id = ForeignKey('source.id', nullable=False, primary_key=True) 
     name = Text(nullable=False) 

    class SourceB(Source): 
     source_id = ForeignKey('source.id', nullable=False, primary_key=True) 
     name = Text(nullable=False) 

    class SourceC(Source, ServerOptions): 
     source_id = ForeignKey('source.id', nullable=False, primary_key=True) 
     name = Text(nullable=False) 

То, что я хочу сделать, это соединить все исходные таблицы, SourceA, SourceB, SourceC и затем order_by имя.

Звук легкий для меня, но я уже стучал головой об этом, пока теперь и мои головы начинают болеть. Также я не очень хорошо знаком с SQL или sqlalchemy, поэтому было много просмотра документов, но безрезультатно. Может быть, я просто этого не вижу. This кажется близким, хотя и имеет отношение к более новой версии, чем то, что у меня есть (см. Версии ниже).

Я чувствую себя близко не то, что что означает что угодно. Вот моя последняя попытка, которая кажется хорошей вплоть до звонка order_by.

Sources = [SourceA, SourceB, SourceC] 
    # list of join on Source 
    joins = [session.query(Source).join(source) for source in Sources] 
    # union the list of joins 
    query = joins.pop(0).union_all(*joins) 

запрос кажется правильным в данный момент, насколько я могу сказать, то есть query.all() работы. Итак, теперь я пытаюсь применить order_by, который не выдает ошибку до тех пор, пока не вызывается .all.

Попытка 1: Я просто использовать атрибут Я хочу

query.order_by('name').all() 
    # throws sqlalchemy.exc.ProgrammingError: (ProgrammingError) column "name" does not exist 

Попытка 2: Я просто использовать определенный атрибут столбца Я хочу

query.order_by(SourceA.name).all() 
    # throws sqlalchemy.exc.ProgrammingError: (ProgrammingError) missing FROM-clause entry for table "SourceA" 

Это очевидно? Что мне не хватает? Благодаря!

версии:

sqlalchemy. версия = '0.8.1'

(PostgreSQL) 9.1.3

EDIT Я имею дело с каркасом, который хочет дескриптор объекта запроса. У меня есть простой запрос, который, как представляется, выполняет то, что я хочу, но мне все равно придется его обернуть в объект запроса. Не уверен, что это возможно. Погуглить ...

select = """ 
    select s.*, a.name from Source d inner join SourceA a on s.id = a.Source_id 
    union 
    select s.*, b.name from Source d inner join SourceB b on s.id = b.Source_id 
    union 
    select s.*, c.name from Source d inner join SourceC c on s.id = c.Source_id 
    ORDER BY "name"; 
""" 
selectText = text(select) 
result = session.execute(selectText) 
# how to put result into a query. maybe Query(selectText)? googling... 
result.fetchall(): 
+0

Используют вы [ 'inheritance'] (Http: //docs.sqlalchemy. орг/о/rel_0_9/ОРМ/inheritance.html)? – van

+0

напечатайте 'query.order_by ('name')', это может дать вам некоторую подсказку. – rajpy

+0

@van Я использую наследование, которое заставляет меня полагать, что без какого-либо из вышеупомянутого кода я мог бы просто выполнить запрос (источник) .order_by ('name'). All() ', но это терпит неудачу, потому что столбец 'name' не существует в базовом классе Source. 'sqlalchemy.exc.ProgrammingError: (ProgrammingError) column" name "не существует' – ralphinator80

ответ

1

Предполагая, что coalesce функции достаточно хорошо, ниже примеры должны указать вам в этом направлении. Один из вариантов автоматически создает список детей, а другой - явный.

Это не запрос, указанный в вашем редактировать, но вы можете сортировать (ваш первоначальный запрос):

def test_explicit(): 
    # specify all children tables to be queried 
    Sources = [SourceA, SourceB, SourceC] 
    AllSources = with_polymorphic(Source, Sources) 

    name_col = func.coalesce(*(_s.name for _s in Sources)).label("name") 
    query = session.query(AllSources).order_by(name_col) 
    for x in query: 
     print(x) 


def test_implicit(): 
    # get all children tables in the query 
    from sqlalchemy.orm import class_mapper 
    _map = class_mapper(Source) 
    Sources = [_smap.class_ 
       for _smap in _map.self_and_descendants 
       if _smap != _map # @note: exclude base class, it has no `name` 
       ] 
    AllSources = with_polymorphic(Source, Sources) 

    name_col = func.coalesce(*(_s.name for _s in Sources)).label("name") 
    query = session.query(AllSources).order_by(name_col) 
    for x in query: 
     print(x) 
+0

Спасибо @van! Это именно то, что я искал. – ralphinator80

0

Ваша первая попытка звучит, как это не работает, потому что нет никакого имени в источнике, который является корнем таблицы запроса. Кроме того, после ваших объединений будет несколько столбцов имени, поэтому вам нужно быть более конкретными. Попробуйте

query.order_by('SourceA.name').all() 

Что касается вашей второй попытки, то что такое ServerA?

query.order_by(ServerA.name).all() 

Возможно, опечатка, но не уверена, что это для SO или вашего кода. Попробуйте:

query.order_by(SourceA.name).all() 
+0

Пробовал вы первые предложения, передавая строковый аргумент. Нет кубиков. 'ServerA' был опечаткой, должен был быть' SourceA'. Обновлено. Я не вижу нескольких столбцов 'name' из объединений. Я создаю список запросов из одного соединения на каждой дочерней таблице с родителем, а затем вызывает 'union_all' и все те отдельные запросы, которые объединяют столбцы' name'. – ralphinator80

Смежные вопросы