【问题标题】:ORACLE SQL: correlated update issueORACLE SQL:相关更新问题
【发布时间】:2014-04-16 08:59:16
【问题描述】:

大家好,我在 oracle 的相关更新方面遇到了这种问题。

考虑我有一张表params

id_s    id_p    value    desc
-----------------------------------------------
10064     9      aaa     r
10064     8      bbb     t
10064     4      ccc     t
10064     4      ttt     y
11119     9      ddd     f
11119     8      eee     g 
11119     4      fff     b
11119     4      kkk     x

所以我想更新 params 以获得以下信息

id_s    id_p    value    desc
-----------------------------------------------
10064     9      aaa     r
10064     8      bbb     t
10064     4      ccc     t
10064     4      ttt     y
11119     9      aaa     r
11119     8      bbb     t 
11119     4      ccc     t
11119     4      ttt     y

我这样写更新

update params p1
   set (p1.value, p1.desc) = (
           select p2.value
                , p2.desc 
             from params p2
            where p2.id_s = 10064
              and p2.id_p = p1.id_p
       )
 where p1.id_s = 11119
     ;

执行返回错误'ORA01427:单行子查询返回多于一行'

我怎样才能使这个更新工作?

【问题讨论】:

  • 您的查询应该没问题 - 您是否在运行子查询时将 p1.id_p 替换为它的一些值?
  • @collapsar 是的,我试过了。只有一个值而不是 p1.id_p 更新有效,但是当 p1.id_p 有多个值时,返回错误“ORA01427:Single-row subquery return more than one row”。
  • 根据您的明确条件,您如何确定哪些主记录和从记录匹配?例如。 id_p = 4 你有 2 个! = 2 个将id_s = 10064 与id_s = 11119 的记录相关联的选项。请注意,如果相关性的选择无关紧要,则必须确保源集和目标集的基数相同。另请注意,这种不变性通常是数据模型损坏的标志。

标签: oracle sql-update correlated


【解决方案1】:

您必须在子查询中添加附加条件:

update params p1
    set (p1.value, p1.desc) = (
            select p2.value
                 , p2.desc 
              from params p2
             where p2.id_s = 10064
               and p2.id_p = p1.id_p
               and p1.id_s = 11119
        )
  where p1.id_s = 11119
      ;

编辑: 操作规范的更新使事情变得更加复杂,这实际上相当于部分 pk 更新(就给出的表格摘录而言,它们的列是完整的)。

一种可能的解决方案实现了以下基本思想:id_pid_s 的主组合的结果集与相同列的从组合的结果集按照 2 排序中的排名进行配对。排序只是根据列 valuedesc 对结果集的排序,但当然任何其他排序也可以(请注意,特别是 2 个 不同的 排序是可行的)。

然后将所述配对与更新结果集相关联。

在oracle sql中:

update params p1
   set (p1.value, p1.desc) = (
           select emb.value
                , emb.desc 
             from (
                    select p2.value
                         , p2.desc
                         , p2.id_p
                         , rownum     rn 
                      from params p2
                     where p2.id_s = 10064
                  order by p2.value
                         , p2.desc
                  ) emb
             join (
                    select pm.value
                         , pm.desc
                         , pm.id_p
                         , rownum     rn 
                      from params pm
                     where pm.id_s = 11119
                  order by pm.value
                         , pm.desc
                  ) emb_master
                       ON (     emb_master.id_p = emb.id_p
                            AND emb_master.rn   = emb.rn   )
            where p1.id_s = 11119
              and emb_master.id_p     = p1.id_p
              and emb_master.value    = p1.value
              and emb_master.desc     = p1.desc
       )
 where p1.id_s = 11119
     ;

这个方案的可行性取决于假设结果集以元组的每个值为模(id_pid_s)具有相同的基数。如果你不这样做,更新将是不完整的。

根据给出的摘录在 ora 11g2 上进行了测试。

【讨论】:

  • 问题是我的子查询无论如何都会返回多行,无论有没有你建议的添加,我都得到了 ora-01427,我认为'and p2.id_p = p1.id_p' 行应该有帮助但它没有。
  • 您应该再次检查作为独立查询发出的子查询是否产生超过 1 行。我根据您问题的表格摘录针对 ora 11g2 测试了这个版本,它按预期工作。
  • 你是对的朋友,我刚刚编辑了我的问题,更正了表格中的可能值。例如,id_p 可以有不止一行具有相同的值
  • 这正是我需要的先生。非常感谢您的深入解释。
【解决方案2】:

当返回多于一行时,您没有指定要执行的操作。您可以使用rownum = 1 选择任意行:

update params p1
   set (p1.value, p1.desc) = (
           select p2.value, p2.desc 
           from params p2
           where p2.id_s = 10064 and p2.id_p = p1.id_p and rownum = 1
       )
where p1.id_s = 11119;

【讨论】:

  • 我刚刚编辑了我的问题,更正了表格中的可能值。例如,具有相同值的 id_p 可以有不止一行。我只是对 rownum 感到困惑,在这种情况下会有所帮助吗
  • @arminrock 。 . . rownum = 1 将选择匹配的行之一并将其用于更新。这将修复错误。我不知道这是否是您希望查询执行的操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-03
  • 1970-01-01
相关资源
最近更新 更多