在我的应用仅支持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()
如果任务没有父任务或父任务处于SUCCESSEED或FAILED状态(简而言之,如果父任务已被处理),则此请求选择具有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的这个请求?