SQL 删除不在另一个 table 中的行
SQL delete rows not in another table
我正在寻找一种好的 SQL 方法(Oracle 数据库)来满足下一个要求:
- 删除 Table A 中不存在于 Table B.[=46= 中的行]
- 两个 table 具有相同的结构
- 有些字段是 可为空的
- 列和行的数量很大(要比较更多的 10 万行和 20-30 列)
- 每一行的每个字段都需要比较 Table A 与 table B.
- 这样的要求是由于一个过程必须每天 运行 因为变化将来自 Table B.
换句话说:Table A 减 Table B => 从 Table A 中删除记录
delete from Table A
where (field1, field2, field3) in
(select field1, field2, field3
from Table A
minus
select field1, field2, field3
from Table B);
非常重要的一点是,MINUS 在 DELETE 子句中失败,因为没有考虑可空字段上的空值( oracle 的未知结果,然后没有匹配项)。
我也尝试 EXISTS 并成功,但我必须使用 NVL 函数用虚拟值替换空值,我不想要它,因为我不能保证NVL 中替换的值不会作为字段中的有效值出现。
有人知道完成这样的事情的方法吗?请记住 performance 和 nullable 字段为 "a must".
永远感谢
使用左外连接并在 where 子句中测试 null
删除一个
从一个
a.x = b.x 上的左外连接 b
其中 b.x 为空
对大量记录使用批量操作。性能方面它会更快。
并在两个 table 之间使用联接来获取要删除的行。可为空的列可以与一些默认值进行比较。
另外,如果你想让TableA和TableB相似,你为什么不截断tableA然后从tableb插入数据
您是否考虑过 ORALCE SQL MERGE
语句?
decode
找到相同点(即使两个值都为空):
decode( field1, field2, 1, 0 ) = 1
要删除表 1 中未在表 2 中找到的行:
delete table1 t
where t.rowid in (select t1.rowid
from table1 t1
left outer join table2 t2
on decode(t1.field1, t2.field1, 1, 0) = 1
and decode(t1.field2, t2.field2, 1, 0) = 1
and decode(t1.field3, t2.field3, 1, 0) = 1
/* ... */
where t2.rowid is null /* no matching row found */
)
使用现有索引
...
left outer join table2 t2
on (t1.index_field1=t2.index_field1 or
t1.index_field1 is null and t2.index_field1 is null)
and ...
假设您在每个 table 上可用相同的 PK 字段...(拥有 PK 或其他一些唯一密钥对此至关重要。)
create table table_a (id number, name varchar2(25), dob date);
insert into table_a values (1, 'bob', to_date('01-01-1978','MM-DD-YYYY'));
insert into table_a values (2, 'steve', null);
insert into table_a values (3, 'joe', to_date('05-22-1989','MM-DD-YYYY'));
insert into table_a values (4, null, null);
insert into table_a values (5, 'susan', to_date('08-08-2005','MM-DD-YYYY'));
insert into table_a values (6, 'juan', to_date('11-17-2001', 'MM-DD-YYYY'));
create table table_b (id number, name varchar2(25), dob date);
insert into table_b values (1, 'bob', to_date('01-01-1978','MM-DD-YYYY'));
insert into table_b values (2, 'steve',to_date('10-14-1992','MM-DD-YYYY'));
insert into table_b values (3, null, to_date('05-22-1989','MM-DD-YYYY'));
insert into table_b values (4, 'mary', to_date('12-08-2012','MM-DD-YYYY'));
insert into table_b values (5, null, null);
commit;
-- confirm minus is working
select id, name, dob
from table_a
minus
select id, name, dob
from table_b;
-- from the minus, re-query to just get the key, then delete by key
delete table_a where id in (
select id from (
select id, name, dob
from table_a
minus
select id, name, dob
from table_b)
);
commit;
select * from table_a;
但是,如果在某个时间点,tableA 将被重置为与 tableB 相同,为什么不像另一个答案所建议的那样,截断 tableA select 全部来自 tableB.
100K 并不大。我可以在不到 1 秒的时间内将 ~100K 截断并插入我的笔记本电脑实例。
> DELETE FROM purchase WHERE clientcode NOT IN (
> SELECT clientcode FROM client );
这将从购买 table 中删除客户代码不在客户 table 中的行。购买客户代码table引用客户table的客户代码。
DELETE FROM TABLE1 WHERE FIELD1 NOT IN (SELECT CLIENT1 FROM TABLE2);
我正在寻找一种好的 SQL 方法(Oracle 数据库)来满足下一个要求:
- 删除 Table A 中不存在于 Table B.[=46= 中的行]
- 两个 table 具有相同的结构
- 有些字段是 可为空的
- 列和行的数量很大(要比较更多的 10 万行和 20-30 列)
- 每一行的每个字段都需要比较 Table A 与 table B.
- 这样的要求是由于一个过程必须每天 运行 因为变化将来自 Table B.
换句话说:Table A 减 Table B => 从 Table A 中删除记录
delete from Table A
where (field1, field2, field3) in
(select field1, field2, field3
from Table A
minus
select field1, field2, field3
from Table B);
非常重要的一点是,MINUS 在 DELETE 子句中失败,因为没有考虑可空字段上的空值( oracle 的未知结果,然后没有匹配项)。
我也尝试 EXISTS 并成功,但我必须使用 NVL 函数用虚拟值替换空值,我不想要它,因为我不能保证NVL 中替换的值不会作为字段中的有效值出现。
有人知道完成这样的事情的方法吗?请记住 performance 和 nullable 字段为 "a must".
永远感谢
使用左外连接并在 where 子句中测试 null
删除一个 从一个 a.x = b.x 上的左外连接 b 其中 b.x 为空
对大量记录使用批量操作。性能方面它会更快。
并在两个 table 之间使用联接来获取要删除的行。可为空的列可以与一些默认值进行比较。
另外,如果你想让TableA和TableB相似,你为什么不截断tableA然后从tableb插入数据
您是否考虑过 ORALCE SQL MERGE
语句?
decode
找到相同点(即使两个值都为空):
decode( field1, field2, 1, 0 ) = 1
要删除表 1 中未在表 2 中找到的行:
delete table1 t
where t.rowid in (select t1.rowid
from table1 t1
left outer join table2 t2
on decode(t1.field1, t2.field1, 1, 0) = 1
and decode(t1.field2, t2.field2, 1, 0) = 1
and decode(t1.field3, t2.field3, 1, 0) = 1
/* ... */
where t2.rowid is null /* no matching row found */
)
使用现有索引
...
left outer join table2 t2
on (t1.index_field1=t2.index_field1 or
t1.index_field1 is null and t2.index_field1 is null)
and ...
假设您在每个 table 上可用相同的 PK 字段...(拥有 PK 或其他一些唯一密钥对此至关重要。)
create table table_a (id number, name varchar2(25), dob date);
insert into table_a values (1, 'bob', to_date('01-01-1978','MM-DD-YYYY'));
insert into table_a values (2, 'steve', null);
insert into table_a values (3, 'joe', to_date('05-22-1989','MM-DD-YYYY'));
insert into table_a values (4, null, null);
insert into table_a values (5, 'susan', to_date('08-08-2005','MM-DD-YYYY'));
insert into table_a values (6, 'juan', to_date('11-17-2001', 'MM-DD-YYYY'));
create table table_b (id number, name varchar2(25), dob date);
insert into table_b values (1, 'bob', to_date('01-01-1978','MM-DD-YYYY'));
insert into table_b values (2, 'steve',to_date('10-14-1992','MM-DD-YYYY'));
insert into table_b values (3, null, to_date('05-22-1989','MM-DD-YYYY'));
insert into table_b values (4, 'mary', to_date('12-08-2012','MM-DD-YYYY'));
insert into table_b values (5, null, null);
commit;
-- confirm minus is working
select id, name, dob
from table_a
minus
select id, name, dob
from table_b;
-- from the minus, re-query to just get the key, then delete by key
delete table_a where id in (
select id from (
select id, name, dob
from table_a
minus
select id, name, dob
from table_b)
);
commit;
select * from table_a;
但是,如果在某个时间点,tableA 将被重置为与 tableB 相同,为什么不像另一个答案所建议的那样,截断 tableA select 全部来自 tableB.
100K 并不大。我可以在不到 1 秒的时间内将 ~100K 截断并插入我的笔记本电脑实例。
> DELETE FROM purchase WHERE clientcode NOT IN (
> SELECT clientcode FROM client );
这将从购买 table 中删除客户代码不在客户 table 中的行。购买客户代码table引用客户table的客户代码。
DELETE FROM TABLE1 WHERE FIELD1 NOT IN (SELECT CLIENT1 FROM TABLE2);