在SQLAlchemy中从子查询生成布尔表达式

时间:2014-09-10 17:52:21

标签: python sql postgresql sqlalchemy

我有以下SQLAlchemy模型:

PENDING_STATE = 'pending'
COMPLETE_STATE = 'success'
ERROR_STATE = 'error'

class Assessment(db.Model):
    __tablename__ = 'assessments'

    id = db.Column(db.Integer, primary_key=True)
    state = db.Column(
        db.Enum(PENDING_STATE, COMPLETE_STATE, ERROR_STATE,
                name='assessment_state'),
        default=PENDING_STATE,
        nullable=False,
        index=True)

    test_results = db.relationship("TestResult")


class TestResult(db.Model):
    __tablename__ = 'test_results'

    name = db.Column(db.String, primary_key=True)
    state = db.Column(
        db.Enum(PENDING_STATE, COMPLETE_STATE, ERROR_STATE,
                name='test_result_state_state'),
        default=PENDING_STATE,
        nullable=False,
        index=True)

    assessment_id = db.Column(
        db.Integer,
        db.ForeignKey(
            'assessments.id', onupdate='CASCADE', ondelete='CASCADE'),
        primary_key=True)

我正在尝试实现逻辑,以便在其任何测试结果处于错误状态时将评估更新为错误状态,并在所有测试结果都处于成功状态时将评估更新为成功状态。 / p>

我可以像这样编写原始SQL:

SELECT 'error'
FROM assessments
WHERE assessments.state = 'error' OR 'error' IN (
    SELECT test_results.state
    FROM test_results
    WHERE test_results.assessment_id = 1);

但我不知道如何将其翻译成SQLAlchemy。我认为子查询会是这样的:

(select([test_results.state]).where(test_results.assessment_id == 1)).in_('error')

但是我无法找到任何方法来将查询结果与我在原始SQL中执行的文字进行比较。我发誓我必须遗漏一些东西,但我只是没有找到一种方法来编写返回布尔表达式的查询,我认为这基本上是我所反对的。只是简单的事情:

SELECT 'a' = 'b'

似乎没有出现在文档中。

有关如何在SQLAlchemy中表达此状态的任何想法?如果我看起来像是以愚蠢的方式解决这个问题,我也完全愿意重新思考我的架构。

谢谢!

2 个答案:

答案 0 :(得分:0)

下面的查询应该进行error检查。请记住,如果不是错误,则不会返回任何行。

q = (db.session.query(literal_column("'error'"))
     .select_from(Assessment)
     .filter(Assessment.id == sid)
     .filter(or_(
         Assessment.state == ERROR_STATE,
         Assessment.test_results.any(TestResult.state == ERROR_STATE),
     )))

如果您希望对success进行类似的检查,您可以找到是否有TestResult a success并取消布尔结果。

答案 1 :(得分:0)

我实际上最终使用postgres触发器执行此操作,这可能是处理状态更新的更好方法。因此,对于错误案例,我得到了:

sqlalchemy.event.listen(TestResult.__table__, 'after_create', sqlalchemy.DDL("""
CREATE OR REPLACE FUNCTION set_assessment_failure() RETURNS trigger AS $$
BEGIN
    UPDATE assessments
    SET state='error'
    WHERE id=NEW.assessment_id;
    RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';

CREATE TRIGGER assessment_failure
    AFTER INSERT OR UPDATE OF state ON test_results
    FOR EACH ROW
    WHEN (NEW.state = 'error')
    EXECUTE PROCEDURE set_assessment_failure();"""))

类似的成功'我计算测试结果数量与成功测试结果数量的情况。

尽管如此,我仍然可以通过van来回答我的问题!谢谢,我之前没有遇到任何关系。