Oracle:将 CTE 与更新子句一起使用

Oracle: Using CTE with update clause

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

我在尝试此操作时遇到错误 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

因为 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),然后执行更新

Can I do something like this in oracle database?

好吧,这不是你能不能做的问题。这是关于你是否需要这样做。在您的查询中,我没有看到任何过滤条件。您想更新所有行吗?我认为您的情况不需要 CTE

什么时候需要CTE,即当你有多次执行子查询的场景时,一个with子句作为子查询分解方法。您使用 WITH 子句来确保子查询执行一次,并且结果集存储为临时 table.

是的,您可以对 UPDATE 语句使用 WITH 子句。

例如,

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>

基于 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