【问题标题】:Oracle: Using CTE with update clauseOracle:将 CTE 与更新子句一起使用
【发布时间】:2015-03-04 07:37:20
【问题描述】:

我可以在 oracle 数据库中使用公用表表达式进行更新吗?

我在尝试此操作时收到错误 ORA-00928: missing SELECT keyword

with average as (SELECT avg(salary) FROM instructor)
update instructor
               set salary = case
                   when salary <= average then salary * 1.05 
                   else salary * 1.03                                     
               end

【问题讨论】:

  • 我对 Oracle 数据库没有太多经验,但我认为您遇到了错误,因为您想在更新中使用 CTE(以表的形式返回结果)。为什么不将SELECT avg(salary) FROM instructor 的结果存储到一个变量中并在UPDATE 中使用它呢?我认为这是做你想做的最简单的方法..
  • 好的,我会这样做的。但是我有一个问题,我们可以同时使用 with 和 update 子句吗?
  • 如我所说,CTE 以表格的形式返回结果,然后您可以通过与其他表格的 JOIN 来使用它,或者以其他方式使用(但不能以您的方式使用)重新使用它)以获得您想要的结果。所以,回答你的问题:不,你不能像你那样使用 CTE(它没有被命名为'with')。
  • 语法不正确。是的,您可以在更新语句中使用 WITH 子句,请参阅我的答案。

标签: sql oracle common-table-expression


【解决方案1】:

我可以在 oracle 数据库中做这样的事情吗?

嗯,这与您是否可以做到无关。这是关于你是否需要这样做。在您的查询中,我没有看到任何过滤条件。您想更新所有行吗?在您的情况下,我认为不需要 CTE

您何时需要 CTE,即当您遇到多次执行子查询的场景时,将 with 子句作为子查询分解方法。您使用 WITH 子句确保子查询执行一次,并将结果集存储为临时表。

是的,您可以将 WITH 子句用于 UPDATE 语句。

例如,

UPDATE TABLE t
SET t.column1, t.column2 = (SELECT column1, column2 FROM 
                                       (
                                        WITH cte AS(
                                   SELECT ... FROM another_table
                                                 )
                                         SELECT * FROM cte
                                        )

您可以使用 MERGE 语句USING WITH 子句。

例如,

SQL> MERGE INTO emp e USING
  2  (WITH average AS
  3    (SELECT deptno, AVG(sal) avg_sal FROM emp group by deptno)
  4  SELECT * FROM average
  5  ) u
  6  ON (e.deptno = u.deptno)
  7  WHEN MATCHED THEN
  8  UPDATE SET e.sal      =
  9    CASE
 10      WHEN e.sal <= u.avg_sal
 11      THEN e.sal * 1.05
 12      ELSE e.sal * 1.03
 13    END
 14  /

14 rows merged.

SQL>

【讨论】:

    【解决方案2】:

    由于average salary 只是一个标量值,你可以这样做

    update instructor
       set salary = case
           when salary <= (select avg(t.salary) from instructor t) then salary * 1.05 
           else salary * 1.03                                     
       end
    

    在这种情况下,Oracle 首先计算平均值(比如1234.4567),然后执行更新

    【讨论】:

    • 但是上面的查询是有效的吧?所以我们可以用'with'子句和'update'对吗?
    • @shashankgaurav 在这种情况下,您不需要 CTE 来计算平均值,因为它是在 CASE WHEN 语句中计算的。
    • @alberto 我在谈论我的查询。
    • @shashankgaurav 实际上,您不能像在查询中那样同时使用 CTE 和 UPDATE。这就是 Dmitry 稍微修改了您的查询的原因。
    【解决方案3】:

    基于 another answer 对保留键视图的相关更新,这是在 Oracle SQL 中使用 CTE 和更新避免 where 子句重复的另一个可能选项:

    update (
        with cte as (select avg(salary) average_salary from instructor)
        select id, salary, cte.average_salary from instructor cross join cte
        where <some_condition>
    )
    set salary = case
        when salary <= average_salary/2 then salary * 1.1 
        when salary <= average_salary then salary * 1.05 
        else salary * 1.03                                     
    end
    

    在自加入的情况下,这可以简化为无 CTE 版本:

    update (
        select id, salary, (select avg(salary) from instructor) average_salary 
        from instructor
        where <some_condition>
    )
    set salary = case
        when salary <= average_salary/2 then salary * 1.1 
        when salary <= average_salary then salary * 1.05 
        else salary * 1.03                                     
    end
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 1970-01-01
    • 2016-05-06
    相关资源
    最近更新 更多