2016-06-14 19 views
1

Ich habe eine Funktion:SQL-Fehler: ORA-00904: "CNPPARMID": ungültige Kennung

In Zeile sofort ausführen 'wählen' || Schemamename || "." || Wert1 || '_seq.nextval von dual' in cnpParmId;

Erhalte Fehler als SQL-Fehler: ORA-00904: "CNPPARMID": ungültiger Bezeichner. Ich habe versucht, die cnpParmId innerhalb der Anführungszeichen, versucht in cnpParmId von Dual, auf alle möglichen Arten. Aber es funktioniert nicht. Bitte geben Sie mir einige Ideen, um dieses Problem zu lösen. Danke !!

+1

Da die Antworten indirekt aufzeigen, erhalten Sie wahrscheinlich den Fehler bei der 2. Anweisung "execute southern", nicht die erste. – sstan

Antwort

2

Ihre Funktion erfolgreich kompiliert, und Sie erhalten den Fehler zur Laufzeit:

select test(user, 'T42') from dual; 

SQL Error: ORA-00904: "CNPPARMID": invalid identifier 
ORA-06512: at "MYSCHEMA.TEST", line 23 

Sie sagten, der Fehler war auf der ersten execute immediate, aber das ist Zeile 21 nicht Zeile 23, und wenn es das cnpParmId Bezug war es beschweren sich dann würde es einen Kompilierungsfehler verursachen - die Funktion würde aber mit Fehlern erstellt werden/Warnungen, und es wäre nicht möglich, es zu nennen.

So ist es die zweite execute immediate, an der Linie 23, die zur Laufzeit wird erroring (umformatiert leicht):

execute immediate 
    'select ''T'' from dual where cnpParmId not in ' || 
    '(select value1 from ' || schemaname || '.' || tablename || ')' 
    into good; 

Als GolezTrol gesagt, die dynamische Anweisung in einem SQL-Kontext ausgeführt, die keine Sichtbarkeit jeder haben Ihrer PL/SQL-Variablen. Es ist das gleiche wie die generierte Anweisung ausgeführt wird:

select 'T' from dual where cnpParmId not in (select value1 from myschema.t42); 

... direkt in SQL * Plus oder SQL Developer, die auch bekommen:

SQL Error: ORA-00904: "CNPPARMID": invalid identifier 
00904. 00000 - "%s: invalid identifier" 

Als Variation von GolezTrol der Verkettung, könnten Sie eine verwenden Binden Sie die Variable, um ein hartes Parsing bei jedem Durchlauf Ihrer Schleife zu verhindern. Sie müssen jedoch auch den Namen der Primärschlüsselspalte angeben, da ebenfalls nicht erkannt wird. und das muss verkettet werden in:

execute immediate 
    'select ''T'' from dual where :cnpParmId not in ' || 
    '(select ' || value1 || ' from ' || schemaname || '.' || tablename || ')' 
    into good using cnpParmId; 

die kompiliert und ausgeführt wird.

könnten Sie auch not exists verwenden, anstatt not in, was könnte besser durchführen, da Sie für die (indexiert) Primärschlüssel suchen:

execute immediate 
    'select ''T'' from dual where not exists (select null from ' 
    || schemaname || '.' || tablename || ' where ' || value1 || ' = :cnpParmId)' 
    into good using cnpParmId; 

Sie können auch die Abfrage bewegen, die value1 außerhalb der Schleife findet; Es gibt keinen Vorteil, das wiederholt anzurufen.


Es sieht so aus, als ob Sie dies tun, weil Sie Primärschlüsselwerte haben, die nicht aus der Sequenz generiert wurden. Wenn Sie immer noch neue Datensätze hinzufügen - z. über einen Trigger, der nur die Sequenz verwendet, wenn die Spalte für den übergebenen Schlüssel null ist - dann brauchen Sie einen solchen Hack oder eine Einfügeschleife, die das ORA-01001 abfängt. Aber dieser Ansatz hat immer noch eine Race-Bedingung - eine andere Sitzung kann gleichzeitig eine manuelle Einfügung mit dem gleichen Wert durchführen, den Ihre Funktion findet, und eine der Sitzungen wird einen Fehler erhalten.

Es wäre normalerweise besser, nur die Reihenfolge zu verwenden; Wenn Sie dies jetzt tun oder dies ändern können, wäre eine einmalige Anpassung all Ihrer Sequenzen, die höher als der aktuelle maximale Schlüsselwert ist, einfacher.

+0

Es hat funktioniert. Vielen Dank!! :) – bin

1

Mit execute immediate führen Sie die Anweisung außerhalb des Bereichs der Funktion aus, sodass sie die PLSQL-Variable nicht verwenden kann. Ich würde dies lösen, indem Sie es als eine normale Abfrage ausführen und SELECT INTO oder einen Cursor verwenden, um das Abfrageergebnis abzurufen.

Aber es sollte auch funktionieren, wenn Sie den Wert in die Query-String selbst ersetzen, wie folgt aus:

ändern

'select ''T'' from dual where cnpParmId not in ' || 

in

'select ''T'' from dual where ' || cnpParmId || ' not in ' ||