Sql 选择“按最后一个关系”或“无关系”
我有一个任务和操作之间的关系。我想选择不带操作或带操作的手动任务!='上次操作已取消 范例Sql 选择“按最后一个关系”或“无关系”,sql,postgresql,Sql,Postgresql,我有一个任务和操作之间的关系。我想选择不带操作或带操作的手动任务!='上次操作已取消 范例 tasks table : ------------- |id | state | | 3 |auto | | 5 |manual | | 6 |manual | | 2 |manual | | 8 |manual | operations table : ---------------------------------- |id | action | task_id | time | |
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次操作查询。Hmmm。我正在考虑获取有关操作的信息:
select distinct on (task_id)
from operations o
order by task_id, time desc;
然后左连接以获取任务:
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';
嗯。我正在考虑获取有关操作的信息:
select distinct on (task_id)
from operations o
order by task_id, time desc;
然后左连接以获取任务:
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';
假设这是您的模式:
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)
假设这是您的模式:
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)
如果您愿意依赖于“取消”是对任务执行的最后一个操作(如果执行了),也就是说,如果取消将任务置于终端状态,则无需关注取消是最后一个操作,只需关注是否有取消即可 在这种情况下,可以使用相当简单的外部联接来查找结果:
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在筛选条件中为空-假设“id”是表操作的主键,则只有在没有操作行满足给定任务行的联接条件的情况下,它才能在联接结果中为空。也就是说,仅适用于没有关联“已取消”操作的任务,包括那些根本没有操作的任务
另一方面,如果您需要包括具有“已取消”操作但最后一个操作不同的任务,则可以使用窗口功能帮助您识别每个任务的最后一个操作:
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_时间必须出现在连接条件中,不是内联视图的过滤条件,它将是非法的,也不是外部查询的过滤条件,它将产生错误的效果。如果您愿意相信“取消”是对任务执行的最后一个操作(如果执行了),也就是说,如果取消将任务置于终端状态,然后不需要关注取消是最后一个操作,只需要关注是否有取消 在这种情况下,可以使用相当简单的外部联接来查找结果:
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在筛选条件中为空-假设“id”是表操作的主键,则只有在没有操作行满足给定任务行的联接条件的情况下,它才能在联接结果中为空。也就是说,仅适用于没有关联“已取消”操作的任务,包括那些根本没有操作的任务
另一方面,如果您需要包括具有“已取消”操作但最后一个操作不同的任务,则可以使用窗口功能帮助您识别每个任务的最后一个操作:
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_时间必须出现在联接条件中,而不是内联视图的过滤条件(如果该时间不合法)或外部查询的过滤条件(如果该时间会产生错误的效果)。您是否愿意将取消作为每个具有任何此类操作的任务的最后一个操作?是,我不想做手术,或者取消上次手术。这不是我要的。换句话说,如果给定任务有“取消”操作,该任务是否会有后续操作?您是否愿意相信取消是每个有任何此类操作的任务的最后一个操作?是的,我不想要操作,或取消最后一个操作。这不是我要问的。换句话说,如果给定任务有一个“已取消”的操作,该任务是否会有任何后续操作?distinct查询是否只返回最后一个操作?@Syl。它返回每个任务的最后一个操作。为此,distinct on通常比row_number具有更好的性能。distinct查询是否只返回最后一个操作?@Syl。它返回每个任务的最后一个操作。为此,distinct on通常比row_number具有更好的性能。