简体   繁体   English

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

[英]Generating Boolean Expressions from Subqueries in SQLAlchemy

I have the following SQLAlchemy models: 我有以下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)

And I am trying to implement logic to update an assessment to the error state if any of its test results are in the error state and update the assessment to the success state if all of its test results are in the success state. 而且,我正在尝试实现一种逻辑,如果其测试结果中的任何一个处于错误状态,则将评估更新为错误状态;如果其所有测试结果都为成功状态,则将评估更新为成功状态。

I can write raw SQL like this: 我可以这样写原始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);

But I don't know how to translate that into SQLAlchemy. 但是我不知道如何将其转换为SQLAlchemy。 I'd think that subquery would be something like: 我认为子查询应该是这样的:

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

but I can't find any way to compare query results against literals like I'm doing in the raw SQL. 但是我找不到像在原始SQL中一样将查询结果与文字进行比较的任何方法。 I swear I must be missing something, but I'm just not seeing a way to write queries which return boolean expressions, which I think is fundamentally what I'm butting up against. 我发誓我一定会错过一些东西,但是我只是没有看到一种写返回布尔表达式的查询的方法,我认为这基本上是我所要面对的。 Just something as simple as: 就像这样简单:

SELECT 'a' = 'b'

Seems to be absent from the documentation. 似乎在文档中没有。

Any ideas on how to express this state change in SQLAlchemy? 关于如何在SQLAlchemy中表达这种状态变化的任何想法? I'd also be perfectly open to rethinking my schemas if it looks like I'm going about this in a silly way. 如果看起来我在以愚蠢的方式进行此操作,我也非常愿意重新考虑自己的模式。

Thanks! 谢谢!

Query below should do it for error check. 下面的查询应进行error检查。 Keep in mind that no rows will be returned in case it is not an eror. 请记住,如果不是错误,将不返回任何行。

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),
     )))

If you wish to do similar check for success , you could find if there is any TestResult which is not a success and negate boolean result. 如果你希望做类似的检查success ,你会发现,如果有任何TestResult这是不是一个success和否定布尔结果。

I actually ended up doing this with postgres triggers, which is probably the better way to handle state updates. 实际上,我最终使用postgres触发器完成了此操作,这可能是处理状态更新的更好方法。 So for the error case, I've got: 因此对于错误情况,我有:

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();"""))

And something similar for the 'success' case where I count the number of test results vs the number of successful test results. 对于“成功”情况,我计算测试结果的数量与成功测试结果的数量类似。

Credit to van for answering my question as I asked it, though! 不过,请感谢van回答了我提出的问题! Thanks, I hadn't bumped into relationship.any before. 谢谢,我以前从未接触过关系。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM