【问题标题】:Convert PostgreSQL COUNT … FILTER query to SQL Alchemy将 PostgreSQL COUNT … FILTER 查询转换为 SQL Alchemy
【发布时间】:2021-04-26 19:31:33
【问题描述】:

我是 SQLAlchemy 的新手,我想转换这个 PostgreSQL 查询:

SELECT product.*
, COUNT(feedback.like) FILTER (WHERE feedback.like = '1') AS like 
, COUNT(feedback.like) FILTER (WHERE feedback.like = '-1') AS unlike
FROM feedback, product
WHERE product.id = feedback.product_id
GROUP BY product.id
ORDER BY product.id;

我已经试过了:

 products = db.session.query(
            Product,
            func.count(Feedback.like > 0).label('like'),
            func.count(Feedback.like < 0).label('unlike')
            ).filter(Product.guide_name_id==id)
            .filter(Product.id == Feedback.product_id) 
            .group_by(Product.id) 
            .order_by(Product.id) 
            .all()

提前感谢您的帮助

【问题讨论】:

  • 您对当前结果有什么问题?
  • @rfkortekaas 当我在我的 API 上进行测试时,响应返回: - 如果没有喜欢,则所有字段都为 null - 如果有喜欢或不喜欢,则为 0 表示喜欢,不喜欢则为 0
  • 一个问题是您的第一个过滤器,根据您提供的 SQL,它不应该存在,并且可能保证不会有输出。

标签: sql postgresql sqlalchemy flask-sqlalchemy


【解决方案1】:

感谢@IljaEverilä 的评论,这里有一个更直接的答案:

class Product(Base):
    __tablename__ = "product"
    id = Column(Integer, primary_key=True)
    name = Column(String(50), nullable=False)

    def __repr__(self):
        return f"<Product(name='{self.name}')>"


class Feedback(Base):
    __tablename__ = "feedback"
    id = Column(Integer, primary_key=True)
    product_id = Column(Integer, ForeignKey(Product.id))
    like = Column(Integer)
    product = relationship(Product)


Base.metadata.create_all(engine)

with Session(engine) as session:

    # set up test data
    widget = Product(name="widget")
    session.add_all(
        [
            widget,
            Feedback(product=widget, like=1),
            Feedback(product=widget, like=1),
            Feedback(product=widget, like=-1),
            Product(name="gadget"),
        ]
    )

    # run the query
    query = (
        select(
            Product,
            func.count(Feedback.like)
            .filter(Feedback.like == 1)
            .label("likes"),
            func.count(Feedback.like)
            .filter(Feedback.like == -1)
            .label("dislikes"),
        )
        .select_from(Product)
        .outerjoin(Feedback)
        .group_by(Product)
    )
    results = session.execute(query).fetchall()
    print(results)
    # [(<Product(name='gadget')>, 0, 0), (<Product(name='widget')>, 2, 1)]

(原答案)

我不确定 SQLAlchemy 的 postgresql 方言是否专门处理 COUNT … FILTER,但您可以使用 SUM 和 CASE 完成同样的事情:

from sqlalchemy import __version__ as sa_version, case, Column, ForeignKey, func, Integer, String
from sqlalchemy.orm import Session

print(sa_version)  # 1.4.0b2


class Product(Base):
    __tablename__ = "product"
    id = Column(Integer, primary_key=True)
    name = Column(String(50), nullable=False)


class Feedback(Base):
    __tablename__ = "feedback"
    id = Column(Integer, primary_key=True)
    product_id = Column(Integer, ForeignKey(Product.id))
    like = Column(Integer)
    product = relationship(Product)


Base.metadata.create_all(engine)

with Session(engine, future=True) as session:
    widget = Product(name="widget")
    session.add_all(
        [
            widget,
            Feedback(product=widget, like=1),
            Feedback(product=widget, like=1),
            Feedback(product=widget, like=-1),
            Product(name="gadget"),
        ]
    )
    results = (
        session.query(
            Product.name,
            func.sum(case((Feedback.like > 0, 1), else_=0)).label(
                "likes"
            ),
            func.sum(case((Feedback.like < 0, 1), else_=0)).label(
                "dislikes"
            ),
        )
        .select_from(Product)
        .outerjoin(Feedback)
        .group_by(Product)
        .all()
    )
    print(results)  # [('widget', 2, 1), ('gadget', 0, 0)]

【讨论】:

猜你喜欢
  • 2020-03-06
  • 2018-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-01
  • 2018-12-08
  • 1970-01-01
相关资源
最近更新 更多