我在任务和操作之间有关系。我想在没有操作的情况下选择手动任务,或者选择一个动作!='取消'进行上一次操作。
实施例
tasks table :
-------------
|id | state |
| 3 |auto |
| 5 |manual |
| 6 |manual |
| 2 |manual |
| 8 |manual |
operations table :
----------------------------------
|id | action | task_id | time |
| 1 | processed | 8 | 8:00 |
| 2 | cancelled | 8 | 9:00 |
| 3 | processed | 6 | 8:00 |
| 4 | processed | 2 | 8:00 |
| 5 | cancelled | 2 | 7:00 |
result : tasks 5,6,2
以下是我设法做的事情:
SELECT tasks.*
WHERE tasks.id NOT IN(
SELECT operations.task_id)
OR tasks.id IN
SELECT operations.task_id
WHERE action!=cancelled
.....
.....
ORDER BY time DESC
我不确定如何结束此查询。此外,它还将对任务中的每一行执行2次查询。
答案 0 :(得分:1)
嗯。我在想distinct on
获取有关操作的信息:
select distinct on (task_id)
from operations o
order by task_id, time desc;
然后left join
来完成任务:
select t.*
from tasks t left join
(select distinct on (task_id)
from operations o
order by task_id, time desc
) o
on o.task_id = t.task_id
where o.task_id is null or o.action <> 'cancelled';
答案 1 :(得分:1)
让我们说这是你的架构:
CREATE TABLE tasks (
id int unique,
state text
);
CREATE TABLE operations (
id serial,
action text,
task_id int REFERENCES tasks (id),
time text
);
INSERT INTO tasks (id, state) VALUES (3, 'auto');
INSERT INTO tasks (id, state) VALUES (5, 'manual');
INSERT INTO tasks (id, state) VALUES (6, 'manual');
INSERT INTO tasks (id, state) VALUES (2, 'manual');
INSERT INTO tasks (id, state) VALUES (8, 'manual');
INSERT INTO operations (action, task_id, time) VALUES ('processed', 8, '8:00');
INSERT INTO operations (action, task_id, time) VALUES ('cancelled', 8, '9:00');
INSERT INTO operations (action, task_id, time) VALUES ('processed', 6, '8:00');
INSERT INTO operations (action, task_id, time) VALUES ('processed', 2, '8:00');
INSERT INTO operations (action, task_id, time) VALUES ('cancelled', 2, '7:00');
这将是您的查询:
SELECT *
FROM tasks
WHERE state = 'manual' AND
(
NOT EXISTS (SELECT 1 FROM operations WHERE task_id = tasks.id LIMIT 1)
OR
(SELECT action FROM operations WHERE task_id = tasks.id ORDER BY id DESC LIMIT 1) != 'cancelled'
)
;
输出:
id | state
----+--------
5 | manual
6 | manual
(2 rows)
答案 2 :(得分:1)
如果您愿意依赖&#39;取消&#39;是任务执行的最后一次操作 - 即,如果取消将任务置于终端状态,那么就不必专注于取消 last 操作,只取决于是否取消。
在这种情况下,您可以使用相当简单的外部联接来查找结果:
select t.*
from
tasks t
left outer join operations o
on t.id = o.task_id
and o.action = 'cancelled'
where t.state = 'manual' and o.id is null;
特别注意过滤条件中的o.id is null
- 假设&#39; id&#39;表是operations
的主键,只有在operations
的行不满足tasks
的给定行的连接条件时,它才能在连接结果中为空。也就是说,仅适用于没有关联&#39;取消&#39;操作(包括那些根本没有操作的操作)。
另一方面,如果您需要包含已取消&#39;操作,但 last 操作不同,那么您可以使用窗口函数来帮助您识别每个任务的最后一个操作:
select t.*
from
tasks t
left outer join (
select
operations.*,
max(operations.time) over (partition by task_id) as last_time
from operations
) o
on t.id = o.task_id
and o.action = 'cancelled'
and o.time = o.last_time
where t.state = 'manual' and o.id is null;
此处必须o.time = o.last_time
出现在连接条件中,而不是内联视图的过滤条件(它将是非法的)或外部查询的过滤条件(它将出错的地方)效果)。