2016-03-26 8 views
2

Ich versuche, Daten in 2 verschiedenen Tabellen in derselben Abfrage mit dem folgenden Code zu aktualisieren:Aktualisierung mit 2 verbindet

UPDATE (SELECT s.passNumb, a.hour, a.minute, p.number, s.situation 
     FROM passwords s 
     JOIN atend a ON s.passNumb = a.passNumb 
     JOIN points p ON a.number = p.number 
     WHERE s.passNumb = 1 AND 
       p.number = 1) 
    SET a.hour = TO_CHAR(SYSDATE, 'HH24'), 
     a.minute = TO_CHAR(SYSDATE, 'MI'), 
     s.situation = 'F'; 

Aber ich bin immer diese Fehlermeldung: Cannot modify a column which maps to a non key-preserved table. Was mache ich falsch?

Antwort

1

Eine Ansicht mit einem Join (oder eine Inline-Ansicht enthält eine in Ihrem Fall kommen) müssen die folgenden Bedingungen erfüllen aktualisierbar sein:
https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_8004.htm

If you want a join view to be updatable, then all of the following conditions must be true:

The DML statement must affect only one table underlying the join.

For an INSERT statement, the view must not be created WITH CHECK OPTION, and all columns into which values are inserted must come from a key-preserved table. A key-preserved table is one for which every primary key or unique key value in the base table is also unique in the join view.

For an UPDATE statement, the view must not be created WITH CHECK OPTION, and all columns updated must be extracted from a key-preserved table.


Die erste Bedingung ziemlich offensichtlich ist: The DML statement must affect only one table underlying the join.

Aber was bedeutet es: "Schlüsseltabelle erhalten"?

A key-preserved table is one for which every primary key or unique key value in the base table is also unique in the join view.

Der Schlüssel erhaltenen Tabelle bedeutet, dass jede Reihe aus dieser Tabelle höchstens einmal im Ergebnis einer Ansicht angezeigt.

ein einfaches Beispiel:

CREATE TABLE users(
    user_id int primary key, 
    user_name varchar(100), 
    age int 
); 

insert into users values(1,'Tom', 22); 

CREATE TABLE emails(
    user_id int, 
    email varchar(100) 
); 

Insert into emails values(1, '[email protected]'); 
Insert into emails values(1, '[email protected]'); 
commit; 

Und ein Join:

SELECT * 
FROM users u 
JOIN emails e ON u.user_id = e.user_id; 

    USER_ID USER_NAME    AGE USER_ID EMAIL    
---------- --------------- ---------- ---------- -------------------- 
     1 Tom      22   1 [email protected] 
     1 Tom      22   1 [email protected] 

Wenn Sie an einem Ergebnis dieser beitreten betrachten, ist es offensichtlich, dass:

  • user_id, user_name und Alter kommen aus nicht-Schlüssel erhalten Tabelle
  • E-Mail kommt aus Schlüssel-erhalten Tabelle

Und nun: Dieses Update ist akzeptabel, weil sie einen Schlüssel erhalten Spalte (Tabelle) Updates in diesem beitreten:

UPDATE (
     SELECT * FROM users u 
     JOIN emails e ON u.user_id = e.user_id 
    ) 
    SET email = email || '.it' ; 

    USER_ID USER_NAME    AGE USER_ID EMAIL     
---------- --------------- ---------- ---------- ------------------------- 
     1 Tom      22   1 [email protected]  
     1 Tom      22   1 [email protected] 

Aber dieses Update kann, da es nicht getan werden, berührt eine Säule aus nicht-Schlüssel-Tabelle erhalten:

UPDATE (
    SELECT * FROM users u 
    JOIN emails e ON u.user_id = e.user_id 
) 
SET age = age + 2; 

SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table 
01779. 00000 - "cannot modify a column which maps to a non key-preserved table" 
*Cause: An attempt was made to insert or update columns of a join view which 
      map to a non-key-preserved table. 
*Action: Modify the underlying base tables directly. 

Wenn Sie eine Weile denken .... Tom erscheint 2 Mal im Ergebnis der Verbindung (aber es gibt nur einen Tom in der users Tabelle).

Wenn wir in diesem Join versuchen, age = age + 2 zu aktualisieren, was sollte dann ein Ergebnis dieses Updates sein?

Soll Tom nur einmal aktualisiert werden? Soll Tom nach diesem Update 22 + 2 = 24 Jahre alt sein?

Oder vielleicht Tom sollte zweimal aktualisiert werden (da es zweimal im Ergebnis der Verknüpfung erscheint), also sollte es 22 + 2 + 2 = 26 Jahre alt sein.

Ein anderes Beispiel - bitte sagen Sie mir, was sollte ein Ergebnis dieses Updates sein?:

UPDATE (....our join ...) SET age = length(email); 

Es gibt sehr schwierige Fragen :)
Und aus diesem Grund Oracle verhindert, dass nicht-Schlüssel erhalten Tabellen zu aktualisieren.


Die Fehlermeldung gibt diesen Hinweis: *Action: Modify the underlying base tables directly.

Das bedeutet, dass wir direkt auf diese Tabelle aktualisieren müssen, einen separaten Befehl UPDATE:

UPDATE users SET age = age + 2 
+0

Danke für die Erklärung, ich habe es. – developer033