[英]RIGHT OUTER JOIN in SQLAlchemy
我有兩個表beard
和moustache
定義如下:
+--------+---------+------------+-------------+
| 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
但沒有一個真正有效。 任何人都可以幫助我嗎?
在 SQL 中, A RIGHT OUTER JOIN B
等價於B LEFT OUTER JOIN A
。 因此,從技術上講,在RIGHT OUTER JOIN
API 中不需要 - 可以通過切換目標“可選”和加入“可選”的位置來做同樣的事情。 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() 文檔, “控制要加入的內容”部分。
根據@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()
但是,這有效,但您不能將其稱為答案,因為它看起來像是一種黑客行為。 這是 sqlalchemy 中應該有RIGHT OUTER JOIN
另一個原因。
如果 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()
。
這個答案是對上一個(Timur 的答案)的補充。
這是我所擁有的,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)
這似乎可以獨立工作,但似乎不可能與另一個選擇表達式結合使用
不幸的是,SQLAlchemy 只為LEFT OUTER JOIN
提供 API 為.outerjoin()
。 如上所述,我們可以通過反轉LEFT OUTER JOIN
的操作數來獲得RIGHT OUTER JOIN
LEFT OUTER JOIN
; 例如。 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()
只需添加答案,您就可以從SQLAlchemy doc 中找到select_from
的用法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.