【问题标题】:How to use SQLAlchemy to select value at a position in a PostgreSQL ARRAY?如何使用 SQLAlchemy 在 PostgreSQL ARRAY 中的某个位置选择值?
【发布时间】:2013-01-14 13:14:50
【问题描述】:

对于嵌套评论系统,我使用Comment 模型中的以下定义将树结构存储在 PostgreSQL 表中:

path = sa.Column(ARRAY(sa.Integer))

这会将所有 cmets 的 ID 存储在当前路径的路径中。因此,如果 id 为 15 的评论是 11 和 13 的子项,则其路径将为 [11,13,15]

现在我想找到并计算子 cmets。因此,为了找到评论 11 的所有子项,包括它自己,我想生成如下所示的 SQL:

SELECT id, path FROM comments WHERE path[1] = 11;

在我的数据库中,这很高兴返回一组不错的评论 11 及其子项。

对于上面的例子,如果我想获取评论的孩子,我可以使用下面的 SQL:

SELECT id, path FROM comments WHERE path[1] = 11 AND path[2] = 13;

应该如何使用 SQLAlchemy 来生成这个 SQL?

我已经使用filter_by()filter() 进行了破解,但没有取得多大成功……这些都不起作用:

q = Comment.query.filter(path[1] == 11)
> NameError: name 'path' is not defined

q = Comment.query.filter_by(path[1] = 11)
> SyntaxError: keyword can't be an expression

我不希望为此查询编写自定义 SQL,但如果这是唯一的方法,那么请提供一些关于如何最好地构造它的指针。

编辑 1

确认我使用的是 SQLAlchemy 0.7 - 因此,适用于此版本(周围)的答案会更有帮助。

我意识到对于上面的评论实现,没有必要在确切的位置找到 id 编号,在任何位置找到它们也可以。所以任何关于如何创建 SQLAlchemy 来生成类似这样的东西的输入都会很好:

SELECT id, path FROM comments WHERE 11 = ANY (path);

这可能吗?

【问题讨论】:

  • 您收到 SyntaxError 'keyword can't be an expression' 因为您使用了单个等号 = 而不是 ==
  • @slashdottir 谢谢 - 它总是那些愚蠢的小事。

标签: python postgresql sqlalchemy


【解决方案1】:

这仅适用于从 SQLAlchemy 0.8(撰写本文时为 beta2)开始:

from sqlalchemy.dialects import postgresql

class Comment(Base):
    __tablename__ = 'comments'
    id = Column(Integer, primary_key=True)
    path = Column(ARRAY(Integer))

q = Comment.query.filter(Comment.path[1] == 11)
# This is just to demonstrate how compiled query would look like.
print q.statement.compile(dialect=postgresql.dialect())

输出:

SELECT comments.id, comments.path 
FROM comments 
WHERE comments.path[%(path_1)s] = %(param_1)s

更新

最近在 SA 邮件列表中有一个 discussion,关于如何为 Postgres 数组创建 = ANY(和相关)查询。即使那里的示例是为 0.8 编写的,它也应该在 0.7 中工作。这是 0.7(已测试)的 = ANY 的工作实现:

from sqlalchemy.sql import literal, tuple_

# There's already built-in any() function in Python, we don't want to
# shadow that.
def any_(value, col):
    return literal(value).op('= ANY')(tuple_(col))

q = Comment.query.filter(any_(11, Comment.path))

【讨论】:

  • 嗨,Audrius,这很有帮助。我现在被困在 0.7 上......有什么方法可以在你知道的 SQL 中生成“ANY ()”吗?问题已更新。
  • 我更新了答案以演示如何在 SA 中编写 = ANY 查询。不过,不确定在 0.7 中可以将其推进多远。
  • 谢谢 - 这很好,我已将自己添加到 SA 邮件列表中。
  • 非常感谢。我一直在疯狂地寻找 ANY 运算符的用法。
猜你喜欢
  • 1970-01-01
  • 2012-12-08
  • 2020-04-22
  • 1970-01-01
  • 2012-08-08
  • 2017-11-18
  • 2021-11-14
  • 2017-09-02
  • 1970-01-01
相关资源
最近更新 更多