我正在寻找复制我在 pgAdmin 中使用的 SQL 查询来连接多个表并将结果表下载到 CSV 文件中。我已经成功使用 pgAdmin 并希望使用 SQLAlchemy 获得相同的结果,因为我的应用程序通过 SQLAlchemy 与数据库交互。
在 pgAdmin 中,我使用这样的查询:
SELECT * FROM visits
LEFT JOIN patients ON visits.patient_id = patients.patient_id
LEFT JOIN [many more left joins here]
WHERE visits.visit_id = 1;
为了使用 SQLAlchemy 完成相同的任务,我尝试了以下代码:
def get_all_data_for_visit(self, visit_id: int):
try:
stmt = select(Visit, Patient).outerjoin(Patient, and_(Visit.patient_id == Patient.patient_id, Visit.visit_id == visit_id))
result = self.db.execute(stmt).all()
if result:
for row in result:
print(row.Patient.patient_id, row.Visit.visit_type)
return result
else:
return None
except OperationalError as e:
self.show_error_msg()
但是,此代码返回患者对象和访问对象,这不是期望的结果。我想迭代对象并将其所有属性(例如,
row.Visit.visit_type
)打印到 CSV 中。我不能简单地迭代所有现有对象,因为有些对象可能是 None
,但我仍然希望结果(在本例中为 null
)在表中。对于我的 SQL 查询,这是可行的。使用 sqlalchemy 我得到一个 AttributeError。
我阅读了相关问题,但找不到我的具体问题的解决方案。
谢谢您的帮助!
SQLAlchemy 的 ORM 层在连接结果中返回对象元组,因为,一般来说,程序员使用 ORM 是因为使用对象图而不是行数据的平面数组更方便。在问题中的情况下 - 将联接查询结果直接写入报告 - 使用平面数组更方便。解决方案是使用 SQLAlchemy 的核心层而不是 ORM,这将像常规 SQL 一样运行。
核心层使用表而不是 ORM 实体。鉴于 ORM 实体类存在,可以从中获取表:
patients = Patient.__table__
visits = Visit.__table__
查询语句几乎相同,只是列是通过表的 .c
(或
.columns
)属性而不是直接访问的:
q = stmt = (
sa.select(Patient, Visit)
.outerjoin(Patient, Visit.patient_id == Patient.patient_id)
.where(Visit.visit_id == visit_id)
)
为了复制问题中的 SQL,我切换了投影中表的顺序,并且如 Barmar implied 那样,将 visit_id
过滤器从连接条件移至
WHERE
子句。查询可以通过会话或连接执行。执行的结果将是一个
CursorResult 实例,您可以将其视为命名元组的可迭代对象。可以通过名称或位置访问一行中的各个列。
请注意,SQLAlchemy 将自动消除结果列中多次出现的标识符的歧义。您可以通过调用CursorResult
的
.keys()
方法来查看结果中的列名称。