【问题标题】:Gradually filtering a table based on a column in Sqlalchemy基于Sqlalchemy中的列逐步过滤表
【发布时间】:2020-01-15 04:08:10
【问题描述】:

假设我有一个包含 2 列的表,其中包含 Order IDStudent ID

Order ID | Student ID |
-----------------------
1        | 1
1        | 2
1        | 3
2        | 1
2        | 3
3        | 1
3        | 2
4        | 1
4        | 2
4        | 3
5        | 2
5        | 3
.....

这里是多对多的关系:一门课程可以包含多个学生,一个学生可以注册多个课程。

问题是:我想过滤包含特定学生 ID 集的课程。例如:

  • 如果学生 ID 集为 (1,2,3),则返回的课程 ID 应为 (1,4),因为只有这 2 门课程让该集中的所有学生都注册了。

  • 如果学生ID设置为(1,2),则返回的课程ID应为(1,3,4)

  • 如果学生ID设置为(2,3),那么结果应该是(1,4,5)

等等

学生 ID 集的大小可以根据 Python 中的集的限制而变化。

目前,我正在查询特定课程并将对象存储到特定列表中,然后使用 Python 进行过滤。但是,从上表中多次查询数千个项目只是很慢。

【问题讨论】:

  • 您使用的是什么数据库?这看起来很像集合逻辑。
  • @SunnyPatel 这是 PostGres,我更喜欢在使用实际 SQL 之前在 SqlAlchemy 中进行。为了测试,我使用内存中的 SqlLite,它很快,但是当使用 PostGres 实际部署在 AWS 云上时,速度慢得让人无法接受,现在我正在修复它。
  • 我有 DB 优先的心态,以确保我的解决方案可以使用干净的 SQL 代码,因为有时将其转换为 ORM 语言可能会稀释它。所以我为你提供了一个基于数据库的解决方案。希望对您有所帮助!

标签: python sqlalchemy


【解决方案1】:

这对我来说是 PostgreSQL 中的一个有趣的解决方案。看看我的DB Fiddle 这个:

SELECT "Order ID"
FROM enrollments
GROUP BY "Order ID"
HAVING ARRAY[1, 2, 3] <@ array_agg("Student ID")

对于不知情的人,上述查询基本上对Order ID 进行分组,并仅过滤数组(1, 2, 3) 完全包含在同一订单(课程)的所有Student IDs 中的那些。

这可以翻译成 SQLAlchemy(未经测试),类似于:

from sqlalchemy.dialects.postgresql import array, ARRAY, array_agg
session.query(Enrollments)
       .with_entities(Enrollments["Order ID"])
       .group_by(Enrollments["Order ID"])
       .having(array_agg(
               Enrollments["Student ID"],
               type_=ARRAY(Integer)
           )
           .contains([1, 2, 3])
       )
       .all()

【讨论】:

  • 谢谢! @IljaEverilä
  • 感谢 Sunny,您的示例有所帮助!现在速度很快。但是,我想将结果进一步切片,一次只显示 10 行。我在having 子句之后放了一个.slice(start ,end),但它不起作用。
  • @Amumu,它应该可以工作(我个人没有使用过),你在.slice() 之后取下了.all() 终结器吗?它应该立即获取您的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 2019-12-26
相关资源
最近更新 更多