Frage

Dies ist mein Anwendungsfall:Die Eingabe ist eine Zeichenfolge, die ein Oracle PL/SQL-Anweisung von beliebigen Komplexität.Wir können davon ausgehen, es ist eine einzelne Anweisung (kein Skript).Jetzt, einige bits von dieser input-string geschrieben werden.

E. g.Tabellennamen müssen mit einem Präfix versehen sein, Aggregatfunktionen in der Auswahlliste, die nicht mit einer Spalte ein alias zugewiesen werden soll default:

SELECT SUM(ABS(x.value)), 
TO_CHAR(y.ID,'111,111'),
y.some_col
FROM
tableX x,
(SELECT DISTINCT ID
FROM tableZ z
WHERE ID > 10) y
WHERE
...

wird

SELECT SUM(ABS(x.value)) COL1, 
TO_CHAR(y.ID,'111,111') COL2,
y.some_col
FROM
pref.tableX x,
(SELECT DISTINCT ID, some_col
FROM pref.tableZ z
WHERE ID > 10) y
WHERE
...

(Haftungsausschluss:nur zur Verdeutlichung des Problems, Aussage nicht sinnvoll)

Seit Aggregat-Funktionen können geschachtelt werden und subSELECTs sind ein b_tch, wage ich nicht reguläre Ausdrücke verwenden.Naja, eigentlich habe ich getan und erreicht 80% Erfolg, aber ich muss die restlichen 20%.

Die richtige Vorgehensweise ist, vermute ich, ist die Verwendung von Grammatiken und Parser.Ich fummelte, um mit c++ ANTLR2 (ich weiß zwar nicht viel über Grammatiken und parsing mit Hilfe von solchen).Ich sehe nicht einen einfachen Weg, um die SQL-bits:

list<string> *ssel = theAST.getSubSelectList(); // fantasy land

Könnte jemand vielleicht bieten einige Hinweise, wie "analysieren Experten" betreiben würden dieses Problem?EDIT:Ich bin mit Oracle 9i.

War es hilfreich?

Lösung

Vielleicht können Sie diese verwenden, es änderungen eine select-Anweisung in eine xml-block:

declare
    cl clob;
begin
    dbms_lob.createtemporary (
        cl,
        true
    );
    sys.utl_xml.parsequery (
        user,
        'select e.deptno from emp e where deptno = 10',
        cl
    );
    dbms_output.put_line (cl);
    dbms_lob.freetemporary (cl);
end;
/ 

<QUERY>
  <SELECT>
    <SELECT_LIST>
      <SELECT_LIST_ITEM>
        <COLUMN_REF>
          <SCHEMA>MICHAEL</SCHEMA>
          <TABLE>EMP</TABLE>
          <TABLE_ALIAS>E</TABLE_ALIAS>
          <COLUMN_ALIAS>DEPTNO</COLUMN_ALIAS>
          <COLUMN>DEPTNO</COLUMN>
        </COLUMN_REF>
        ....
        ....
        ....
</QUERY>

Siehe hier: http://forums.oracle.com/forums/thread.jspa?messageID=3693276�

Jetzt ist Sie 'nur' müssen Parsen von xml-block.

Edit1:

Leider habe ich nicht vollständig verstehen, die Bedürfnisse der OP, aber ich hoffe, dass dies helfen kann (Es ist eine andere Art zu Fragen, die 'Namen' der Spalten für Beispiel Abfrage select count(*),max(dummy) from dual):

set serveroutput on

DECLARE
 c       NUMBER;
 d       NUMBER;
 col_cnt PLS_INTEGER;
 f       BOOLEAN;
 rec_tab dbms_sql.desc_tab;
 col_num NUMBER;

PROCEDURE print_rec(rec in dbms_sql.desc_rec) IS
BEGIN
  dbms_output.new_line;
  dbms_output.put_line('col_type = ' || rec.col_type);
  dbms_output.put_line('col_maxlen = ' || rec.col_max_len);
  dbms_output.put_line('col_name = ' || rec.col_name);
  dbms_output.put_line('col_name_len = ' || rec.col_name_len);
  dbms_output.put_line('col_schema_name= ' || rec.col_schema_name);
  dbms_output.put_line('col_schema_name_len= ' || rec.col_schema_name_len);
  dbms_output.put_line('col_precision = ' || rec.col_precision);
  dbms_output.put_line('col_scale = ' || rec.col_scale);
  dbms_output.put('col_null_ok = ');

  IF (rec.col_null_ok) THEN
    dbms_output.put_line('True');
  ELSE
    dbms_output.put_line('False');
  END IF;
END;

BEGIN
  c := dbms_sql.open_cursor; 
  dbms_sql.parse(c,'select count(*),max(dummy) from dual ',dbms_sql.NATIVE); 
  dbms_sql.describe_columns(c, col_cnt, rec_tab);

  for i in rec_tab.first..rec_tab.last loop
    print_rec(rec_tab(i));
  end loop;

  dbms_sql.close_cursor(c);
END;
/

(Siehe hier für mehr info: http://www.psoug.org/reference/dbms_sql.html)

Der OP möchte auch in der Lage zu ändern die schema-name der Tabelle in einer Abfrage.Ich denke, der einfachste sagen zu erzielen, ist eine Abfrage der Tabelle die Namen von user_tables und suchen Sie in der sql-Anweisung für diese Tabelle die Namen und das Präfix Sie oder ein 'alter session set current_schema = ....'.

Andere Tipps

Wenn die Quelle der SQL-Anweisung, Zeichenfolgen sind andere Programmierer, Sie können einfach darauf bestehen, dass die Teile, die Notwendigkeit ändern werden einfach gekennzeichnet durch Besondere escape-Konventionen, z.B., schreiben $TABELLE statt der den Namen der Tabelle, oder $TABLEPREFIX, wo Sie benötigt wird.Dann finden Sie die Plätze, die gepatcht werden müssten erreicht werden kann mit einem Teilstring suchen und ersetzen.

Wenn Sie wirklich müssen, beliebige SQL-Zeichenfolgen und nicht bekommen, Sie gut markiert, Sie brauchen, um irgendwie die SQL-Zeichenfolge analysieren, wie Sie beobachtet haben.Die XML-Lösung ist sicherlich eine Möglichkeit.

Ein anderer Weg ist zu verwenden eine program transformation system.So ein tool analysiert eine Zeichenfolge für eine Sprache, die Instanz, bauen ASTs, durchführen der Analyse und transformation auf ASTs, und dann spuckte eine überarbeitete string.

Die DMS Software Reengineering Toolkit ist ein solches system.Es hat PLSQL-front-end-parser.Und Sie verwenden können das Muster-Regie Transformationen zu erreichen schreibt Sie erscheinen zu müssen.Für Ihr Beispiel mit wählen Sie Elemente aus:

domain PLSQL.
rule use_explicit_column(e: expression):select_item -> select_item
   "\e" -> "\e \column\(\e\)".

Zum Lesen der Regel, Sie müssen verstehen, dass die Sachen in Anführungszeichen steht, abstrakte Bäume, in einigen computer-Sprache, die wir manipulieren wollen.Was die "domain-PLSQL -" Satz sagt, ist, "verwenden der PLSQL-parser", um die Zeichenfolge in Anführungszeichen Inhalte, die, wie er weiß.(DMS hat viele langauge Parser, zum von zu wählen).Die Bedingungen "Ausdruck" und "select_item" sind die grammatischen Konstrukte aus der Sprache von Interesse, z.B., PLSQL in diesem Fall.Finden Sie die railroad-Diagramme in PLSQL-Referenz-Handbuch.Der Schrägstrich stellt escape/meta-Informationen eher als Ziel-Sprache-syntax.

Was die Regel sagt, ist, verwandeln diejenigen, die analysierten Elemente, die select_items das bestehen ausschließlich aus einer Ausdruck \e, durch die Umwandlung in einen select_item aus denselben Ausdruck \e und der entsprechenden Spalte ( \column(\e) ), vermutlich basierend auf der position in der select-Liste Element für die spezifischen Tabelle.Sie würden implementieren Spalte Funktion, dass kann bestimmen die entsprechenden Namen aus der position des Element auswählen.In diesem Beispiel habe ich gewählt, um zu definieren, der die Spalte-Funktion zum akzeptieren der Ausdruck von Interesse als argument;der Ausdruck ist tatsächlich vergangen, als die übereinstimmenden Baum und damit die Spalte-Funktion können Sie bestimmen, wo es in der select_items Liste von Wandern bis die abstract syntax tree.

Diese Regel handhabt nur die Elemente auswählen.Sie möchte hinzufügen, mehr Regeln zu behandeln die verschiedenen anderen Fällen, die von Interesse für Sie.

Was die transformation system bedeutet für Sie:

  • analysieren Sie die Sprache-fragment von Interesse
  • bauen AST
  • lassen Sie musteranschluss nach Orten von Interesse (indem AST pattern-matching) aber mit der Oberfläche syntax der Ziel-Sprache
  • ersetzen Sie abgestimmten Muster durch ein anderes Muster
  • berechnen aritrary Ersatz (als ASTs)
  • regenerieren Quelle text aus dem modifizierten ASTs.

Beim schreiben der Regeln ist nicht immer trivial, es ist das, was erforderlich ist, wenn Ihre problem, ausgewiesen gestellt.

Die XML empfohlene Lösung ist, einen anderen Weg zu bauen, so ASTs.Es muss nicht die schöne Muster passenden Eigenschaften, obwohl Sie möglicherweise in der Lage zu bekommen eine Menge von XSLT.Was ich nicht weiß ist, ob die XML hat der parse-Baum in complete detail;die DMS-parser nicht bieten diese vom design als es ist benötigt, wenn Sie wollen zu tun beliebig Analyse und transformation.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top