sql - 删除连接到另一表 SQL 的一个表中的记录

标签 sql oracle sql-delete

我有两个表,一个包含 212,000 条记录(已弃用的记录),另一个包含 10,500,000 条记录

我想在 id 和 version_number 字段上连接两个表,因为两个表都有这些字段。我希望从连接表中删除匹配的记录(来自连接表),即从 10,500,000 条记录中删除所有 212,000 条记录

我想知道使用 Oracle SQL 实现此目的的最佳方法是什么?我见过 示例中,使用单个字段使用内连接,并使用删除语句从表 2 中删除表 1,但没有看到使用两个字段的内连接(在连接中)。

在删除记录之前使用外部联接是否有意义?我想这可以帮助我跟踪已删除的内容(如果可能的话)

最佳答案

除了检查将有多少行之外,您不需要使用OUTER JOIN。将不会被删除。

此类查询的示例如下(我使用答案末尾提供的生成的测试数据)

with del as (
select delta.id, delta.version,
decode(big.id,null,0,1) is_deleted
from delta
left outer join big 
on delta.id = big.id and delta.version = big.version
)
select is_deleted, count(*) cnt, max(id||'.'||version) eg_id_vers
from del
group by is_deleted;

IS_DELETED        CNT  EG_ID_VERS                                                                   
---------- ---------- ----------
         1      20000 99995.0   
         0         20 100100.0   

根据您的数据大小,您应该在两个表上使用带有全表扫描HASH JOIN以获得可接受的性能。

基本上有两种选择如何进行删除

可更新的连接 View

请注意,在这种情况下,您的小表必须在ID、VERSION(或主键)上有唯一索引

create unique index delta_idx on delta(id,version);

相反,BIG 表应该没有这样的约束。这很重要,因为它清楚地表明您的大表是连接 View 中唯一一个保留键的表

由于独特的约束,简单地将连接放入小表无法复制大表中的行

参见here有关更新联接 View 的更多信息

delete from 
(
select delta.id, delta.version, big.id big_id, big.version
from big 
join delta 
on delta.id = big.id and delta.version = big.version
)

上面的删除BIG表中删除行,因为这是唯一保留键的表(请参阅上面的讨论)

此 DML 导致 HASH JOIN

使用 EXISTS 删除

如果您的小表没有主键(即它可以包含具有相同 ID 和 VERSION 的重复行),您必须回退 other answer 中提出的解决方案.

DELETE FROM big 
    WHERE EXISTS (SELECT null
                  FROM delta
                  WHERE delta.id = big.id and delta.version = big.version
                 ) 

不需要任何索引,并且您应该期望使用HASH JOIN RIGHT SEMI执行计划,这意味着两种方法并没有真正的不同。

测试示例数据

create table big as
select 
trunc(rownum/10) id, mod(rownum,10) version,
lpad('x',10,'Y') pad
from dual connect by level <= 1000000;

/* the DELTA table has 50 times less rows,
allow some rows out of range of the BIG table - those rows will not be deleted **/
drop table delta;
create table delta as
select 
trunc(rownum*50/10) id, mod(rownum*50,10) version
from dual connect by level <= 1001000/50;

create unique index delta_idx on delta(id,version);

关于sql - 删除连接到另一表 SQL 的一个表中的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59911501/

相关文章:

mysql - 其他函数,如 FIND_IN_SET,它返回逗号分隔列表中可用的字符串数量

mysql - 当角色完全不同时,将用户登录名和密码存储在数据库中的方法

sql - 在数据库中创建表时出错

php - 删除具有特定字段的所有条目

Mysql 5.5/phpmyadmin 简单查询之谜

sql - BigQuery 根据(Array CONTAINED IN Array)条件连接 2 个表

mysql - 如何在 MySQL 中通过分组连接两个表?

sql - 对组的子组应用 COUNT 函数

Oracle SQL Developer (4.1.1) Mac OSX 安装问题 (El Capitan)

mysql - 如果行存在于 MySQL 的另一个表中,则从一个表中删除行