Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

ORA-01779:không thể sửa đổi cột ánh xạ tới một bảng không được lưu giữ khóa

Mệnh đề biểu thức bảng DML chỉ hữu ích khi bạn cần các cột từ nhiều bảng. Trong trường hợp của bạn, bạn có thể sử dụng bản cập nhật thường xuyên với EXISTS :

update web_userrole
set role = replace(role, 'FULL', 'READ')
where read_only <> 'Y'
    and exists
    (
        select 1/0
        from web_userdatasource
        where datasource = p_datasource
            and username = web_userrole.username
    );

Nếu bạn thực sự cần sử dụng các cột từ cả hai bảng, bạn có ba tùy chọn:

  1. lặp lại tham gia trong SETWHERE mệnh đề. Điều này dễ xây dựng nhưng không tối ưu.
  2. Biểu thức bảng DML. Điều này nên hoạt động, nếu bạn có các chỉ mục chính xác.
  3. MERGE , dưới đây là một ví dụ.

    merge into web_userrole
    using
    (
        select distinct username
        from web_userdatasource
        where datasource = p_datasource
    ) web_userdatasource on
    (
        web_userrole.username = web_userdatasource.username
        and web_userrole.read_only <> 'Y'
    )
    when matched then update
    set role = replace(role, 'FULL', 'READ');
    

Điều này không trực tiếp trả lời câu hỏi của bạn, nhưng thay vào đó cung cấp một số giải pháp thay thế. Tôi không thể tạo lại lỗi bạn đang gặp phải. Tôi cần một trường hợp thử nghiệm đầy đủ để xem xét thêm.

Lời khuyên chung cho các chế độ xem có thể cập nhật

Một trong những vấn đề chính với các dạng xem có thể cập nhật là số lượng lớn các hạn chế đối với các truy vấn mà chúng có thể chứa. Truy vấn hoặc chế độ xem không được chứa nhiều tính năng, chẳng hạn như DISTINCT, GROUP BY, một số biểu thức nhất định, v.v. Các truy vấn có các tính năng đó có thể phát sinh ngoại lệ "ORA-01732:thao tác thao tác dữ liệu không hợp pháp trên chế độ xem này".

Truy vấn dạng xem có thể cập nhật phải trả lại mỗi hàng của bảng đã sửa đổi một cách rõ ràng chỉ một lần. Truy vấn phải là "khóa được bảo toàn", có nghĩa là Oracle phải có thể sử dụng khóa chính hoặc ràng buộc duy nhất để đảm bảo rằng mỗi hàng chỉ được sửa đổi một lần.

Để chứng minh lý do tại sao khóa được bảo toàn lại quan trọng, đoạn mã dưới đây tạo một câu lệnh cập nhật không rõ ràng. Nó tạo ra hai bảng, bảng đầu tiên có một hàng và bảng thứ hai có hai hàng. Các bảng nối với cột A và cố gắng cập nhật cột B trong bảng đầu tiên. Trong trường hợp này, tốt nhất là Oracle ngăn cập nhật, nếu không giá trị sẽ không xác định. Đôi khi giá trị sẽ được đặt thành "1", đôi khi giá trị sẽ được đặt thành "2".

--Create table to update, with one row.
create table test1 as
select 1 a, 1 b from dual;

--Create table to join two, with two rows that match the other table's one row.
create table test2 as
select 1 a, 1 b from dual union all
select 1 a, 2 b from dual;

--Simple view that joins the two tables.
create or replace view test_view as
select test1.a, test1.b b_1, test2.b b_2
from test1
join test2 on test1.a = test2.a;

--Note how there's one value of B_1, but two values for B_2.
select *
from test_view;

A  B_1  B_2
-  ---  ---
1    1    1
1    1    2

--If we try to update the view it fails with this error:
--ORA-01779: cannot modify a column which maps to a non key-preserved table
update test_view
set b_1 = b_2;

--Using a subquery also fails with the same error.
update
(
    select test1.a, test1.b b_1, test2.b b_2
    from test1
    join test2 on test1.a = test2.a
)
set b_1 = b_2;

MERGE tuyên bố không có các hạn chế giống nhau. MERGE câu lệnh dường như cố gắng phát hiện sự không rõ ràng tại thời gian chạy, thay vì thời gian biên dịch.

Rất tiếc, MERGE không phải lúc nào cũng làm tốt việc phát hiện ra sự mơ hồ. Trên Oracle 12.2, câu lệnh dưới đây đôi khi sẽ hoạt động, và sau đó không thành công. Thực hiện những thay đổi nhỏ đối với truy vấn có thể khiến nó hoạt động hoặc không thành công, nhưng tôi không thể tìm thấy một mẫu cụ thể.

--The equivalent MERGE may work and changes "2" rows, even though there's only one.
--But if you re-run, or uncomment out the "order by 2 desc" it might raise:
--  ORA-30926: unable to get a stable set of rows in the source tables
merge into test1
using
(
    select test1.a, test1.b b_1, test2.b b_2
    from test1
    join test2 on test1.a = test2.a
    --order by 2 desc
) new_rows
    on (test1.a = new_rows.a)
when matched then update set test1.b = new_rows.b_2;

UPDATE không thành công tại thời điểm biên dịch nếu về mặt lý thuyết có thể có các bản sao. Một số câu nói nên công việc sẽ không chạy.

MERGE không thành công nếu cơ sở dữ liệu phát hiện các hàng không ổn định tại thời điểm chạy. Một số câu nói không nên công việc sẽ vẫn chạy.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORA-00947 Không đủ giá trị khi khai báo kiểu trên toàn cầu

  2. Cách thêm 'ON DELETE CASCADE' trong câu lệnh ALTER TABLE

  3. Làm cách nào để lấy thẻ xml tự đóng trong Oracle PLSQL?

  4. PL / SQL:làm cách nào để nhắc người dùng nhập vào một thủ tục?

  5. chèn nhiều hàng trong Oracle SQL