![]() |
Datenbank: MySQL • Version: 5 • Zugriff über: UniDAC
UniDac Select & Edit (Anfängerfrage)
Hallo zusammen,
ich teste gerade die UniDAC-Komponenten (wir möchten unsere firmeninterne Applikation (Kommandozeilenprogramm) als Stand-alone exe ohne zusätzliche DLL ausliefern). Der erste Test besteht darin, einen Datensatz einzulesen, ein paar Felder abzuändern und wieder zurückzuschreiben. Ich habe das so gemacht (die try/except-Blöcke habe ich hier weggelassen):
Delphi-Quellcode:
Beim "uniQuery.Post" gibt's dann eine Exception (Fehler in SQL-Statement near "index=3234").
uniConn := TUniConnection.Create(nil);
uniQuery := TUniQuery.Create(nil); try // Datenbankverbindung uniConn.Server := dbHost; uniConn.Port := 3306; uniConn.Username := dbUser; uniConn.Password := dbPassword; uniConn.Database := dbName; uniConn.ProviderName := TMySQLUniProvider.GetProviderName; uniConn.Open; // Abfrage uniQuery.Connection := uniConn; uniQuery.SQL.Text := Format('SELECT * FROM %s WHERE hostname=''%s''',[dbTable, ComputerName]); uniQuery.Open; // Datenbankabfrage durchführen uniQuery.First; // und auf erstem Datensatz positionieren if not uniQuery.Eof then begin stUser := uniQuery.FieldByName('username').AsString; expDate := uniQuery.FieldByName('reset_date').AsDateTime; // Felder aktualisieren uniQuery.Edit; uniQuery.FieldByName('last_update').AsDateTime := Now; uniQuery.Post; end; uniQuery.Close; finally uniConn.Free; uniQuery.Free; end; "index" ist ein AutoIncrement-Feld in der Tabelle und kann natürlich nicht geschrieben werden. Fragen: - Stimmt meine Vorgehensweise prinzipiell mit Edit/Post? - Wie kann man das zum Server geschickte SQL-Statement überprüfen? - Was ist zu tun bzgl. des Fehlers mit "index"? Kann das Feld vor dem Post entfernt werden? Ich weiß, dass es auch bei UniDAC ein Forum gibt - aber die Experten sind nun mal hier... .sundance. |
AW: UniDac Select & Edit (Anfängerfrage)
An deinem Code ist soweit alles richtig.
4 Kleinigkeiten:
Delphi-Quellcode:
// QuotedString statt ''
uniQuery.SQL.Text := Format('SELECT * FROM %s WHERE hostname=%s',[dbTable, QuotedString(ComputerName)]);
Delphi-Quellcode:
Eof nimmt man wenn man durch das Dataset iterieren möchte
uniQuery.Open; // Datenbankabfrage durchführen
// nach einem Open steht die Datenmenge immer auf dem 1. Datensatz (aber nur wenn die Menge zuvor geschlossen war) // uniQuery.First; // und auf erstem Datensatz positionieren - braucht man nicht Um zu prüfen ob überhaupt Datensätze vorhanden sind verwendet man IsEmpty
Delphi-Quellcode:
Beim beschreiben der Felder kann man die kürzere Schreibweise verwenden.
// if not uniQuery.Eof then begin
if not uniQuery.IsEmpty then begin Beim Lesen sollte man es aber die AsXXXXX-Methoden verwenden um eine Ungültige Variantumwandlung Exception zu vermeiden
Delphi-Quellcode:
Jetzt nur zu deinem Problem mit dem Autoincrementfeld "index".
// Felder aktualisieren
uniQuery.Edit; uniQuery['last_update'] := Now; // kürzer und "schöner" (ist aber auch Geschmacksache) uniQuery.FieldByName('last_update').AsDateTime := Now; uniQuery.Post; Die VCL muss wissen dass das Autoincfeld nicht upgedatet werden darf. Prüfe mal welchen Inhalt
Delphi-Quellcode:
hat.
uniQuery.FieldByName('index').ProviderFlags
Notfalls muss man von Hand eingreifen und die Flags ändern. Eigentlich müsste das UniDAC schon richtig machen (alte Version?) |
AW: UniDac Select & Edit (Anfängerfrage)
Hallo sx2008,
vielen Dank für deine Tipps (ist echt deutlich schlanker... Schade, dass die Doku da ein wenig mager ist). Vor dem Aufruf von "Post" haben die ProviderFlag folgenden Inhalt: [pfInUpdate..pfInWhere] (hab's mal auf [pfHidden] gesetzt -> keine Veränderung) Alte Version ist nicht der Fall (ist vom September 2013) .sundance. |
AW: UniDac Select & Edit (Anfängerfrage)
Hallo,
warum nicht in etwa so:
Delphi-Quellcode:
Damit kommt "niemand" auf die Idee, index zu aktualisieren.
uniQuery.SQL.Text := Format('update %s set last_update = %f WHERE hostname = %s',[dbTable,now,QuotedString(ComputerName)]);
uniQuery.ExecSql; Mein Erfahrung aus den letzten "Jahrzehnten" ist, dass das Update einer Tabelle via Query, Edit und Post nicht bei allen Datenbanken immer reibungslos funktioniert. In Deinem Fall versucht die Query (vermutlich) alle mit "Select * from" geholten Spalten per Post in die Datenbank zu schreiben. Sie "weiß" nicht, das index nicht geschrieben werden darf, dies "weiß" nur die Datenbank. Daraus dürfte der auftretende Fehler resultieren. Das direkte Update dürfte auch schneller sein, als erst die Daten zu holen, dann im Programm zu ändern und dann zu schreiben. Mit dem Update ist exakt ein Datenbankzugriff erforderlich. |
AW: UniDac Select & Edit (Anfängerfrage)
Hallo Stephan,
der Gedanke mit
Delphi-Quellcode:
ist mir auch schon durch den Kopf gegangen, und wäre auch bestimmt nicht komplizierter als Edit/Post. Aber im Beispiel ist es nur ein Feld, welches aktualisiert werden muss - in der "echten" Anwendung sind es aber deutlich mehr (5-10) und da wird der "Zusammenbau" des SQL-Statements doch etwas unübersichtlicher.
ExecSQL
Ich habe mittlerweile auch von Devart eine Lösung für das index-Problem erhalten: Zitat:
Delphi-Quellcode:
uniQuery.Options.QuoteNames := True;
Damit funktioniert es problemlos... Aber wahrscheinlich muss ich noch aus einem anderen Grund auf die ExecSQL-Variante ausweichen, um anstelle der Delphi-Funktion
Delphi-Quellcode:
die aktuelle Serverzeit einzutragen (über die mySQL-Funktion NOW()). Leider kann ich mir das vorherige Einlesen hier nicht sparen, weil (in der "echten" Anwendung) einige Felder vor dem Update ausgewertet werden müssen...
Now
.sundance. |
AW: UniDac Select & Edit (Anfängerfrage)
Hallo .sundance.,
stimmt, "index" ist ein reserviertes Wort, da hätte ich auch drauf kommen können :-( Warum sollte ein
Delphi-Quellcode:
komplizierte sein, als ein
uniQuery.SQL.Text := Format('update %s set spalte1 = %s,
spalte2 = %s, ... spalteN = %s WHERE hostname = %s',[dbTable,wert1,wert2,...,wertN,QuotedString(ComputerName)]); uniQuery.ExecSql;
Delphi-Quellcode:
?
uniQuery.Edit;
uniQuery.FieldByName('spalte1').AsString := wert1; uniQuery.FieldByName('spalte2').AsString := wert2; ... uniQuery.FieldByName('spalteN').AsString := wertN; uniQuery.Post; Querys kann man parametrisieren, schau mal nach ParamByName... Könnte dann in etwa so aussehen:
Delphi-Quellcode:
Und auch hier ist dann nur ein schreibender Zugriff auf die Datenbank notwendig und nicht erst lesen und dann schreiben.
uniQuery.SQL.Text := Format('update %s set spalte1 = :spalte1,
spalte2 = :spalt2, ... spalteN = :spalteN WHERE hostname = %s',[dbTable,QuotedString(ComputerName)]); uniQuery.ParamByName('spalte1').AsString := wert1; uniQuery.ParamByName('spalte2').AsString := wert2; ... uniQuery.ParamByName('spalteN').AsString := wertN; uniQuery.ExecSql; |
AW: UniDac Select & Edit (Anfängerfrage)
Zitat:
|
AW: UniDac Select & Edit (Anfängerfrage)
@Frank:
Gute Idee. Hier liegt die Datenbank allerdings gegeben vor, also muss ich mit "index" vorlieb nehmen... Aber beim nächsten Datenbankprojekt soll's dann besser werden. @Stephan: OK, "kompliziert" war nicht der richtige Ausdruck. Was ich meinte war, dass die zeilenweise Zuordnung von Feld und Wert übersichtlicher ist als ein langer SQL-String. Aber das mit "ParameterByName" sieht interessant aus. Werde ich gleich mal probieren. Ach ja, noch was: Wie kann man sicher überprüfen, ob nach einem
Delphi-Quellcode:
bzw.
uniConn.Open
Delphi-Quellcode:
die jeweiligen Aktionen fehlerfrei verlaufen sind? Gibt es da bei UniDAC eine Statusabfrage oder wird im Fehlerfall eine Exception ausgelöst?
uniConn.ExecSQL
Vielen Dank für eure Unterstützung sundance |
AW: UniDac Select & Edit (Anfängerfrage)
Hi,
ein weiterer Vorteil von ParamByName ist, dass man sich um Quotes und die Konvertierung des Datentyps keine Gedanken machen muss. |
AW: UniDac Select & Edit (Anfängerfrage)
Zitat:
Wie würdest Du z.B. ein Feld nennen, dass Teil eines Index ist? Offensichtlich wird gern der Unterschied zwischen Index und Key Constraint vernachlässigt, beides existiert aber technisch völlig unabhängig voneinander und kann auch so eingesetzt werden. D.h. es ist möglich, eine Primärschlüsselspalte ohne Index zu verwenden (macht natürlich wenig Sinn). Es ist auch möglich einen Index anzulegen, der zu keinem Key Konstraint bzw. logischen Fremdschlüssel gehört. Das macht je nach Anwendungsfall schon sehr viel Sinn und ergibt sich u.U. erst in einer späteren Lebensphase der Datenbank (Tuning). Feldnamen sollten primär an der Logik des Datenmodells und am Feldinhalt orientiert sein, nicht an physikalischen Gegebenheiten. Die ändern sich nämlich gern mal und dann kann man mit seinen "Konventionen" ganz schön auf dem Bauch landen. Jedes RDBMS trennt physikalische Optionen (z.B. in der Create Table Anweisung) von den logischen Optionen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:36 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