11

我有两个表beardmoustache定义如下:

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

+--------+-------------+----------------+
| person | moustacheID | moustacheStyle |
+--------+-------------+----------------+

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

+--------+---------+------------+-------------+-------------+----------------+
| person | beardID | beardStyle | beardLength | moustacheID | moustacheStyle |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 1       | rasputin   | 1           |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 2       | samson     | 12          |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    |         |            |             | 1           | fu manchu      |
+--------+---------+------------+-------------+-------------+----------------+

询问:

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"

但是我不能创建它的 SQLAlchemy 表示。我尝试了几种从实施from_statement到的方法,outerjoin但没有一个真正奏效。有人可以帮我吗?

4

5 回答 5

11

在 SQL 中,A RIGHT OUTER JOIN B等价于B LEFT OUTER JOIN A. 因此,从技术上讲,API 中不需要RIGHT OUTER JOIN- 可以通过切换目标“可选择”的位置并加入“可选择”来做同样的事情。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)

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

于 2019-01-24T15:27:50.023 回答
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()

但是,这可行,但您不能将其称为答案,因为它显示为 hack。这是 sqlalchemy 中应该存在的另一个原因RIGHT OUTER JOIN

于 2012-07-10T16:50:41.837 回答
2

如果 A,B 是表,您可以
SELECT * FROM A RIGHT JOIN B ON A.id = B.a_id WHERE B.id = my_id
通过:
SELECT A.* FROM B JOIN ON A.id = B.a_id WHERE B.id = my_id
在 sqlalchemy 中实现:

from sqlalchemy import select


result = session.query(A).select_entity_from(select([B]))\
    .join(A, A.id == B.a_id)\
    .filter(B.id == my_id).first()

例如:

# import ...

class User(Base):
    __tablenane = "user"

    id = Column(Integer, primary_key=True)
    group_id = Column(Integer, ForeignKey("group.id"))

class Group(Base):
    __tablename = "group"

    id = Column(Integer, primary_key=True)
    name = Column(String(100))

您可以使用以下代码通过用户 id 获取用户组名称:

# import ...
from sqlalchemy import select

user_group_name, = session.query(Group.name)\
    .select_entity_from(select([User]))\
    .join(Group, User.group_id == Group.id)\
    .filter(User.id == 1).first()

如果您想要外部连接,请使用outerjoin()而不是join().

这个答案是对前一个答案的补充(帖木儿的答案)。

于 2020-05-18T04:30:34.923 回答
1

这是我所拥有的,ORM 风格:

from sqlalchemy.sql import select, false

stmt = (
    select([Beard, Moustache])
    .select_from(
        outerjoin(Beard, Moustache, false())
    ).apply_labels()
).union_all(
    select([Beard, Moustache])
    .select_from(
        outerjoin(Moustache, Beard, false())
    ).apply_labels()
)

session.query(Beard, Moustache).select_entity_from(stmt)

这似乎可以自己工作,但似乎不可能与另一个选择表达式一起加入

于 2015-02-08T13:32:47.023 回答
0

LEFT OUTER JOIN不幸的是,SQLAlchemy 只为as提供 API .outerjoin()。如上所述我们可以RIGHT OUTER JOIN通过反转 ; 的操作数LEFT OUTER JOIN得到a 例如。A RIGHT JOIN B是一样的B LEFT JOIN A。在 SQL 中,以下语句是等价的:

SELECT * FROM A RIGHT OUTER JOIN B ON A.common = B.common;
SELECT * FROM B LEFT OUTER JOIN A ON A.common = B.common;

但是,在 SQLAlchemy 中,我们需要查询一个类然后执行join. 棘手的部分是重写 SQLAlchemy 语句以反转表。例如,下面前两个查询的结果是不同的,因为它们返回不同的对象。

# No such API (rightouterjoin()) but this is what we want.
# This should return the result of A RIGHT JOIN B in a list of object A
session.query(A).rightouterjoin(B).all()   # SELECT A.* FROM A RIGHT OUTER JOIN B ...

# We could reverse A and B but this returns a list of object B
session.query(B).outerjoin(A).all()        # SELECT B.* FROM B LEFT OUTER JOIN A ...

# This returns a list of object A by choosing the 'left' side to be B using select_from()
session.query(A).select_from(B).outerjoin(A).all()   # SELECT A.* FROM B LEFT OUTER JOIN A ...

# For OP's example, assuming we want to return a list of beard object:
session.query(beard).select_from(moustache).outerjoin(beard).all()

只需添加答案,您就可以select_fromSQLAlchemy 文档中找到使用方法。

于 2020-05-08T01:13:10.593 回答