将子查询转换为自连接
Convert Subquery to Self Join
SQL 的新手,我知道联接往往比子查询更快。我有以下 table,我当前的查询给出了我需要的结果,但我不能绕过使用自连接的类似查询,假设它是可能的。
Table
id scheduled_id action_id
------------ ------------ ------------
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 3 1
架构
create table ma (
id integer primary key,
scheduled_id integer,
action_id integer
);
insert into ma (
id,
scheduled_id,
action_id
)
values
(1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(4, 2, 1),
(5, 2, 2),
(6, 3, 1);
查询
select * from ma where action_id = 3
union all
select * from ma where scheduled_id not in (
select scheduled_id from ma
where action_id = 3)
结果
id scheduled_id action_id
------------ ------------ ------------
3 1 3
4 2 1
5 2 2
6 3 1
我的结果应该是 action_id 值为 3 的所有行加上 scheduled_ids 不具有 action_id 值 3 的所有行。
sqlfiddle 可以在 http://sqlfiddle.com/#!5/0ba51/3 找到。
谢谢。
我认为 JOIN 并不是您真正需要的。我会使用以下查询,它避免了 UNION :
SELECT m.*
FROM ma m
WHERE
m.action_id = 3
OR NOT EXISTS (
SELECT 1
FROM ma m1
WHERE
m1.scheduled_id = m.scheduled_id
AND m1.action_id = 3
)
在检查某物是否存在(或不存在)时,带有相关子查询的 NOT EXISTS 通常是最相关和最有效的方法。
My result should be all the scheduled_ids that have the value of 3 plus all the scheduled_ids and action_ids for those scheduled_ids that do not have a value of 3.
这不是您的查询所做的。这样做的查询是:
select ma.*
from ma
where exists (select 1
from ma ma2
where ma2.scheduled_id = ma.scheduled_id and
ma2.action_id = 3
);
虽然您可以使用自联接来执行此操作,但这很棘手,因为查询可能会导致重复。对于逻辑,我推荐 exists
或 in
。
此代码仅在您的 action_id 始终为 1、2、3、4 等并且从不跳过 3 时才有效。我只是想提供一个替代答案,以防添加概念max(action_id) 可能对你有用。
select ma.id
, ma.scheduled_id
, ma.action_id
, ma_max.max_action_id
from (
select scheduled_id
, max(action_id) as max_action_id
from ma
group by scheduled_id
) ma_max
join ma
on ma_max.scheduled_id = ma.scheduled_id
where (action_id = 3 or max_action_id < 3)
它几乎肯定不会像使用 "EXISTS" 的其他答案那样执行。我只是喜欢在 where (action_id = 3 or max_action_id < 3)
.
中如何将逻辑的复杂性降低到本质上易于阅读的一行
这个怎么样?虽然不是自我加入但比联合更快
select * from ma
where action_id = 3 or scheduled_id not in (
select scheduled_id from ma
where action_id = 3
)
您使用自联接查找的结果是:
SELECT DISTINCT t1.*
FROM ma t1
JOIN ma t2
ON t1.SCHEDULED_ID <> t2.SCHEDULED_ID --Satisfies 2nd query
WHERE t2.ACTION_ID = 3 --Satisfies 2nd query
OR t1.ACTION_ID = 3 --Satisfies 1st query
ORDER BY t1.ID
SELECT m1.*
FROM ma m1
INNER JOIN
(
SELECT *
FROM ma m2
WHERE m2.action_id = 3
) AS matbl
WHERE m1.action_id = 3
OR matbl.scheduled_id<>m1.scheduled_id
希望对您有所帮助。
SQL 的新手,我知道联接往往比子查询更快。我有以下 table,我当前的查询给出了我需要的结果,但我不能绕过使用自连接的类似查询,假设它是可能的。
Table
id scheduled_id action_id
------------ ------------ ------------
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 3 1
架构
create table ma (
id integer primary key,
scheduled_id integer,
action_id integer
);
insert into ma (
id,
scheduled_id,
action_id
)
values
(1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(4, 2, 1),
(5, 2, 2),
(6, 3, 1);
查询
select * from ma where action_id = 3
union all
select * from ma where scheduled_id not in (
select scheduled_id from ma
where action_id = 3)
结果
id scheduled_id action_id
------------ ------------ ------------
3 1 3
4 2 1
5 2 2
6 3 1
我的结果应该是 action_id 值为 3 的所有行加上 scheduled_ids 不具有 action_id 值 3 的所有行。
sqlfiddle 可以在 http://sqlfiddle.com/#!5/0ba51/3 找到。
谢谢。
我认为 JOIN 并不是您真正需要的。我会使用以下查询,它避免了 UNION :
SELECT m.*
FROM ma m
WHERE
m.action_id = 3
OR NOT EXISTS (
SELECT 1
FROM ma m1
WHERE
m1.scheduled_id = m.scheduled_id
AND m1.action_id = 3
)
在检查某物是否存在(或不存在)时,带有相关子查询的 NOT EXISTS 通常是最相关和最有效的方法。
My result should be all the scheduled_ids that have the value of 3 plus all the scheduled_ids and action_ids for those scheduled_ids that do not have a value of 3.
这不是您的查询所做的。这样做的查询是:
select ma.*
from ma
where exists (select 1
from ma ma2
where ma2.scheduled_id = ma.scheduled_id and
ma2.action_id = 3
);
虽然您可以使用自联接来执行此操作,但这很棘手,因为查询可能会导致重复。对于逻辑,我推荐 exists
或 in
。
此代码仅在您的 action_id 始终为 1、2、3、4 等并且从不跳过 3 时才有效。我只是想提供一个替代答案,以防添加概念max(action_id) 可能对你有用。
select ma.id
, ma.scheduled_id
, ma.action_id
, ma_max.max_action_id
from (
select scheduled_id
, max(action_id) as max_action_id
from ma
group by scheduled_id
) ma_max
join ma
on ma_max.scheduled_id = ma.scheduled_id
where (action_id = 3 or max_action_id < 3)
它几乎肯定不会像使用 "EXISTS" 的其他答案那样执行。我只是喜欢在 where (action_id = 3 or max_action_id < 3)
.
这个怎么样?虽然不是自我加入但比联合更快
select * from ma
where action_id = 3 or scheduled_id not in (
select scheduled_id from ma
where action_id = 3
)
您使用自联接查找的结果是:
SELECT DISTINCT t1.*
FROM ma t1
JOIN ma t2
ON t1.SCHEDULED_ID <> t2.SCHEDULED_ID --Satisfies 2nd query
WHERE t2.ACTION_ID = 3 --Satisfies 2nd query
OR t1.ACTION_ID = 3 --Satisfies 1st query
ORDER BY t1.ID
SELECT m1.*
FROM ma m1
INNER JOIN
(
SELECT *
FROM ma m2
WHERE m2.action_id = 3
) AS matbl
WHERE m1.action_id = 3
OR matbl.scheduled_id<>m1.scheduled_id
希望对您有所帮助。