0

在我的应用仅支持PostgreSQL之前,我需要添加对ORACLE XE的支持。下面有在PostgreSQL中工作的SQLAlchemy请求:

parent = aliased(Task)
sub_qry = self.session.query(parent.id) \
    .filter(and_(
        parent.id == Task.parent_id,
        parent.task_status_id.in_([ETaskStatus.SUCCESSED.value, ETaskStatus.FAILED.value])
    )) \
    .subquery()
task = self.session.query(Task).with_for_update() \
    .filter_by(priority=priority.value, task_status_id=ETaskStatus.IN_QUEUE.value) \
    .filter(or_(
        Task.parent_id.is_(None),
        Task.parent_id.in_(sub_qry)
    )) \
    .order_by(Task.created_at) \
    .first()

如果任务没有父任务或父任务处于SUCCESSEEDFAILED状态(简而言之,如果父任务已被处理),则此请求选择具有IN_QUEUE状态的任务。该请求还会锁定找到的行以更改其状态,直到其他工作人员没有接管相同的任务。但是,此请求在ORACLE XE 中不起作用,它失败并出现错误:

sqlalchemy.exc.DatabaseError: (cx_Oracle.DatabaseError) ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.
[SQL: SELECT tasks_id, tasks_parent_id, tasks_priority, tasks_command_id, tasks_target, tasks_task_status_id, tasks_created_at, tasks_created_by 
FROM (SELECT tasks.id AS tasks_id, tasks.parent_id AS tasks_parent_id, tasks.priority AS tasks_priority, tasks.command_id AS tasks_command_id, tasks.target AS tasks_target, tasks.task_status_id AS tasks_task_status_id, tasks.created_at AS tasks_created_at, tasks.created_by AS tasks_created_by 
FROM tasks 
WHERE tasks.priority = :priority_1 AND tasks.task_status_id = :task_status_id_1 AND (tasks.parent_id IS NULL OR tasks.parent_id IN (SELECT tasks_1.id 
FROM tasks tasks_1 
WHERE tasks_1.id = tasks.parent_id AND tasks_1.task_status_id IN (:task_status_id_2, :task_status_id_3))) ORDER BY tasks.created_at) 
WHERE ROWNUM <= :param_1 FOR UPDATE]
[parameters: {'priority_1': 1, 'task_status_id_1': 0, 'task_status_id_2': 2, 'task_status_id_3': 3, 'param_1': 1}]
(Background on this error at: http://sqlalche.me/e/13/4xp6)

我在阅读 StackOverflow 上的类似问题时遇到了问题,但我不知道如何绕过它。我也尝试过更改请求:

task = self.session.query(Task).with_for_update() \
    .join(parent, Task.parent_id == parent.id) \
    .filter_by(priority=priority.value, task_status_id=ETaskStatus.IN_QUEUE.value) \
    .filter(or_(
        Task.parent_id.is_(None),
        parent.task_status_id.in_([ETaskStatus.SUCCESSED.value, ETaskStatus.FAILED.value])
    )) \
    .order_by(Task.created_at) \
    .first()

但似乎它没有起到任何作用。

如何通过ORACLE XE v.18.4.0的这个请求?

4

0 回答 0