将子查询转换为自我联接

时间:2019-02-14 20:13:23

标签: sql sqlite subquery self-join

SQL的新手,我知道联接往往比子查询快。我有下表,我的当前查询为我提供了我需要的结果,但我想如果可能的话,我无法绕过使用自联接的类似查询。

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的所有行加上那些action_id值为3的chedched_id的所有行。

sqlfiddle可能位于http://sqlfiddle.com/#!5/0ba51/3

谢谢。

6 个答案:

答案 0 :(得分:1)

我认为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通常是最相关且最有效的方法。

答案 1 :(得分:1)

这个怎么样?虽然不是自加入,但比联合快

select * from ma
where action_id = 3 or scheduled_id not in (
    select scheduled_id from ma
    where action_id = 3
  )

答案 2 :(得分:1)

使用自我联接的结果是:

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

答案 3 :(得分:1)

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

希望这会有所帮助。

答案 4 :(得分:0)

  

我的结果应该是值为3的所有schedule_id加上那些值为3的schedule_id和action_id。

这不是您的查询所做的。这样做的查询是:

select ma.*
from ma
where exists (select 1
              from ma ma2
              where ma2.scheduled_id = ma.scheduled_id and
                    ma2.action_id = 3
             );

尽管您可以使用自连接进行此操作,但这很棘手,因为查询可能导致重复。对于逻辑,我建议使用existsin

答案 5 :(得分:0)

仅当您的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)中的一条简单易读的行。