Oracle 从多个表更新

Posted

技术标签:

【中文标题】Oracle 从多个表更新【英文标题】:Oracle update from multiple tables 【发布时间】:2015-04-28 22:30:42 【问题描述】:

我有一个包含两个事实表和几个维度表的星型模式。我想将其中一个事实更新为两个事实表中事实的总和。假设我有如下数据:

Fact1:
Val1|Dim1|Dim2|Dim3|RunNB
100 |1   |2   |3   |1
200 |1   |2   |4   |1
101 |1   |2   |3   |2 

Fact2:
Val2|Val3|Dim1|Dim2|Dim3|RunNB
100 |0   |1   |2   |3   |3
200 |0   |1   |2   |4   |3
101 |0   |1   |2   |3   |4

Run:
RunNB|Date
1    |20150423
2    |20150428
3    |20150423

我想用 Fact1.Val1 + Fact2.Val2 填充 Fact2.Val3,用于尺寸匹配的所有行,并且与运行关联的日期相同。

以下查询选择正确的数据:

select Fact1.Val1 + Fact2.Val2
from Fact1, Fact2, Run r1, Run r2
where Fact1.Dim1 = Fact2.Dim1 AND
      Fact1.Dim2 = Fact2.Dim2 AND
      Fact1.Dim3 = Fact3.Dim3 AND
      Fact1.RunNB = r1.RunNB AND
      r1.Date = '20150423' AND
      Fact2.RunNB = r2.RunNB AND
      r2.Date = '20150423';

我需要选择总和,然后用总和更新适当的 Fact2.Val3。我在构建更新语句时遇到问题。

我的理解是Oracle不支持:

update x
set y
FROM z
where q

我也试过了:

update (
  select ...
) set ...

语法,但我无法正常工作。我可以为此使用 MERGE 吗?任何帮助将不胜感激。

【问题讨论】:

这似乎是一个糟糕的数据模型。具有两个事实表的星型模式不是真正的星型模式。但是两个具有相同维度和相关事实的事实表呢?绝对臭。此外,如果您的事实表包含适当的仓库卷,您不希望在它们上运行更新语句(包括合并)。 同意。我试图做的任务没有意义。但是,由于各种遗留原因,我需要这样做。我不能改变数据模型,也不能改变要求。您对我如何实现这一点有任何想法吗? 【参考方案1】:

merge 语句适用于给定示例:

merge into (select * from fact2 
  where runnb in (select runnb from run where rDate = '20150423')) f2
using (  
  select dim1, dim2, dim3, run.runnb, val1 
    from fact1 join run on fact1.runnb = run.runnb and rDate = '20150423' ) f1
on (f1.dim1 = f2.dim1 and f1.dim2 = f2.dim2 and f1.dim3 = f2.dim3) 
when matched then update set f2.val3 = f1.val1 + f2.val2;

如果表 fact1 中的 dim1、dim2、dim3 一天的行数多于一行,则必须首先在 using 部分中对它们进行分组和求和, 否则可能会出现错误无法获得稳定的行集。 顺便说一句 - 我在表 run 中将 date 重命名为 rdate

【讨论】:

谢谢。当我实现这个时,我得到以下 Oracle 错误:Error report: SQL Error: ORA-30926: unable to get a stable set of rows in the source tables 30926. 00000 - "unable to get a stable set of rows in the source tables" *Cause: A stable set of rows could not be got because of large dml activity or a non-deterministic where clause. *Action: Remove any non-deterministic where clauses and reissue the dml. 我的真实数据集比我的示例中的大得多,但是两个 select 语句都返回相同数量的记录,没有欺骗。对这个问题有什么想法吗? 更新:我想我看到了 ORA-30926 错误的根本原因。由于数据的规范化存在一些问题,实际上存在一些欺骗(大约 160000 条记录中的 10 条)。我怀疑查询不会出现这些错误...谢谢。 正如我警告过的那样 - 此错误意味着对于某些行,fact1 中存在相同(dim1、dim2、dim3、日期)的重复项。这是SQLFiddle,我在其中重现了这种情况,您可以从小提琴中对您的数据运行查询以检查它。要使merge 正常运行,此查询不应返回任何行。我在fact1 中添加了一行,val1=201。现在merge(我也不知道)不知道它必须使用哪一行。解决方案是在内部查询中对数据进行分组,但我不知道你是否想要这个。或者消除欺骗。

以上是关于Oracle 从多个表更新的主要内容,如果未能解决你的问题,请参考以下文章

oracle 怎么理解update 表 set 字段1 = 值,字段2 = 值 where 字段3 = 值

为啥 oracle 不支持在单个查询中更新多个表?

oracle怎么用一个表的多个字段数据更新另一个表相应的字段中

Oracle MERGE语句

Oracle多表关联如何更新多个字段

oracle 如何实现对单个表批量更新