【问题标题】:Update statement with inner join on Oracle在 Oracle 上使用内部连接更新语句
【发布时间】:2022-12-10 20:24:32
【问题描述】:

我有一个在 MySQL 中运行良好的查询,但是当我在 Oracle 上运行它时,出现以下错误:

SQL 错误:ORA-00933:SQL 命令未正确结束
00933. 00000 - “SQL 命令未正确结束”

查询是:

UPDATE table1
INNER JOIN table2 ON table1.value = table2.DESC
SET table1.value = table2.CODE
WHERE table1.UPDATETYPE='blah';

【问题讨论】:

  • 当我试图在 Oracle 中设置 table2 以测试我的答案时,我发现 Oracle 拒绝将 DESC 作为列名。
  • 抱歉,我只是缩写了原始列名来描述它显然不是数据库中的那个

标签: sql oracle inner-join ora-00933


【解决方案1】:

该语法在 Oracle 中无效。你可以这样做:

UPDATE table1 SET table1.value = (SELECT table2.CODE
                                  FROM table2 
                                  WHERE table1.value = table2.DESC)
WHERE table1.UPDATETYPE='blah'
AND EXISTS (SELECT table2.CODE
            FROM table2 
            WHERE table1.value = table2.DESC);

或者您可能能够做到这一点:

UPDATE 
(SELECT table1.value as OLD, table2.CODE as NEW
 FROM table1
 INNER JOIN table2
 ON table1.value = table2.DESC
 WHERE table1.UPDATETYPE='blah'
) t
SET t.OLD = t.NEW

这取决于内联视图是否被 Oracle 认为是可更新的 (第二条语句是否可更新取决于列出的一些规则 here).

【讨论】:

  • 我做了第二个例子,但必须在 select 中为列名添加别名,然后在 SET 中通过它们的名称引用它们,但它起作用了,谢谢
  • 第二个示例的好处是允许您在实际执行更新之前测试 SQL。
  • 第二个例子对我有用。我喜欢那个,因为它看起来干净且可读。在性能方面不知道两者之间的优缺点。但是,我现在并不担心这一点,因为我将其用于一次性脚本来更正错误数据。
  • 关于可更新连接的密钥保留要求的说明:asktom.oracle.com/pls/asktom/…
  • 得到这个 - “ORA-01779:无法修改映射到非键保留表的列”,然后 stackoverflow.com/questions/9335536/… 提供了帮助。
【解决方案2】:

用这个:

MERGE
INTO    table1 trg
USING   (
        SELECT  t1.rowid AS rid, t2.code
        FROM    table1 t1
        JOIN    table2 t2
        ON      table1.value = table2.DESC
        WHERE   table1.UPDATETYPE='blah'
        ) src
ON      (trg.rowid = src.rid)
WHEN MATCHED THEN UPDATE
    SET trg.value = code;

【讨论】:

  • 工作完美,但 Oracle 要求我说 merge into table 1 t 等等。
  • 派对迟到了,但这仍然是一个很好的话题。我需要知道,但是……我错过了什么吗?主表,“table1”。在 USING 中,table1 别名为 t1。表 2,别名为 t2,但在 ON 中,引用是...?外部表 1 - 不是 t1 - 这是对外部表还是类型的引用?表二?不是t2吗?我很困惑。更好的别名的粉丝......
  • 这里只是一点,如果你的键(trg.rowid 或 src.rid)有一个重复的项目,这个子句会抛出一个错误:ora-30926.ora-code.com
  • @Marc 在ON 中,trg 是主表的别名,table1(您的逻辑是“外部”表),src 引用USING 组(您的逻辑是“内部表” ).但是,是的,可能可以更好地引用,但我能够遵循它。
  • @supernova:托尼的回答是更新内联视图。这在某些情况下可行,但视图必须是“保留键”的(每个连接表都必须在其主键或其他唯一字段集上进行相等连接)。这确保了目标表中的每条记录最多对结果行集中的一条记录有贡献,因此,目标表中的每条记录最多更新一次。
【解决方案3】:

MERGEWHERE 子句:

MERGE into table1
USING table2
ON (table1.id = table2.id)
WHEN MATCHED THEN UPDATE SET table1.startdate = table2.start_date
WHERE table1.startdate > table2.start_date;

您需要 WHERE 子句,因为无法更新 ON 子句中引用的列。

【讨论】:

  • 这个版本可以说是更干净的,但它不是触发器友好的,因为我不知道如何避免使用这种语法为未更改的行触发更新触发器。 (我假设触发器需要变了行。)
【解决方案4】:

不要使用上面的一些答案。

有些人建议使用嵌套的 SELECT,不要那样做,它非常慢。如果您有很多记录要更新,请使用加入,例如:

update (select bonus 
        from employee_bonus b 
        inner join employees e on b.employee_id = e.employee_id 
        where e.bonus_eligible = 'N') t
set t.bonus = 0;

有关详细信息,请参阅此链接。 http://geekswithblogs.net/WillSmith/archive/2008/06/18/oracle-update-with-join-again.aspx

此外,请确保您要加入的所有表上都有主键。

【讨论】:

  • 短而完美
【解决方案5】:
 UPDATE ( SELECT t1.value, t2.CODE
          FROM table1 t1
          INNER JOIN table2 t2 ON t1.Value = t2.DESC
          WHERE t1.UPDATETYPE='blah')
 SET t1.Value= t2.CODE

【讨论】:

    【解决方案6】:

    here 所示,Tony Andrews 提出的第一个解决方案的一般语法是:

    update some_table s
    set   (s.col1, s.col2) = (select x.col1, x.col2
                              from   other_table x
                              where  x.key_value = s.key_value
                             )
    where exists             (select 1
                              from   other_table x
                              where  x.key_value = s.key_value
                             )
    

    我认为这很有趣,尤其是当您想要更新多个字段时。

    【讨论】:

    • 这对我不起作用。它更新整个表。
    【解决方案7】:

    它工作正常甲骨文

    merge into table1 t1
    using (select * from table2) t2
    on (t1.empid = t2.empid)
    when matched then update set t1.salary = t2.salary
    

    【讨论】:

    • 可以通过在末尾添加逗号来设置多个属性。在“用户名”列 (t1.UserName = t2.UserName) 上匹配后,我需要在表上执行 t1.First_Name = t2.FirstName, t1.Last_Name = t2.LastName,以从名为 UserInfo (select * from UserInfo) t2) 的表中检索他们的姓名。数据库就是这样,它在任何地方都使用 UserName 作为 UserInfo 的主键,而不是直接将 FirstName 和 LastName 放在表中。这解决了!
    • 这个答案对 Quassnoi 比您早五年已经提供的答案没有任何补充。
    【解决方案8】:

    以下语法对我有用。

    UPDATE
    (SELECT A.utl_id,
        b.utl1_id
        FROM trb_pi_joint A
        JOIN trb_tpr B
        ON A.tp_id=B.tp_id Where A.pij_type=2 and a.utl_id is null
    )
    SET utl_id=utl1_id;
    

    【讨论】:

    • @JimGarrison 请重新编辑这个答案,这样我就可以删除我的反对票....我试图使用这种语法,但它没有更新我的表格。我找到了原因 - 我的 SET 正在执行 REPLACE 并且我试图将列中的特定字符串留空 - 结果 Oracle 将 '' 视为空值,并且该字段无法为空。我认为语法只是更新临时表而不是真正的表,但我错了。
    【解决方案9】:

    使用描述而不是表 2 的 desc,

    update
      table1
    set
      value = (select code from table2 where description = table1.value)
    where
      exists (select 1 from table2 where description = table1.value)
      and
      table1.updatetype = 'blah'
    ;
    

    【讨论】:

    • 为什么你想在 table2 上触发两个单独的查询
    【解决方案10】:
    UPDATE table1 t1
    SET t1.value = 
        (select t2.CODE from table2 t2 
         where t1.value = t2.DESC) 
    WHERE t1.UPDATETYPE='blah';
    

    【讨论】:

      【解决方案11】:
      UPDATE (SELECT T.FIELD A, S.FIELD B
      FROM TABLE_T T INNER JOIN TABLE_S S
      ON T.ID = S.ID)
      SET B = A;
      

      A 和 B 是别名字段,不需要指向表。

      【讨论】:

      • 嗨,丹。您正在发布一个已经有很好答案的相当古老的问题。你能解释一下什么时候你的问题比其他解决方案更可取吗?
      • 当然,我已经看到一个答案,其中 b = a 是通过指向表名 (table1.B = table2.A) 编写的,但不需要指向表。
      • 您实际上是在更新视图中的字段,这些字段会映射到表中。如果内部视图的别名是 h,那么“自我记录”版本将是“set h.b = h.a”。
      【解决方案12】:
      UPDATE IP_ADMISSION_REQUEST ip1
      SET IP1.WRIST_BAND_PRINT_STATUS=0
      WHERE IP1.IP_ADM_REQ_ID        =
        (SELECT IP.IP_ADM_REQ_ID
        FROM IP_ADMISSION_REQUEST ip
        INNER JOIN VISIT v
        ON ip.ip_visit_id=v.visit_id
        AND v.pat_id     =3702
        ); `enter code here`
      

      【讨论】:

        【解决方案13】:

        就完整性而言,因为我们在谈论 Oracle,这也可以做到:

        declare
        begin
          for sel in (
            select table2.code, table2.desc
            from table1
            join table2 on table1.value = table2.desc
            where table1.updatetype = 'blah'
          ) loop
            update table1 
            set table1.value = sel.code
            where table1.updatetype = 'blah' and table1.value = sel.desc;    
          end loop;
        end;
        /
        

        【讨论】:

        • 这可以做到,但这是最慢的方法。
        【解决方案14】:

        甲骨文基地在这方面有很好的表现。

        https://oracle-base.com/articles/misc/updates-based-on-queries

        从这个链接 - 我使用了对上述查询的修改,它对我不起作用(来自使用 rowid 的 mathguy 的答案)

        MERGE /*+ APPEND PARALLEL(8) */ INTO dest_table tt
        USING source_table st
        ON (tt.identifier = st.identifier)
        WHEN MATCHED THEN
          UPDATE SET tt.number = st.number;
        

        这里我有两个表:source 和 dest。它们都有一个共同的 varchar 字段,我将源标识字段 (PK) 添加到 dest 表中。

        【讨论】:

          【解决方案15】:
          update table1  a 
             set a.col1='Y' 
           where exists(select 1 
                          from table2 b
                         where a.col1=b.col1 
                           and a.col2=b.col2
                       )
          

          【讨论】:

            猜你喜欢
            • 2011-01-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-12-01
            • 1970-01-01
            相关资源
            最近更新 更多