![]() |
Möglicher Fehler in GetTableName
Hallo,
Der Titel ist jetzt leider nicht gerade der Beste.. Habe folgende SQL: Zitat:
TCustomDADataSet besitzt eine Methode GetTableName die intern PSGetTableName aufruft, welche wiederrum in einigen Fällen die Funktion GetTableNameFromSQLEx aus der Unit Data.DBCommon aufruft. Und diese GetTableNameFromSQLEx-Funktion hat in meinen Augen einen Fehler. Denn GetTableName und somit GetTableNameFromSQLEx liefern bei obiger Query als Ergebnis "TABELLE_INNEN" statt "TABELLE1". In der Funktion selbst wird quasi das erste "FROM" gesucht und der Tabellenname dahinter zurückgegeben. Meine 2 Fragen: 1) Könnt ihr das in eurer Delphi Version reproduzieren (habs mit XE7 probiert) 2) Stimmt ihr mir zu dass das Ergebnis oben falsch ist oder verstehe ich die Funktion nur falsch und TABELLE_INNEN ist zwar nicht das was ich will aber das was rauskommen sollte. |
AW: Möglicher Fehler in GetTableName
Zitat:
Zum Verständnis: Welchen Rückgabewert erwartest Du bei dieser Query?
Code:
Und hier?
select a.Customer
from Tabelle1 a join Tabelle2 b on a.ID = b.ID
Code:
Und hier?
select a.Customer
from Tabelle2 b join Tabelle1 a on a.ID = b.ID
Code:
Und hier?
select a.Customer, b.Info
from Tabelle2 b join Tabelle1 a on a.ID = b.ID
Code:
Nicht falsch verstehen: Ich will nur verstehen, welchen Sinn diese Funktion haben soll.
select *
from Tabelle2 b join Tabelle1 a on a.ID = b.ID |
AW: Möglicher Fehler in GetTableName
Es gibt z.B. Methoden die generieren aus einem SELECT Statement automatisch ein Insert-Statement für die jeweilige Tabelle. Dafür ist das halt nützlich u.a. Daher würde ICH folgende Ergebnisse erwarten:
- Tabelle1 - Tabelle2 - Tabelle2 - Tabelle2 Ob die Methode allerdings auch so gedacht ist weiß ich nicht. Im Prinzip erwarte ich den (ersten) Tabellennamen des äußersten FROM. Die Funktion aus der Unit Data.DBCommon:
Delphi-Quellcode:
function GetTableNameFromSQLEx(const SQL: string; IdOption: IDENTIFIEROption): string;
var Start: PChar; Token: string; SQLToken, CurSection: TSQLToken; begin Result := ''; Start := PChar(SQL); CurSection := stUnknown; repeat SQLToken := NextSQLTokenEx(Start, Token, CurSection, IdOption); if SQLToken in SQLSections then CurSection := SQLToken; until SQLToken in [stEnd, stFrom]; if SQLToken = stFrom then begin repeat SQLToken := NextSQLTokenEx(Start, Token, CurSection, IdOption); if SQLToken in SQLSections then CurSection := SQLToken else // stValue is returned if TableNames contain quote chars. if (SQLToken = stTableName) or (SQLToken = stValue) then begin if AnsiRightStr(Token, 1) = ';' then Token := AnsiLeftStr(Token, Token.Length-1); if AnsiRightStr(Token, 1) = ')' then Token := AnsiLeftStr(Token, Token.Length-1); Result := Trim(Token); while (Start[0] = '.') and not (SQLToken in [stEnd]) do begin SQLToken := NextSqlTokenEx(Start, Token, CurSection, IdOption); Result := Result + '.' + Token; end; Exit; end; until (CurSection <> stFrom) or (SQLToken in [stEnd, stTableName]); end; end; |
AW: Möglicher Fehler in GetTableName
Zitat:
Falls du unbedingt einen Tabellennamen brachst, dann gib ihn doch Deiner Abfrage mit
SQL-Code:
Gruß
select'tabelle1',tabelle1.*,'tabelle2',tabelle2.* etc.
K-H |
AW: Möglicher Fehler in GetTableName
Ok, verstanden (dann wäre eine Antwort zwar nicht korrekt, aber unwichtig).
Man kann bei einer Typ-2-Grammatik keinen nichthierarchischen Parser verwenden. Oder einfacher ausgedrückt: Die Sprache ist rekursiv formuliert (Queries können Queries beinhalten, es gibt Klammerebenen), also muss man einen Satz der Sprache (das 'SQL-Statement') auch rekursiv analysieren. Es reicht natürlich ein Stack, aber der ist ja auch rekursiv. Ob sich das Problem mit RegEx lösen lässt, weiß ich nicht. Rein theoretisch nicht, denn RegEx kann 'eigentlich' nur Typ-3 Grammatiken parsen, aber mit dem ganzen Lookahead-Gedöns und dem bilden von Gruppen wäre es theoretisch denkbar, obwohl... nee. geht nicht (meine Meinung :mrgreen:) Jedenfalls geht es nicht so. Garantiert nicht. Um es richtig zu machen, musst du einen Parser schreiben, der die kompletten SELECT-Syntax implementiert und dann im aufgespannten Syntaxbaum beim 'äußeren' FROM-Knoten nachschauen: Dort hängen dann die JOIN-Operatoren mit den in Frage kommenden Tabellen. Allerdings ist es ja so, dass die Veränderung nicht über eine Tabelle läuft, sondern über viele, d.h. alleine schon das Funktionsresultat "der Tabellenname" ist falsch, es müsste "die Tabellennamen" heißen und pro Feld angegeben werden. Tipp: SQL-Server kann direkt auf einer View Operationen (DELETE, INSERT, UPDATE) ausführen. Andere RDBMS können das vielleicht/vermutlich auch. Wenn als *das* dein Problem ist, packe deine Query in eine View und führe das Update einfach auf der View aus. Ansonsten bin ich persönlich kein Verfechter von 'Ich verstehe die Query und baue Dir ein INSERT draus'. Das geht nämlich manchmal auch in die Hose. Besser ist es, die DML explizit auszuformulieren. Aber vermutlich ist das eh nicht dein Problem. |
AW: Möglicher Fehler in GetTableName
Den ersten Tabellennamen vom äußersten FROM ...
SQL-Code:
Es wird schwierig immer den richtigen Tabellennamen zu treffen und aufzulösen.
select
* from ( select * from tab1 ) Darum ist es auch besser, die Statements eben nicht automatisch generieren zu lassen. Den Aufwand den man damit betreibt um auch wirklich alle Ausnahmen zu berücksichtigen schmeisst man wieder in die Tonne, wenn die nächste noch unberücksichtigte Ausnahme kommt. Irgendwann ist man es leid. Da baue ich mir doch lieber ein Repository und arbeite mit Objekten, oder meinetwegen auch eine DataSet-Factory, die mir die passenden Abfrage-Instanzen liefert. |
AW: Möglicher Fehler in GetTableName
..lieber ein Repository..
Dazu noch der Hinweis, dass selbest das "richtige" finden des Tabellennamens u.U. nicht das Ende der Fahnenstange ist. Werden hier nur Spalten aus der Update Table selektiert, ist vielleicht alles im grünen Bereich, sind aber Werte aus anderen Tabellen in den Ausgabespalten dabei(soll ja vorkommen), dann kann man die nicht updaten, zumindest nicht auf Basis einer Update Table. Im Repository würde man also nicht nur die Table, sondern vielleicht auch die Spalten mitverwalten. |
AW: Möglicher Fehler in GetTableName
Zitat:
Meine Repositories sehen ungefähr so aus
Delphi-Quellcode:
Das Repository weiß, wo die Informationen gespeichert werden und eben auch, wo es die Informationen wieder holen kann (da wo man auch speichert?). Das Repository hat dann x Abfrage-Objekte und leitet die Anforderungen durch diese hindurch.
type
TFooId = type Integer; TFooIdHelper = record helper for TFooId const null = 0; end; TFoo = class public constructor Create( Id : TFooId; const Title : string ); property Id : TFooId read Fid; property Title : string read FTitle; end; IFooRepository = interface function Get( FooId : TFooId; out Foo : TFoo ) : Boolean; function GetAll : TArray<TFooId>; function Store( Foo : TFoo; Dispose : Boolean = False ) : Boolean; function NextFooId : TFooId; end; |
AW: Möglicher Fehler in GetTableName
Leute ihr driftet total ab.
Es ist jetzt total egal ob man sich irgendwelche Statements generieren lassen sollte oder nicht oder welche Alternativen es dazu gibt. Die Frage ist: Ist das ein Fehler in der RTL? Sollte diese Funktion in dem von mir genannten Fall nicht "TABELLE1" statt "TABELLE_INNEN" zurückgeben? Alles andere ist vollkommen irrelevant. |
AW: Möglicher Fehler in GetTableName
Zitat:
Bei FireDAC ist das zumindest so gelöst, daß man über UpdateOptions.UpdateTableName den Namen angeben kann und sogar muss, wenn "FireDAC den Namen der zu aktualisierenden Tabelle nicht korrekt aus der Abfrage abrufen kann." Dabei ist es ziemlich unerheblich, warum FireDAC das nicht kann, weil der entsprechende Algorithmus vielleicht nur für simple SELECT-Anweisungen funktioniert. Ich habe jetzt die erwähnten DA-Komponenten nicht greifbar, aber vielleicht gibt es da ja einen ähnlichen Mechanismus. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz