2015-03-04 2 views
2

Могу ли я сделать обновление с использованием общего выражения таблицы в базе данных oracle?Oracle: использование CTE с предложением update

Я получаю ошибку 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 
+0

У меня нет большого опыта работы с базой данных Oracle, но я думаю, что вы получаете сообщение об ошибке, потому что вы хотите использовать CTE (который возвращает результаты в форме таблицы) внутри обновления. Почему бы вам просто не сохранить результат «SELECT avg (зарплата) FROM trainer' в переменную и использовать ее в UPDATE? Я думаю, что это самый простой способ сделать то, что вы хотите. –

+1

Хорошо, я сделаю это. Но у меня есть вопрос, мы можем использовать вместе и обновлять предложение вместе? – shashankgaurav

+0

Как я уже сказал, [CTE] (http://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL#Common_table_expression) возвращает результаты в форме таблицы, а затем вы можете использовать их через JOINs с другими таблицами или использовать в другими способами (но не так, как вы его используете), чтобы получить нужные результаты.Итак, чтобы ответить на ваш вопрос: Нет, вы не можете использовать CTE (он не называется «с») таким образом, как ваш. –

ответ

4

С 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), а затем выполните обновление .

+1

Но приведенный выше запрос действительно? Итак, мы можем использовать предложение «с» с «обновлением»? – shashankgaurav

+0

@shashankgaurav В этом случае вам не нужен CTE для вычисления среднего значения, поскольку он вычисляется внутри оператора CASE WHEN. –

+1

@alberto Я говорил о своем запросе. – shashankgaurav

2

Могу ли я сделать что-то подобное в базе данных оракула?

Ну, это не о том, можете ли вы это сделать или нет. Речь идет о том, нужно ли вам это делать или нет. В вашем запросе я не вижу никаких критериев фильтрации. Вы хотите обновить все строки? Я не вижу необходимости в CTE в вашем случае.

Когда вам понадобится CTE, то есть предложение a как метод факторизации подзапроса, когда у вас есть сценарий, когда подзапрос выполняется несколько раз. Вы используете предложение 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 заявление ИСПОЛЬЗОВАНИЕС пункта.

Например,

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> 
1

Основываясь на another answer на коррелированных обновление ключа сохранившийся зрения, вот еще один возможный вариант для использования КТР с обновлением в Oracle SQL избежать дублирования, где положение:

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 
+0

Подробнее о «ключевой сохраненной» вещи: http://dba.stackexchange.com/questions/38728/oracle-non-key-preserved-table-should-be – Vadzim

Смежные вопросы