【问题标题】:Using "WITH" and "UPDATE" statements in the same SQL query在同一个 SQL 查询中使用“WITH”和“UPDATE”语句
【发布时间】:2017-08-15 07:58:44
【问题描述】:

我有一张表格,需要使用 Excel 电子表格中的一些数据进行更新。我正在考虑以下方面的查询:

WITH temp AS(
(SELECT 'abcd' AS oldvalue, 'defg' AS newvalue FROM dual) UNION
(SELECT .....) --About 300 lines of this, copied from Excel and then formatted into the SELECT statement
)
UPDATE mytable
   SET name = (SELECT newvalue FROM temp WHERE mytable.name = temp.oldvalue)

但 Oracle 似乎不喜欢在同一个查询中使用“WITH”和“UPDATE”语句。我收到一条错误消息,提示“缺少 SELECT 关键字”。我发现我可以将临时表定义放在 SELECT 语句中,即

 SET name = (SELECT newvalue FROM (
         (SELECT 'abcd' AS oldvalue, 'defg' AS  newvalue FROM dual) UNION
         (SELECT .....)
          ) temp WHERE mytable.name = temp.oldvalue)

但是,在查询的中间定义一个类似的表是非常非常混乱的代码。我一想到就畏缩。必须有更好的方法来做到这一点。我应该设置一个全局临时表吗?还是我只是错过了一些简单的语法,可以使这项工作以原始方式工作?

【问题讨论】:

  • 我认为创建临时表绝对是更好的方法。

标签: sql oracle sql-update common-table-expression


【解决方案1】:

您可以在更新中使用 with 子句;你只需要在正确的地方做:

UPDATE mytable
   SET name = (WITH temp AS((SELECT 'abcd' AS oldvalue, 'defg' AS newvalue FROM dual) UNION
                            (SELECT .....) --About 300 lines of this, copied from Excel and then formatted into the SELECT statement
                           )
               SELECT newvalue
               FROM   temp
               WHERE  mytable.name = temp.oldvalue);

但是,您可能只想更新临时子查询中存在的行,因此您需要一个额外的 where 子句:

UPDATE mytable
   SET name = (WITH temp AS((SELECT 'abcd' AS oldvalue, 'defg' AS newvalue FROM dual) UNION
                            (SELECT .....) --About 300 lines of this, copied from Excel and then formatted into the SELECT statement
                           )
               SELECT newvalue
               FROM   temp
               WHERE  mytable.name = temp.oldvalue)
WHERE  EXISTS (WITH temp AS((SELECT 'abcd' AS oldvalue, 'defg' AS newvalue FROM dual) UNION
                            (SELECT .....) --About 300 lines of this, copied from Excel and then formatted into the SELECT statement
                           )
               SELECT NULL
               FROM   temp
               WHERE  mytable.name = temp.oldvalue);

或者,使用 MERGE 语句:

merge into mytable tgt
  using (WITH temp AS((SELECT 'abcd' AS oldvalue, 'defg' AS newvalue FROM dual) UNION
                      (SELECT .....) --About 300 lines of this, copied from Excel and then formatted into the SELECT statement
                     )
         SELECT mytable.rowid r_id,
                temp.newvalue
         FROM   temp
         inner  join mytable on mytable.name = temp.oldvalue) src
    on (tgt.rowid = src.r_id)
when matched then
update set tgt.name = src.newvalue;

注意您必须在合并语句的源查询中加入实际表,因为您正在尝试更新正在加入的列,而您不能在合并语句中执行此操作 - 因此我已将合并连接切换为加入 mytable.rowid。

您必须测试这两个语句,看看哪一个在您的数据上表现最好。

【讨论】:

    【解决方案2】:

    试试这个:

    更新 mytable m 设置名称 = (与温度 AS (SELECT 'abcd' AS oldvalue, 'defg' AS newvalue FROM DUAL UNION ALL /* 在这种情况下使用 UNION ALL 而不是 UNION */ 从 DUAL 中选择“efgh”作为旧值,“klmn”作为新值) 选择新值 从温度 WHERE temp.oldvalue = m.name)

    或者,您可以通过将其插入 Excel 中的相邻单元格来生成脚本:

       ="UPDATE YOUR_TABLE_NAME SET NAME="&CELL_WITH_NEW_VALUE&" WHERE NAME="&CELL_WITH_OLD_VALUE&"; COMMIT;"
    

    并将其向下拖动到值列表的末尾。

    之后,将其作为脚本运行,就完成了!

    【讨论】:

    • Boneist 的回答对我来说效果更好,但这也是一个非常好的解决方案。 +1
    【解决方案3】:

    首先,我建议像这样使用 JOIN 进行更新:

    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
    

    此外,如果您有权限,请使用一些 ETL 解决方案(Pentaho、SSIS、Oracle BI Suite)创建表并导入数据。从性能的角度来看,这很干净而且还可以。

    或者,使用光标 - 更多信息在下面的链接中: http://www.adp-gmbh.ch/ora/plsql/cursors/for_update.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-11
      • 1970-01-01
      • 2019-04-29
      • 1970-01-01
      • 1970-01-01
      • 2021-05-03
      • 2022-07-06
      • 2013-06-03
      相关资源
      最近更新 更多