2009-07-28 15 views
3

Ich habe es mit zwei Tabellen, die 2 Spalten haben, wie unter aufgeführt.Aktualisieren Sie alle Zeilen einer einzelnen Spalte

Tabelle 1: table_snapshot account_no | balance_due

Tabelle 2: Tabelle_ bezahlt account_no | post_balance | delta_balance

habe ich eine dritte Spalte mit dem folgenden Befehl table2:

ALTER TABLE table_paid ADD delta_balance number(18); 

Ich versuche, die folgende Abfrage zu verwenden, die neue Spalte (delta_balance) mit dem Unterschied in Salden zwischen 1 zu aktualisieren und 2. FYI, table_paid ist eine Teilmenge von table_snapshot. In Tabelle 2 sind nur einige wenige Konten in Tabelle 1 vorhanden. Ich erhalte die Fehlermeldung: SQL-Anweisung wurde nicht ordnungsgemäß beendet. die Abfrage, die ich verwende, ist:

Schätzen Sie, wenn jemand meine Abfrage korrigieren kann.

Vielen Dank.

Neuling.

Antwort

4

Oracle nicht das haben UPDATE ... FROM Syntax, die Sie von MS Sql Server verwenden (was, glaube ich, ist nicht ANSI sowieso). Stattdessen, wenn Sie ein Update auf einer Ergebnismenge tun müssen, um, Oracle hat man das Suchresultates als eine Art Inline-Ansicht erstellen, aktualisieren Sie über die Sicht, etwa so:

UPDATE (SELECT tp.delta_balance 
       , tp.post_balance 
       , ts.balance_due 
      FROM table_paid tp 
        JOIN table_snapshot ts 
        ON tp.account_no = ts.account_no 
     ) 
    SET delta_balance = post_balance - balance_due; 

Dies ist mehr „richtiger“ als die von Babar und palindrom gelieferten Antworten, da ihre Abfragen jede Zeile in table_paid aktualisieren, auch wenn in table_snapshot keine entsprechenden Zeilen vorhanden sind. Wenn es eine Übereinstimmung von 1-1 gibt, müssen Sie sich keine Sorgen machen, aber es ist sicherer, dies mit der Inline-Ansicht zu tun.

In Ihrem Beispiel ist unklar, welche Tabelle die Elterntabelle ist, oder (wie ich vermute) die Elterntabelle und account_no verweist auf den Primärschlüssel einer anderen Tabelle (vermutlich account oder "table_account" von Ihrem Regeln der Namensgebung). In jedem Fall ist klar, dass es in Ihrer Tabelle keine 1: 1 Übereinstimmung gibt - 15K in einer, Millionen in der anderen.

Dies könnte 2 Dinge bedeuten: entweder gibt es viele Zeilen in table_snapshot, die keine entsprechende Zeile in table_paid haben, oder es gibt viele Zeilen in table_snapshot für jede Zeile in table_paid. Wenn Letzteres wahr ist, ist Ihre Abfrage unmöglich - Sie haben mehrere Aktualisierungen für jede Zeile in table_paid, und das Ergebnis wird nicht vorhersehbar sein; Woher weißt du, welche der Ausdrücke "post_balance - balance_due" letztendlich den Wert einer gegebenen delta_balance bestimmen?

Wenn Sie meine Abfrage ausführen, werden Sie dies schnell genug herausfinden - Sie erhalten eine Fehlermeldung, die besagt, "ORA-01779: kann keine Spalte ändern, die auf eine nicht Schlüssel-beibehaltene Tabelle". Dieser Fehler wird nicht basierend auf den Daten in der Tabelle angezeigt (möglicherweise in Ordnung), sondern basiert auf den Primärschlüsseln, die Sie in den beiden Tabellen definiert haben.Wenn die Join-Bedingung, die Sie angeben, nicht eindeutig zu einer 1-1-Beziehung zwischen der aktualisierten Tabelle und dem Rest des Joins führt, erhalten Sie diesen Fehler basierend auf den definierten Schlüsseln. Es ist Oracles Art, Ihnen zu sagen: "Sie sind dabei, Ihre Daten zu vermasseln".

In den anderen Antworten hier erhalten Sie nur einen Fehler (in diesem Fall ORA-01427: einreihige Unterabfrage gibt mehr als eine Zeile zurück), wenn Sie tatsächlich Daten haben, die ein Problem verursachen würden; Meine Version ist strenger, es kann also sein, dass Sie die anderen Versionen verwenden müssen.

Und wie die anderen schon gesagt haben, werden Sie definitiv einen Index für account_no für die Tabelle table_snapshot haben wollen. Einer auf dem table_paid würde auch nicht weh tun.

+0

Ausgezeichnet .. Danke für die detaillierte Info! – novice

4

testen Werde

UPDATE table_paid 
SET table_paid.delta_balance = table_paid.post_balance - 
(SELECT table_snapshot.balance_due from table_snapshot WHERE table_paid.account_no = 
table_snapshot.account_no); 
1

UPDATE table_paid SET table_paid.delta_balance = table_paid.post_balance - (wählen balance_due von table_snapshot WHERE table_paid.account_no = table_snapshot.account_no)

+0

Hallo Babar und Palindrom, Ihre Abfrage wird in eine vollständige Tabelle Scan und ist noch in Ausführung. Tabelle 1 hat etwa 1,3 Millionen Datensätze und Tabelle 2 hat 15k Datensätze. Haben Sie Vorschläge, wie Sie die Scangeschwindigkeit erhöhen können? grüße! – novice

+0

Für weitere Informationen sehen Sie, was Tom Kyte über Update in vielen Zeilen zu sagen hat - http://asktom.oracle.com/pls/asktom/f?p=100:11:0::NR::P11_QUESTION_ID:6407993912330 – jva

+1

erstellen ein Index auf Tabelle1 (account_no), wenn Sie nicht bereits haben. – palindrom

Verwandte Themen