Выполнить два ОБНОВЛЕНИЯ одновременно с дополнительными данными в Oracle - PullRequest
1 голос
/ 24 апреля 2019

У меня есть следующая таблица, которую мне нужно обновить:

USER:

| ID | ACTIVE | REF_COL | COL_2 | COL_3 |
|----|--------|---------|-------|-------|
| 1  |    1   |  value  | value | value |
| 2  |    0   |  value  | value | value |
| 3  |    1   |  value  | value | value |

Я выполняю следующие две UPDATE инструкции отдельно:

  1. Statement-1

    UPDATE
        USER
    SET
        ACTIVE = 1
    WHERE
        REF_COL IN (
            -- Subquery that generates a list of values
        )
    
  2. Statement-2

    UPDATE
        USER
    SET
        ACTIVE = 0
    WHERE
        REF_COL NOT IN (
            -- Subquery that generates a list of values
        )
    

Подзапрос, который генерирует список значений, одинаков для обоих UPDATEзапросы.

Есть ли способ, который поможет мне выполнить запрос сразу, например MERGE?

Следующий запрос с использованием оператора MERGE недействителен:

MERGE INTO USER U
USING (
    -- Subquery that generates a list of values
) T
ON (U.REF_COL = T.VALUE)
WHEN MATCHED THEN
    UPDATE SET U.ACTIVE = 1
WHEN NOT MATCHED THEN
    UPDATE SET U.ACTIVE = 0

Поскольку предложение WHEN NOT MATCHED THEN предполагает наличие оператора INSERT.

Ответы [ 4 ]

2 голосов
/ 24 апреля 2019

Использование CASE в SET

UPDATE
    USER U
SET
    U.ACTIVE = (CASE WHEN U.REF_COL IN (<subquery>) THEN 0 ELSE 1 END)

DEMO

1 голос
/ 24 апреля 2019

Используя идею, предложенную Пондером Стиббонсом в его ответе , я создал следующий запрос;дополнительная логика, которую я добавил, состоит в том, чтобы фильтровать только те строки, для которых необходимо обновить значение ACTIVE:

MERGE INTO USER U
USING (
    SELECT
        TGT.ID,
        SRC.ACTIVE
    FROM
        USER TGT
        JOIN (
            SELECT
                U.REF_COL,
                NVL2(T.REF_COL, 1, 0) AS ACTIVE
            FROM
                USER U
                LEFT JOIN (
                    -- Subquery that generates a list of values
                ) T ON T.REF_COL = U.REF_COL            
        ) SRC ON TGT.REF_COL = SRC.REF_COL
    WHERE
        TGT.ACTIVE != SRC.ACTIVE
) F
ON (U.ID = F.ID)
WHEN MATCHED THEN
    UPDATE SET
        U.ACTIVE = F.ACTIVE
1 голос
/ 24 апреля 2019

Вот версия merge с примером. Вы должны поместить логику в source part:

merge into users tgt
using (
  select u.ref_col, nvl2(s.ref_col, 1, 0) active
    from users u 
    left join subquery s on u.ref_col = s.ref_col ) src
on (tgt.ref_col = src.ref_col)
when matched then update set active = src.active;

Пример dbfiddle

0 голосов
/ 24 апреля 2019

псевдокод для слияния:

MERGE into <target table>

    USING
        <souce table/view/result of subquery>
    ON
        <match condition>
    WHEN MATCHED THEN
        <update clause>
        <delete clause>
    WHEN NOT MATCHED THEN
        <insert clause>

oracle docs выглядит следующим образом: merge_insert_clause указывает значения для вставки в столбец целевой таблицы, если условие предложения ON ложно.Если предложение вставки выполнено, то все триггеры вставки , определенные в целевой таблице, активируются.Если вы опустите список столбцов после ключевого слова INSERT, то количество столбцов в целевой таблице должно совпадать с числом значений в предложении VALUES. вы не можете использовать слияние или два обновления, одно для совпадения и другое для несоответствия.

вместо этого вам придется создать процедуру.

CREATE OR REPLACE PROCEDURE all_updates_in_user
IS
   cursor c1 is<<query that generates a list of values>>
BEGIN

  FOR rec in c1
   LOOP

   UPDATE
    USER
SET
    ACTIVE = 1
WHERE
    REF_COL IN rec.columnname;

   UPDATE
    USER
SET
    ACTIVE = 0
WHERE
    REF_COL  NOT IN rec.columnname;  
 END LOOP;
END;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...