PL/SQL — обновить несколько строк в целевой таблице из одной строки в исходной таблице

Я использую оператор слияния для объединения двух таблиц, где одна строка в исходной таблице может обновлять несколько строк в целевой таблице.

Это происходит примерно так

MERGE TABLE1 A
USING (SELECT EMP_CODE, DAYS_OFF FROM TABLE2) B
ON (A.ID = B.EMP_CODE)
WHEN MATCHED THEN
UPDATE SET A.DAYS_OFF = B.DAYS_OFF;

Однако, когда я пытаюсь это сделать, я получаю SQL Error: ORA-30926: unable to get a stable set of rows in the source tables

Есть ли другой способ сделать это?


person DylanW80    schedule 19.06.2015    source источник
comment
Покажите нам свою полную хранимую процедуру   -  person a_horse_with_no_name    schedule 19.06.2015
comment
@jWeaver Я столкнулся с проблемой, отличной от той, что вы упомянули в посте. Моя проблема в том, что я не могу убедиться, что ON (A.ID = B.EMP_CODE) возвращает только одну строку.   -  person DylanW80    schedule 19.06.2015
comment
не могли бы вы поделиться образцами данных из обеих таблиц?   -  person Ravi    schedule 19.06.2015
comment
@jWeaver Я понимаю, что это может показаться несговорчивым с моей стороны, но я действительно не могу. Могу ли я каким-либо другим образом помочь прояснить проблему?   -  person DylanW80    schedule 19.06.2015
comment
@jWeaver Я попробовал первое решение, предложенное в сообщении, которое вы упомянули, но теперь оно выдает ошибку SQL: ORA-01445: невозможно выбрать ROWID или образец представления соединения без таблицы с сохраненным ключом.   -  person DylanW80    schedule 19.06.2015
comment
Не могли бы вы вставить структуру таблицы?   -  person Ravi    schedule 19.06.2015
comment
Table2 содержит более 1 строки для одного и того же emp_id, например: (emp_code=20, days_off=30) и (emp_code=20, days_off=70). И Oracle не знает, какое значение days_off следует выбрать для обновления записей с id = 20 в таблице 1 - 30 или, может быть, 70?   -  person krokodilko    schedule 19.06.2015
comment
@jWeaver Он не содержит первичных ключей :(   -  person DylanW80    schedule 19.06.2015
comment
не имеет значения, покажите хотя бы структуру таблицы   -  person Ravi    schedule 19.06.2015


Ответы (2)


я получаю сообщение об ошибке SQL: ORA-30926: невозможно получить стабильный набор строк в исходных таблицах

Потому что ваша исходная таблица, вероятно, содержит повторяющиеся значения.

Вероятно, вам нужно добавить еще один столбец, чтобы однозначно идентифицировать каждую строку.

CREATE TABLE source_table (
    col1 NUMBER,
    col2 VARCHAR2(10),
    col3 VARCHAR2(10)
);

INSERT INTO source_table (col1, col2, col3) VALUES (1, 'a', 'w');
INSERT INTO source_table (col1, col2, col3) VALUES (1, 'b', 'x');
INSERT INTO source_table (col1, col2, col3) VALUES (2, 'c', 'y');
INSERT INTO source_table (col1, col2, col3) VALUES (3, 'c', 'z');

COMMIT;

CREATE TABLE target_table (
    col1 NUMBER,
    col2 VARCHAR2(10),
    col3 VARCHAR2(10)
);

INSERT INTO target_table (col1, col2, col3) VALUES (1, 'b', 'z');
INSERT INTO target_table (col1, col2, col3) VALUES (3, 'd', 'w');

COMMIT;

Теперь мы собираемся объединить две таблицы.

MERGE INTO target_table trg
USING (--Actually we can simply write source_table for this example but I want to write Select:)
       SELECT col1, col2, col3
       FROM source_table 
      ) src 
ON (trg.col1 = src.col1)
WHEN MATCHED THEN UPDATE SET --Don't forget you cannot update columns that included in ON clause
    trg.col2 = src.col2,
    trg.col3 = src.col3
WHEN NOT MATCHED THEN INSERT
    (
        col1,
        col2,
        col3
    )
    VALUES
    (
        src.col1,
        src.col2,
        src.col3
    );

COMMIT;

Решение

MERGE INTO target_table trg
USING source_table src --Now I simply write the table name:)
ON (
    trg.col1 = src.col1 AND
    trg.col2 = src.col2
   )
WHEN MATCHED THEN UPDATE SET --Don't forget you cannot update columns that included in ON clause
    trg.col3 = src.col3
WHEN NOT MATCHED THEN INSERT
    (
        col1,
        col2,
        col3
    )
    VALUES
    (
        src.col1,
        src.col2,
        src.col3
    );

COMMIT;

Подробнее

person Ravi    schedule 19.06.2015

Эта ошибка означает, что Oracle не может получить для каждой записи в A набор записей, которые соответствуют только этой записи (например, набор записей, который приводит к отношению «многие ко многим»).

Что вам нужно сделать, так это проверить целевую таблицу на наличие дубликатов элементов с тем же «ID».

SQL> list                
  1  MERGE INTO  TABLE1 A
  2   USING (SELECT * FROM TABLE2) B
  3   ON (A.ID = B.EMP_CODE)
  4   WHEN MATCHED THEN
  5  UPDATE SET A.DAYS_OFF = B.DAYS_OFF
  6*
SQL> r
  1  MERGE INTO  TABLE1 A
  2   USING (SELECT * FROM TABLE2) B
  3   ON (A.ID = B.EMP_CODE)
  4   WHEN MATCHED THEN
  5  UPDATE SET A.DAYS_OFF = B.DAYS_OFF
  6*
MERGE INTO  TABLE1 A
*
ERROR at line 1:
ORA-30926: unable to get a stable set of rows in the source tables

SQL> select id, count(0) from table1 group by id;

        ID   COUNT(0)
---------- ----------
         1          2

SQL> delete from table1 t1 where t1.rowid not in (select max(rowid) from table1 t2 where t2.id = t1.id);

1 row deleted.

SQL> commit;

Commit complete.

SQL> MERGE INTO  TABLE1 A
 USING (SELECT * FROM TABLE2) B
 ON (A.ID = B.EMP_CODE)
 WHEN MATCHED THEN
UPDATE SET A.DAYS_OFF = B.DAYS_OFF  2    3    4    5  ; 

2 rows merged.

SQL> commit;

Commit complete.
person IronDrake    schedule 19.06.2015