如何在 SqlAlchemy 上订购嵌套的 SQL SELECT
Posted
技术标签:
【中文标题】如何在 SqlAlchemy 上订购嵌套的 SQL SELECT【英文标题】:How to order nested SQL SELECT on SqlAlchemy 【发布时间】:2020-11-28 18:13:22 【问题描述】:我编写了一个 SQL 脚本,它应该在用户 id 之前获取 X 个条目,根据注册日期在有序 db 表上按registration_date desc 排序。
更具体地说,假设这些是有序数据库中的一些条目:
id | Name | Email | registration_data
3939 | Barbara Hayes | barbara.hayes@example.com | 2019-09-15T23:39:26.910Z
689 | Noémie Harris | noemie.harris@example.com | 2019-09-14T21:39:15.641Z
2529 | Andrea Iglesias | andrea.iglesias@example.com | 2019-09-13T02:59:08.821Z
3890 | Villads Andersen | villads.andersen@example.com | 2019-09-12T06:29:48.708Z
3685 | Houssine Van Sabben | houssine.vansabben@example.com | 2019-09-12T02:27:08.396Z
我想让用户超过 id 3890。所以查询应该返回
689 | Noémie Harris | noemie.harris@example.com | 2019-09-14T21:39:15.641Z
2529 | Andrea Iglesias | andrea.iglesias@example.com | 2019-09-13T02:59:08.821Z
我写的原始 SQL 是这样的:
SELECT * from (
SELECT id, name, email, registration_date FROM public.users
WHERE users.registration_date > (SELECT registration_date FROM users WHERE id = 3890)
order by registration_date
limit 2 )
as a
order by registration_date desc
见this dbfiddle。
我尝试实现 SqlAlchemy 代码,但没有成功。我相信我在子查询上犯了一个错误。这是我到目前为止所做的。
registration_date_min = db.query(User.registration_date) \
.order_by(User.registration_date) \
.filter(User.id == ending_before).first()
users_list = db.query(User) \
.filter(User.registration_date > registration_date_min) \
.order_by('registration_date').limit(limit).subquery('users_list')
return users_list.order_by(desc('registration_date'))
P.s ending_before
代表一个 user_id。就像示例中的 3890
一样。
关于 SqlAlchemy 部分的任何想法都会非常有帮助!
【问题讨论】:
codeshare.io/5QwQEm 真的快吗? @MartijnPieters 表格的示例只是按日期降序排列,这就是具体日期的原因。说实话,我对你所说的示例日期有点困惑,这就是我发布代码共享的原因,以便在那里更快地讨论它。从好的方面来说,我尝试了你的解决方案,它奏效了! 现在在移动设备上。我把查询放到一个 dbfiddle 上,发现我一定把用户 ID 弄混了。 :-/ 很抱歉! 【参考方案1】:首先,你的registration_date_min
查询已经被执行了;你在那里有一列有一列。删除first()
调用;它执行SELECT
并返回第一行。
当您通过主键进行选择时,只会有一行,您不需要对其进行排序。只需使用:
registration_date_min = db.query(User.registration_date).filter(
User.id == ending_before
)
现在是一个查询对象,可以直接用于比较:
users_list = (
db.query(User)
.filter(User.registration_date > registration_date_min)
.order_by(User.registration_date)
.limit(limit)
)
然后您可以从该查询中self-select with Query.from_self()
应用最终排序:
return user_list.from_self().order_by(User.registration_date.desc()))
这会产生以下 SQL(在 SQLite 上,其他方言可能不同):
SELECT anon_1.users_id AS anon_1_users_id, anon_1.users_name AS anon_1_users_name, anon_1.users_email AS anon_1_users_email, anon_1.users_registration_date AS anon_1_users_registration_date
FROM (SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.registration_date AS users_registration_date
FROM users
WHERE users.registration_date > (SELECT users.registration_date AS users_registration_date
FROM users
WHERE users.id = ?) ORDER BY users.registration_date
LIMIT ? OFFSET ?) AS anon_1 ORDER BY anon_1.users_registration_date DESC
如果我将以下模型与__repr__
一起使用:
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
email = db.Column(db.String)
registration_date = db.Column(db.DateTime)
def __repr__(self):
return f"<User(self.id, self.name!r, self.email!r, self.registration_date!r>"
并打印我得到的查询结果实例:
<User(689, 'Noémie Harris', 'noemie.harris@example.com', datetime.datetime(2019, 9, 14, 21, 39, 15, 641000)>
<User(2529, 'Andrea Iglesias', 'andrea.iglesias@example.com', datetime.datetime(2019, 9, 13, 2, 59, 8, 821000)>
【讨论】:
以上是关于如何在 SqlAlchemy 上订购嵌套的 SQL SELECT的主要内容,如果未能解决你的问题,请参考以下文章
如何以灵活的方式将嵌套的 pydantic 模型用于 sqlalchemy