SQLAlchemy对汇总联接进行排序和分组

时间:2018-11-27 12:25:40

标签: python sqlalchemy flask-sqlalchemy

我有一个模拟UsersQuestionsAnswers的数据库。

Questions具有特定的typevalue,作为应用程序的一部分,我需要知道每种问题类型的User总数。

当前,我正在使用python执行此求和,但是我想要一个更好,更有效的解决方案,该解决方案使用基础数据库和适当的功能(func.sum等)。

对数据库和当前解决方案的描述如下:

import datetime
from sqlalchemy import create_engine, Column, ForeignKey, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from itertools import groupby

Base = declarative_base()

class Answer(Base):
    __tablename__ = 'answer'
    question_id = Column(Integer, ForeignKey('question.id'), primary_key=True)
    user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
    question_answers = relationship('Question', back_populates='answers')
    user_answers = relationship('User', back_populates='answers')
    time_answered = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True, autoincrement=True)
    answers = relationship(Answer, back_populates='user_answers', order_by='Answer.time_answered.desc()', lazy='dynamic')

    @property
    def get_answer_totals(self):
        answer_totals = dict()
        sorted_answers = sorted(self.answers, key=lambda x: x.question_answers.type)
        for k, v in groupby(sorted_answers, lambda x: x.question_answers.type):
            answer_totals[k] = sum([answer.question_answers.value for answer in list(v)])
        return answer_totals

class Question(Base):
    __tablename__ = 'question'
    id = Column(Integer, primary_key=True, autoincrement=True)
    type = Column(Integer, nullable=False)
    value = Column(Integer, nullable=False)
    answers = relationship(Answer, back_populates='question_answers', order_by='Answer.time_answered.desc()', lazy='dynamic')

engine = create_engine('sqlite:///soq.db')
DBSession = sessionmaker(bind=engine)
session = DBSession()
Base.metadata.create_all(engine)

user_1 = User(id=1)
user_2 = User(id=2)
session.add_all([user_1, user_2])

question_1 = Question(id=1,type="A",value=50)
question_2 = Question(id=2,type="A",value=10)
question_3 = Question(id=3,type="B",value=20)
question_4 = Question(id=4,type="B",value=30)
question_5 = Question(id=5,type="C",value=10)
session.add_all([question_1, question_2, question_3, question_4, question_5])

user_1.answers.append(Answer(question_id=1,user_id=1))
user_1.answers.append(Answer(question_id=3,user_id=1))
user_1.answers.append(Answer(question_id=4,user_id=1))
print user_1.get_answer_totals

user_2.answers.append(Answer(question_id=1,user_id=2))
user_2.answers.append(Answer(question_id=2,user_id=2))
user_2.answers.append(Answer(question_id=5,user_id=2))
print user_2.get_answer_totals

从上面可以看出,get_answer_totals类中的(丑陋的)User函数首先对数据进行排序,然后对其进行分组,然后对其进行计数。

有人可以帮助我将此功能转换为等效的SQLAlchemy查询吗?

1 个答案:

答案 0 :(得分:0)

针对其他有相同问题的人的解决方案,

@property
def get_answer_totals2(self):
    return self.answers.join(Question, Question.id == Answer.question_id).add_column(Question.type).add_column(func.sum(Question.value)).group_by(Question.type).all()