我有以下代码在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
子句就可以工作,但我看不出如何将它与我的数据一起使用。那么,替代方案是什么?
答案 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).
答案 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中的相应记录。
因此,我认为从查询中删除此内容无法让您从指定的表中删除。 对于这些情况,循环光标将是更好的方法。