如何在sqlalchemy中定义cte/query/join-hybrid_属性,而不必为模型中的每一行重复? 模型 测试1-使用混合_属性-意外结果

如何在sqlalchemy中定义cte/query/join-hybrid_属性,而不必为模型中的每一行重复? 模型 测试1-使用混合_属性-意外结果,sqlalchemy,Sqlalchemy,运行上面的代码会导致为每个“id”重复所有“full_desc”的列表,如下所示: (1, 'Category6 - Brand1 - Product1') (2, 'Category6 - Brand1 - Product1') (3, 'Category6 - Brand1 - Product1') (4, 'Category6 - Brand1 - Product1') (5, 'Category6 - Brand1 - Product1') (6, 'Category6 - Brand1

运行上面的代码会导致为每个“id”重复所有“full_desc”的列表,如下所示:

(1, 'Category6 - Brand1 - Product1')
(2, 'Category6 - Brand1 - Product1')
(3, 'Category6 - Brand1 - Product1')
(4, 'Category6 - Brand1 - Product1')
(5, 'Category6 - Brand1 - Product1')
(6, 'Category6 - Brand1 - Product1')
(7, 'Category6 - Brand1 - Product1')
(8, 'Category6 - Brand1 - Product1')
(9, 'Category6 - Brand1 - Product1')
(1, 'Category5 - Brand2 - Product2')
(2, 'Category5 - Brand2 - Product2')
(3, 'Category5 - Brand2 - Product2')
(4, 'Category5 - Brand2 - Product2')
... 81 rows in total
(1, 'Category6 - Brand1 - Product1')
(2, 'Category5 - Brand2 - Product2')
(3, 'Category7 - Brand4 - Product3')
(4, 'Category7 - Brand3 - Product4')
(5, 'Category5 - Brand1 - Product5')
(6, 'Category7 - Brand5 - Product6')
(7, 'Category3 - Brand2 - Product7')
(8, 'Category1 - Brand3 - Product8')
(9, 'Category4 - Brand3 - Product9')
外部模型定义的CTE 试验2-使用上述CTE定义(模型外)-预期结果-非预期方法 运行上面的代码会为每个id生成一个右描述列表,没有重复(只有9行),如下所示:

(1, 'Category6 - Brand1 - Product1')
(2, 'Category6 - Brand1 - Product1')
(3, 'Category6 - Brand1 - Product1')
(4, 'Category6 - Brand1 - Product1')
(5, 'Category6 - Brand1 - Product1')
(6, 'Category6 - Brand1 - Product1')
(7, 'Category6 - Brand1 - Product1')
(8, 'Category6 - Brand1 - Product1')
(9, 'Category6 - Brand1 - Product1')
(1, 'Category5 - Brand2 - Product2')
(2, 'Category5 - Brand2 - Product2')
(3, 'Category5 - Brand2 - Product2')
(4, 'Category5 - Brand2 - Product2')
... 81 rows in total
(1, 'Category6 - Brand1 - Product1')
(2, 'Category5 - Brand2 - Product2')
(3, 'Category7 - Brand4 - Product3')
(4, 'Category7 - Brand3 - Product4')
(5, 'Category5 - Brand1 - Product5')
(6, 'Category7 - Brand5 - Product6')
(7, 'Category3 - Brand2 - Product7')
(8, 'Category1 - Brand3 - Product8')
(9, 'Category4 - Brand3 - Product9')
问题: 我应该对@hybrid_属性和/或@hybridproperty.extension进行哪些更改,以获得测试2中所需的结果,但使用测试1中的方法?还是有更好的方法来实现这一点

环境
我不确定您是否应该使用
cte
。而
@hybrid_属性的非表达式部分不应使用任何查询

请参阅下面的代码,这些代码应该可以工作(使用sqlalchemy 1.4版):

及有关查询:

# in-memory (not using expressions, but potentially loading categories and brands from the database)
result_1 = session.query(Product).all()
for product in result_1:
    print(product.id, product.full_description)

# using .expression - get 'full_description' in one query.    
result_2 = session.query(Product.id, Product.full_description).all()
for product_id, fulldesc in result_2:
    print(product_id, fulldesc)
,其中后者将生成以下
SQL
语句:

SELECT product.id,

  (SELECT concat(category.description, %(concat_2)s, brand.description, %(concat_3)s, product.description) AS concat_1
   FROM category,
        brand
   WHERE category.id = product.category_id
     AND brand.id = product.brand_id) AS full_desc_subquery

FROM product

非常感谢@van!。但是,我似乎无法在当前环境中使用结果_2(使用.expression)。我忘了在我的问题上提到我正在使用的软件包。我使用的是sqlalchemy 1.3.20和sqlalchemy_utils 0.36.7,也是postgresql 13。我曾尝试将sqlalchemy升级到1.4.2,但它与sqlalchemy_utils冲突,后者只能升级到0.36.8。我在sqlalchemy 1.3.20中遇到的错误可以在这里找到。我尝试将语句更改为:@full_description.expression def full_description(cls):subq=(session.query(func.concat(Category.description)”-“,Brand.description,“-”,cls.description,).filter(Category.id==cls.Category\u id)。filter(Brand.id==cls.Brand\u id)。as\u scalar().label(“full\u desc\u subquery”))返回子查询以使其工作,但是这是正确的方法吗?是因为sqlalchemy 1.3.2和1.4.2之间的变化吗?我对编程非常陌生,掌握sqlalchemy的文档已经很有挑战性,更不用说跟上版本之间的变化了。我认为1.3和1.4版本之间没有什么不同。一些在1.3中被弃用的构造现在在1.4中不起作用。我用1.4进行了测试。
SQLAlchemy==1.3.20
SQLAlchemy-Utils==0.36.7
PostgreSQL 13
@hybrid_property
def full_description(self):
    return self.category.description + " - " + self.brand.description + " - " + self.description

@full_description.expression
def full_description(cls):
    subq = (
        select(
            func.concat(
                Category.description,
                " - ",
                Brand.description,
                " - ",
                cls.description,
            )
        )
        .where(Category.id == cls.category_id).where(Brand.id == cls.brand_id)
        .scalar_subquery()
        .label("full_desc_subquery")
    )
    return subq
# in-memory (not using expressions, but potentially loading categories and brands from the database)
result_1 = session.query(Product).all()
for product in result_1:
    print(product.id, product.full_description)

# using .expression - get 'full_description' in one query.    
result_2 = session.query(Product.id, Product.full_description).all()
for product_id, fulldesc in result_2:
    print(product_id, fulldesc)
SELECT product.id,

  (SELECT concat(category.description, %(concat_2)s, brand.description, %(concat_3)s, product.description) AS concat_1
   FROM category,
        brand
   WHERE category.id = product.category_id
     AND brand.id = product.brand_id) AS full_desc_subquery

FROM product