在Oracle 10g中使用Left Join删除

时间:2010-09-08 22:11:17

标签: oracle oracle10g

我有以下代码在MS SQL Server中正常工作:

delete grp
from grp
left join my_data
on grp.id1 = my_data.id1
and grp.id2 = my_data.id2
and grp.id3 = my_data.id3
and grp.id4 = my_data.id4
where my_data.id1 is NULL

基本上,我想删除grp中可以找到的所有匹配项,并且没有任何等价in my_data。遗憾的是,它在Oracle 10g中不起作用。我尝试使用左连接(+)的旧语法,但它也不起作用。像这样:

delete grp
from grp,
my_data
where grp.id1 = my_data.id1 (+)
and grp.id2 = my_data.id2 (+)
and grp.id3 = my_data.id3 (+)
and grp.id4 = my_data.id4 (+)
and my_data.id1 is NULL

如果我没有多个密钥,IN子句就可以工作,但我看不出如何将它与我的数据一起使用。那么,替代方案是什么?

5 个答案:

答案 0 :(得分:16)

如果您想确保删除内容不明确,可以将Vincent's solution更改为:

delete from grp where rowid in
    (
    select
         grp.rowid
    from
         grp left outer join my_data on
            grp.id1 = my_data.id1
        and grp.id2 = my_data.id2
        and grp.id3 = my_data.id3
        and grp.id4 = my_data.id4
    where
        my_data.id1 is NULL
    )

答案 1 :(得分:15)

表格和数据:

SQL> create table grp (id1 number null, id2 number null, id3 number null, id4 number null);    
Table created.

SQL> create table my_data (id1 number null, id2 number null, id3 number null, id4 number null);

Table created.

SQL> insert into grp values (1, 2, 3, 4);

1 row created.

SQL> insert into grp values (10, 20, 30, 40);

1 row created.

SQL> insert into grp values (1, 2, 30, 40);

1 row created.

SQL> insert into my_data values (1, 2, 3, 4);

1 row created.

SQL> commit;

Commit complete.

使用in注意如果子查询中的ID可以是null,请不要使用。 Not in的{​​{1}}永远不会返回true。

null

使用SQL> delete grp where (id1, id2, id3, id4) not in (select id1, id2, id3, id4 from my_data); 2 rows deleted. SQL> select * from grp; ID1 ID2 ID3 ID4 ---------- ---------- ---------- ---------- 1 2 3 4

exists

答案 2 :(得分:15)

Shannon's solution是要走的路:使用运算符NOT IN(或不是EXISTS)。

但是,您可以在Oracle中删除或更新连接,但是SYNhax与MS SQL Server不同:

SQL> DELETE FROM (SELECT grp.*
  2                  FROM grp
  3                  LEFT JOIN my_data ON grp.id1 = my_data.id1
  4                                   AND grp.id2 = my_data.id2
  5                                   AND grp.id3 = my_data.id3
  6                                   AND grp.id4 = my_data.id4
  7                 WHERE my_data.id1 IS NULL);

2 rows deleted

此外,如果语句无法访问哪个基行,Oracle将只允许您更新连接。特别是,如果某行可能在连接中出现两次,Oracle将不会冒更新或删除(该语句将失败)的风险。在这种情况下,删除只有在my_data(id1, id2, id3, id4).

上有UNIQUE约束时才有效

答案 3 :(得分:1)

文森特的答案https://stackoverflow.com/a/3675205根本不起作用,或者在Oracle 12c中不起作用。通过指定可以使用的最低或最高版本的Oracle,可以改善该答案。证明:

SELECT * FROM v$version where banner like 'Oracle%';
/*
Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
*/
create table a (id int);
create table b (id int);
insert into a select 1 from dual union select 2 from dual;
insert into b select 1 from dual union select 2 from dual union select 3 from dual;
select * from a right join b on b.id = a.id;
/*
1   1
2   2
null    3
*/
delete from (
  select b.*
  from b
  inner join a on a.id = b.id
)    
/*
Error at Command Line : 7 Column : 13
Error report -
SQL Error: ORA-01752: cannot delete from view without exactly one key-preserved table
01752. 00000 -  "cannot delete from view without exactly one key-preserved table"
*Cause:    The deleted table had
           - no key-preserved tables,
           - more than one key-preserved table, or
           - the key-preserved table was an unmerged view.
*Action:   Redefine the view or delete it from the underlying base tables.
*/

delete from b
where rowid in (
  select b.rowid
  from b
  inner join a on a.id = b.id
)
/*
2 rows deleted.
*/
select * from a right join b on b.id = a.id
/*
null  3
*/

drop table a;
drop table b;

最底线是,至少在12c中使用WHERE ROWID IN ()

答案 4 :(得分:0)

我无法添加评论,因为它需要50次重复,因此我在此处添加了答案。

我测试了Vincent从查询中删除的语法,该语法不能让您删除想要的内容,至少在所有删除联接案例中,这并不是常用的方法。

首先,我使用oracle默认用户scott创建一个表:

create table emp1 as select * from emp where sal<2000;

我想从emp中删除emp1中empno的记录(只是一个简单的测试),所以我从查询中使用了此删除:

delete from (select a.* from emp a join emp1 b on a.empno=b.empno);

无论表或连接顺序是什么,左连接还是内部连接,无论我在哪里使用子句,SQL都会删除emp1中的相应记录。

因此,我认为从查询中删除此内容无法让您从指定的表中删除。 对于这些情况,循环光标将是更好的方法。