Oracle 更新基于 2 个其他表的连接

Posted

技术标签:

【中文标题】Oracle 更新基于 2 个其他表的连接【英文标题】:Oracle Update based on join of 2 other tables 【发布时间】:2016-04-21 15:16:21 【问题描述】:

我需要更新一个巨大的表,超过 10 亿条记录(POS 数据),其中的键来自基于与第三个表的连接的表。我可以根据日期分解更新,因为这可以追溯到几年前。 当它们不一样时,我基本上需要用 dedup.retail_sku_key 替换表 edw.f_pos_daily 中的 f.retail_sku_key。 谢谢!

select  F.POS_KEY, f.retail_sku_key , dedup.retail_sku_key dedup_key 
from edw.f_pos_daily f,edw.d_retail_sku sku, edw.d_retail_sku_new dedup
where f.retail_sku_key = sku.retail_sku_key
and sku.retail_sku = dedup.retail_sku
and sku.mtd_item_number = dedup.mtd_item_number
and sku.retailer = dedup.retailer
and f.retail_sku_key <> dedup.retail_sku_key

【问题讨论】:

您可以尝试按照指定的日期使用 BULK COLLECT FORALL 更新。最好更新海量数据 您的问题是什么 - 如何进行相关更新?是一次更新还是根据日期范围分阶段更新?还有什么?如果您有足够的撤消空间,单次更新将是最有效的。 Alex,如果可能的话,我想一次性进行相关更新。我在 Exadata 上运行,空间不是问题。 【参考方案1】:

虽然可能存在 UPDATE 等效项,但我更喜欢在 SQL 语句驱动需要更新哪些行同时生成要更新的值时使用 MERGE。

那么,是这样的吗? (我假设 f.pos_key 是该 f_pos_daily 表上的唯一标识符。如果不是这种情况并且查询为相同的 f_pos_key 值返回多行,这将失败。)

MERGE INTO edw.f_pos_daily f_main
USING (
select f.pos_key -- this is for joining back to the rows that need to be updated...
     , dedup.retail_sku_key dedup_key -- ...and this is the value to update them with
  from edw.f_pos_daily f
     , edw.d_retail_sku sku
     , edw.d_retail_sku_new dedup
 where f.retail_sku_key = sku.retail_sku_key
   and sku.retail_sku = dedup.retail_sku
   and sku.mtd_item_number = dedup.mtd_item_number
   and sku.retailer = dedup.retailer
   and f.retail_sku_key <> dedup.retail_sku_key 
    ) qry
ON (f_main.pos_key = qry.pos_key)
WHEN MATCHED THEN
   UPDATE SET f_main.retail_sku_key = qry.dedup_key
;

如果您确实需要将其分解为单独的更新,您可以通过两种方式一分为二:

1) 在内部查询中隔离 f_pos_daily 中的分区(假设该表是由非 retail_sku_key 分区的)例如FROM edw.f_pos_daily PARTITION (p_some_partition_name) 并为每个分区运行一次上述语句

2) 生成要更新的行范围(再次使用 f_pos_key=unique 假设),例如,每行将更新 10% 的行:

SELECT MIN(f_pos_key) c0,
PERCENTILE_DISC(0.1) WITHIN GROUP (ORDER BY f_pos_key) p1,
PERCENTILE_DISC(0.2) WITHIN GROUP (ORDER BY f_pos_key) p2,
PERCENTILE_DISC(0.3) WITHIN GROUP (ORDER BY f_pos_key) p3,
PERCENTILE_DISC(0.4) WITHIN GROUP (ORDER BY f_pos_key) p4,
PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY f_pos_key) p5,
PERCENTILE_DISC(0.6) WITHIN GROUP (ORDER BY f_pos_key) p6,
PERCENTILE_DISC(0.7) WITHIN GROUP (ORDER BY f_pos_key) p7,
PERCENTILE_DISC(0.8) WITHIN GROUP (ORDER BY f_pos_key) p8,
PERCENTILE_DISC(0.9) WITHIN GROUP (ORDER BY f_pos_key) p9,
MAX(f_pos_key) c4
FROM edw.f_pos_daily;

如果值在 0 到 1000 之间(以及一些未知的行数),这将为您提供如下输出:

P0  P1  P2  P3  P4  P5  P6  P7  P8  P9  P10
0   104 183 319 402 512 607 723 810 914 1000

从这里你只需要在子查询中包含另一个条件就可以了

AND f.pos_key BETWEEN 0 AND 104

在第一次运行时

AND f.pos_key BETWEEN 105 AND 183

第二次运行,以此类推。

【讨论】:

以上是关于Oracle 更新基于 2 个其他表的连接的主要内容,如果未能解决你的问题,请参考以下文章

oracle左连接查询和右连接查询随便举个例子谢谢!

PL/SQ连接oracle,L 新建表的时候, virtual那一列是啥意思

Oracle - 更新连接 - 非键保留表

Oracle - 更新连接 - 非键保留表

Oracle左连接

在其他两个表的列上连接一列的最佳方法