2013-08-01 69 views
3

我在使用核心組件時遇到SQLAlchemy的 select_from語句問題。我試圖建立外部連接查詢目前看起來像: SQLAlchemy將外連接ORM查詢轉換爲Core

query = select([b1.c.id, b1.c.num, n1.c.name, n1.c.num, ...] 
     ).where(and_(
      ... some conditions ... 
     ) 
    ).select_from(
     ???.outerjoin(
     n1, 
     and_(
      ... some conditions ... 
     ) 
    ).select_from(... more outer joins similar to the above ...) 

根據該文檔,結構應該是這樣的:

table1 = table('t1', column('a')) 
table2 = table('t2', column('b')) 
s = select([table1.c.a]).\ 
    select_from(
     table1.join(table2, table1.c.a==table2.c.b) 
    ) 

我的問題是,我沒有表1對象在這種情況下,因爲select ...部分包含列而不是一個表(請參閱我的查詢中的問號)。我試過使用n1.outerjoin(n1...,但是這導致了一個異常(Exception: (ProgrammingError) table name "n1" specified more than once)。

上面的代碼片段是基於工作會話(ORM)查詢派生的,我嘗試將其轉換(成功次數有限)。

b = Table('b', metadata, 
    Column('id', Integer, Sequence('seq_b_id')), 
    Column('num', Integer, nullable=False), 
    Column('active', Boolean, default=False), 
) 
n = Table('n', metadata, 
    Column('b_id', Integer, nullable=False), 
    Column('num', Integer, nullable=False), 
    Column('active', Boolean, default=False), 
) 
p = Table('p', metadata, 
    Column('b_id', Integer, nullable=False), 
    Column('num', Integer, nullable=False), 
    Column('active', Boolean, default=False), 
) 

n1 = aliased(n, name='n1') 
n2 = aliased(n, name='n2') 
b1 = aliased(b, name='b1') 
b2 = aliased(b, name='b2') 
p1 = aliased(p, name='p1') 
p2 = aliased(p, name='p2') 

result = sess.query(b1.id, b1.num, n1.c.name, n1.c.num, p1.par, p1.num).filter(
     b1.active==False, 
     b1.num==sess.query(func.max(b2.num)).filter(
      b2.id==b1.id 
     ) 
    ).outerjoin(
     n1, 
     and_(
      n1.c.b_id==b1.id, 
      n1.c.num<=num, 
      n1.c.active==False, 
      n1.c.num==sess.query(func.max(n2.num)).filter(
       n2.id==n1.c.id 
      ) 
     ) 
    ).outerjoin(
     p1, 
     and_(
      p1.b_id==b1.id, 
      p1.num<=num, 
      p1.active==False, 
      p1.num==sess.query(func.max(p2.num)).filter(
       p2.id==p1.id 
      ) 
     ) 
    ).order_by(b1.id) 

如何將此ORM查詢轉換爲普通的Core查詢? 更新:

我能夠縮小問題。看起來兩個select_from調用的組合導致了這個問題。

customer = Table('customer', metadata, 
    Column('id', Integer), 
    Column('name', String(50)), 
) 
order = Table('order', metadata, 
    Column('id', Integer), 
    Column('customer_id', Integer), 
    Column('order_num', Integer), 
) 
address = Table('address', metadata, 
    Column('id', Integer), 
    Column('customer_id', Integer),   
    Column('city', String(50)), 
) 
metadata.create_all(db) 

customer1 = aliased(customer, name='customer1') 
order1 = aliased(order, name='order1') 
address1 = aliased(address, name='address1') 

columns = [ 
    customer1.c.id, customer.c.name, 
    order1.c.id, order1.c.order_num, 
    address1.c.id, address1.c.city 
] 
query = select(columns) 
query = query.select_from(
    customer1.outerjoin(
     order1, 
     and_(
      order1.c.customer_id==customer1.c.id, 
     ) 
    ) 
) 
query = query.select_from(
    customer1.outerjoin(
     address1, 
     and_(
      customer1.c.id==address1.c.customer_id 
     ) 
    ) 
)  
result = connection.execute(query) 
for r in result.fetchall(): 
    print r 

上面的代碼將導致以下異常:

ProgrammingError: (ProgrammingError) table name "customer1" specified more than once 
'SELECT customer1.id, customer.name, order1.id, order1.order_num, address1.id, address1.city \nFROM customer, customer AS customer1 LEFT OUTER JOIN "order" AS order1 ON order1.customer_id = customer1.id, customer AS customer1 LEFT OUTER JOIN address AS address1 ON customer1.id = address1.customer_id' {} 

如果我是一個有點使用SQLAlchemy的經驗更豐富,我會說,這可能是一個錯誤......

+0

一個你可以用SQL煉丹做有用的東西是通過一個paramater到您的通話create_engine(回聲= TRUE),將放在SQLAlchemy的進入詳細模式。 [更多信息可以在這裏找到](http://stackoverflow.com/questions/2950385/debugging-displaying-sql-command-sent-to-the-db-by-sqlalchemy) – AlexLordThorsen

+0

那麼你最終試圖得到什麼一套? – AlexLordThorsen

+0

我想要得到'b1'和'n1'行的(左外部)連接。 – orange

回答

2

我終於設法解決了這個問題。除了級聯select_from之外,還需要將其他連接鏈接到實際連接。上面的查詢將改爲:

query = select(columns) 
query = query.select_from(
    customer1.outerjoin(
     order1, 
     and_(
      order1.c.customer_id==customer1.c.id, 
     ) 
    ).outerjoin(
     address1, 
     and_(
      customer1.c.id==address1.c.customer_id 
     ) 
    ) 
) 
相關問題