SQLAlchemy中的正确的外部联接

Nih*_*ant 8 python sql sqlalchemy

我有两个表beard,moustache定义如下:

+--------+---------+------------+-------------+
| person | beardID | beardStyle | beardLength |
+--------+---------+------------+-------------+

+--------+-------------+----------------+
| person | moustacheID | moustacheStyle |
+--------+-------------+----------------+
Run Code Online (Sandbox Code Playgroud)

我在PostgreSQL中创建了一个SQL查询,它将组合这两个表并生成以下结果:

+--------+---------+------------+-------------+-------------+----------------+
| person | beardID | beardStyle | beardLength | moustacheID | moustacheStyle |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 1       | rasputin   | 1           |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 2       | samson     | 12          |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    |         |            |             | 1           | fu manchu      |
+--------+---------+------------+-------------+-------------+----------------+
Run Code Online (Sandbox Code Playgroud)

查询:

SELECT * FROM beards LEFT OUTER JOIN mustaches ON (false) WHERE  person = "bob"
UNION ALL
SELECT * FROM beards b RIGHT OUTER JOIN mustaches ON (false) WHERE  person = "bob"
Run Code Online (Sandbox Code Playgroud)

但是我无法创建它的SQLAlchemy表示.我尝试了几种方法from_statement,outerjoin但实际上没有一种方法可行.任何人都可以帮助我吗?

Tim*_*mur 10

在 SQL 中,A RIGHT OUTER JOIN B相当于B LEFT OUTER JOIN A. 因此,从技术上讲,RIGHT OUTER JOINAPI 中不需要- 可以通过切换目标“可选”和加入“可选”的位置来做同样的事情。SQL Alchemy 为此提供了一个 API:

# this **fictional** API:
query(A).join(B, right_outer_join=True)  # right_outer_join doesn't exist in SQLA!

# can be implemented in SQLA like this:
query(A).select_entity_from(B).join(A, isouter=True)
Run Code Online (Sandbox Code Playgroud)

请参阅 SQLA Query.join() 文档“控制要加入的内容”部分


Nih*_*ant 5

根据@Francis P建议,我想出了这个片段:

q1 = session.\
     query(beard.person.label('person'),
           beard.beardID.label('beardID'),
           beard.beardStyle.label('beardStyle'),
           sqlalchemy.sql.null().label('moustachID'),
           sqlalchemy.sql.null().label('moustachStyle'),
     ).\
     filter(beard.person == 'bob')

q2 = session.\
     query(moustache.person.label('person'),
           sqlalchemy.sql.null().label('beardID'), 
           sqlalchemy.sql.null().label('beardStyle'),
           moustache.moustachID,
           moustache.moustachStyle,
     ).\
     filter(moustache.person == 'bob')

result = q1.union(q2).all()
Run Code Online (Sandbox Code Playgroud)

然而,这可行,但你不能将其称为答案,因为它看起来像一个黑客。这是 sqlalchemy 中应该存在的又一个原因RIGHT OUTER JOIN