1

我有一个像这样的 SqlAlchemy 表:

table = sql.Table('treeItems', META,
    sql.Column('id', sql.Integer(), primary_key=True),
    sql.Column('type', sql.String, nullable=False),
    sql.Column('parentId', sql.Integer, sql.ForeignKey('treeItems.id')),
    sql.Column('lineage', PGArray(sql.Integer)),
    sql.Column('depth', sql.Integer),
)

它被映射到这样的对象:

orm.mapper(TreeItem, TreeItem.table, polymorphic_on=TreeItem.table.c.type, polymorphic_identity='TreeItem')

我想选择给定节点的任何子节点,所以我正在寻找的是看起来像这样的 SQL(对于 pk=2 的父节点):

SELECT *
FROM "treeItems"
WHERE ARRAY[2] <@ "treeItems".lineage AND "treeItems".id != 2
ORDER BY "treeItems".lineage

这是我用来尝试获取上述 SQL 的 SqlAlchemy/Python 代码,但运气不佳:

arrayStr = 'ARRAY[%s]' % ','.join([str(i) for i in self.lineage])
lineageFilter = expr.text('%s <@ %s' % (arrayStr, TreeItem.table.c.lineage))
query = SESSION.query(TreeItem).filter(expr.and_(lineageFilter, TreeItem.table.c.id!=self.id))

但这是我最终得到的 SQL(请注意 where 子句中 treeItems 表名周围没有引号):

SELECT "treeItems".id AS "treeItems_id", "treeItems".type AS "treeItems_type", "treeItems"."parentId" AS "treeItems_parentId", "treeItems".lineage AS "treeItems_lineage", "treeItems".depth AS "treeItems_depth"
FROM "treeItems"
WHERE ARRAY[2] <@ treeItems.lineage AND "treeItems".id != %(id_1)s

所以,现在的问题:

有没有比使用 text() 表达式更好的方法/SqlAlchemy 中是否有可以使用 PGArray 执行 <@ 的运算符或表达式?

如果我必须使用 text() 表达式,如何让引号显示在我的表名周围?

谢谢大家!

4

2 回答 2

4

SQLAlchemy 的子句元素具有用于自定义运算符的 .op() 方法。不可用的是数组文字的特殊子句。您可以使用 literal_column 指定数组文字:

print sql.literal_column('ARRAY[2]').op('<@')(table.c.lineage)
# ARRAY[2] <@ "treeItems".lineage

如果您想要一个更好的数组文字 API,那么您可以使用 SQLAlchemy 0.5.4 中添加的 sqlalchemy.ext.compiler 模块来创建

于 2009-06-05T21:53:39.837 回答
0

在这种特殊情况下,我注意到 SQL 中的引用是由于我使用的是混合大小写的表名。将表名从“treeItems”转换为“tree_items”解决了引用问题,并且我能够让我的文本表达式工作:

expr.text('%s <@ %s' % (arrayStr, TreeItem.table.c.lineage))

这是一个修复,很高兴知道需要引用混合大小写的表名,但 Ants 的回答仍然是解决问题的正确方法。

于 2009-06-06T05:52:33.423 回答