使用row_number()删除SQLAlchemy查询

huangapple go评论97阅读模式
英文:

Delete SQLAlchemy query using row_number()

问题

我正在寻找一种使用row_number()函数来进行query.delete()的适当方法。

以下是我当前的解决方案:

  1. subquery = session.query(Foo,
  2. func.row_number().over(order_by=desc(Foo.bar)).label("row_number")).subquery()
  3. subquery = session.query(subquery).filter(subquery.c.row_number > 3)
  4. subquery = subquery.from_self(Foo.id)
  5. query = session.query(Foo).filter(
  6. Foo.id.in_(subquery)
  7. )

我不喜欢我需要明确检查Foo.id是否在ID列表中。我需要比较所有对象的列而不是硬编码它们。类似于:

  1. subquery = session.query(Foo,
  2. func.row_number().over(order_by=desc(Foo.bar)).label("row_number")).subquery()
  3. subquery = session.query(subquery).filter((subquery.c.row_number > 3))
  4. subquery = subquery.from_self(Foo)
  5. query = session.query(Foo).filter(
  6. Foo.in_(subquery)
  7. )

但是当然这不起作用。

如果有人能提出解决方案,我将不胜感激。

英文:

I'm looking for an appropriate way to make query.delete() using row_number() function.

Below there is my current solution:

  1. subquery = session.query(Foo,
  2. func.row_number().over(order_by=desc(Foo.bar)).label("row_number")).subquery()
  3. subquery = session.query(subquery).filter(subquery.c.row_number > 3)
  4. subquery = subquery.from_self(Foo.id)
  5. query = session.query(Foo).filter(
  6. Foo.id.in_(subquery)
  7. )

I don't like that I need explicilty check if Foo.id in list of ids. I need to compare all object's columns without hardcoding them. Somthing like:

  1. subquery = session.query(Foo,
  2. func.row_number().over(order_by=desc(Foo.bar)).label("row_number")).subquery()
  3. subquery = session.query(subquery).filter((subquery.c.row_number > 3))
  4. subquery = subquery.from_self(Foo)
  5. query = session.query(Foo).filter(
  6. Foo.in_(subquery)
  7. )

But of course this does not work.

I would be grateful if anyone will suggest a solution.

答案1

得分: 0

经过一些调查,我了解到以下内容:

  1. 您需要为筛选指定确切的模型字段。我创建了一个名为 _get_reference_attrs 的方法,该方法使用主键字段,如果没有主键,则使用所有字段。

  2. 有问题的代码使用了3个嵌套的查询(不包括删除查询),但只需要2个。为此,您需要正确收集您在上面选择中选择的内容(attrs_subquery)。

这是我的解决方案:

  1. from sqlalchemy import func, desc, tuple_, inspect
  2. def _get_reference_attrs(model):
  3. """
  4. 收集将在删除查询中使用的模型属性
  5. 默认情况下,使用主键列。如果没有主键,则使用所有列。
  6. """
  7. mapper = inspect(model)
  8. primary_key_names = [primary_key.key for primary_key in mapper.primary_key]
  9. if primary_key_names:
  10. attrs = [attr for attr in mapper.attrs if attr.key in primary_key_names]
  11. else:
  12. attrs = mapper.attrs
  13. return attrs
  14. attrs = _get_reference_attrs(Foo)
  15. subquery = session.query(*attrs,
  16. func.row_number().over(order_by=desc(Foo.bar)).label("row_number")).subquery()
  17. attrs_subquery = [getattr(subquery.c, attr.key) for attr in attrs]
  18. subquery = session.query(*attrs_subquery).select_from(subquery).filter(subquery.c.row_number > 1)
  19. query = session.query(Foo).filter(
  20. tuple_(*attrs).in_(subquery)
  21. )

希望这对您有所帮助。

英文:

After some time of investigations, I understood the following:

  1. You need to specify exact model fields for filtration. I created a method _get_reference_attrs that uses primary key fields, or all fields, if there is no primary key.
  2. Code in question used 3 nested select queries (not including delete query), but only 2 are required. For this you need to correctly collect what you are selecting in the upper selection (attrs_subquery)

That's my solution:

  1. from sqlalchemy import func, desc, tuple_, inspect
  2. def _get_reference_attrs(model):
  3. """
  4. Collecting attributes of model that will be used in delete query
  5. By default the primary key columns are used. If no primary key - all columns are used.
  6. """
  7. mapper = inspect(model)
  8. primary_key_names = [primary_key.key for primary_key in mapper.primary_key]
  9. if primary_key_names:
  10. attrs = [attr for attr in mapper.attrs if attr.key in primary_key_names]
  11. else:
  12. attrs = mapper.attrs
  13. return attrs
  14. attrs = _get_reference_attrs(Foo)
  15. subquery = session.query(*attrs,
  16. func.row_number().over(order_by=desc(Foo.bar)).label("row_number")).subquery()
  17. attrs_subquery = [getattr(subquery.c, attr.key) for attr in attrs]
  18. subquery = session.query(*attrs_subquery).select_from(subquery).filter(subquery.c.row_number > 1)
  19. query = session.query(Foo).filter(
  20. tuple_(*attrs).in_(subquery)
  21. )

huangapple
  • 本文由 发表于 2023年4月4日 03:57:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/75923333.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定