Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Firebird / UniDac - Insert über Query? (https://www.delphipraxis.net/147488-firebird-unidac-insert-ueber-query.html)

moelski 9. Feb 2010 21:30

Datenbank: Firebird • Version: 2.5 • Zugriff über: ÛniDac

Firebird / UniDac - Insert über Query?
 
Moin !

Ich versuche gerade mittels UniDac in eine Tabelle (Firebird) einen Datensatz einzutragen.
Habe mir dazu ein TUniQuery hergenommen. Und dann auf einen Button folgenden Code gelegt:
Delphi-Quellcode:
  Query.Active := True;
  Query.SQLInsert.Add('INSERT Into Demo (demo.wert1) VALUES (12)');
  Query.Insert;
  Query.Post;
Will aber so nicht. Kriege immer die Meldung dass das SQL Statement nicht leer sein darf.

Wenn ich Query.SQL.Add nutze, dann sagt er mir das kein Return kommt vom Query ...

Kann mich da mal gerade einer "einnorden" :D ?

mkinzler 9. Feb 2010 21:35

Re: Firebird / UniDac - Insert über Query?
 
Entweder
Delphi-Quellcode:
  Query.Close;
  Query.SQL.Text := 'select * from demo where 1=0;';
  Query.Open;
  Query.SQLInsert.Text := 'INSERT Into Demo (demo.wert1) VALUES (12);';
  Query.Insert;
  Query.Post;
oder
Delphi-Quellcode:
  Query.SQL.Text := 'INSERT Into Demo (demo.wert1) VALUES (12);';
  Query.ExecSQL:

moelski 21. Feb 2010 06:38

Re: Firebird / UniDac - Insert über Query?
 
Moin !

Erstmal danke mkinzler !!

Hätte da aber nochmal ne Frage. Ich komme mit dem UniDac noch nicht ganz klar. Und ich denke es liegt daran, das ich derzeit meist ADO verwendet habe. Und dort hat man eine DataSet Componente. Die ist einfacher zu handhaben als ein Query (zumindest für mich im moment ;) ).

Was ich auch hinbekomme ist ein Append mit Query:
Delphi-Quellcode:
  Query.Close;
  Query.SQL.Text := 'select * from DataStore where 1=0;';
  Query.Active := True;
  Query.Edit;
  Query.FieldByName('ID').AsInteger := 12;
  Query.FieldByName('FIELD1').AsWideString := 'Hallo';
  Query.append;
Was nicht geht ist eine Max Abfrage:
Delphi-Quellcode:
    Query.Close;
    Query.SQL.Text := 'Select max(ID) from DataStore;';
    Query.Active := True;
Da kriege ich den Fehler dass das Feld ID nicht gefunden werden kann.
erstaunlich ist aber, das ich das im Queryeditor mit genau dem Statement problemlos auslesen kann :gruebel:

Und könnte mir jemand sagen wie ich das mit einem AutoInc Feld mache?
Ich habe in meiner Datenbank einen entsprechenden Trigger definiert und einen Generator:
TRIG_AUTOINCID
SQL-Code:
AS
BEGIN
if (NEW.ID is NULL) then NEW.ID = GEN_ID(AUTOINCID, 1);
END
Der AutoInc funktioiert auch wenn ich mit einem DB admin Tool einen neuen Datensatz anlege.

Doch wie kann ich den Trigger mittels UniDac nutzen und auch beim anlegen gleich die generierte ID zurück bekommen?

RWarnecke 21. Feb 2010 07:43

Re: Firebird / UniDac - Insert über Query?
 
Den nächsten Wert eines Triggers kannst Du mit dem folgenden SQL-Befehl Abfragen
SQL-Code:
SELECT NEXT VALUE FOR <generator_name> FROM RDB$DATABASE;
Im Feld Gen_ID findest Du dann den nächsten Wert vom Trigger.

Edit2 : Aber aufpassen, wenn der SELECT-Befehl ausgeführt wird, dann wird der Trigger angestossen und um eins erhöht. Ich habe dann nochmal den Befehl
SQL-Code:
ALTER SEQUENCE <generator_name> RESTART WITH <ergebnis aus select - 1>;
ausgeführt, damit der Trigger wieder auf dem alten Wert steht.

Eine Tabelle incl. AutoInc_Feld erstelle ich so :
SQL-Code:
CREATE TABLE Adresse (
   AutoInd INTEGER,
   Feld1 INTEGER,
   Feld2 INTEGER,
   Feld3 CHAR(50),
   Feld4 CHAR(50)
);

CREATE GENERATOR GEN_Adresse_ID;
SET TERM ^ ;

create trigger Adresse_bi for Adresse
active before insert position 0 
as
begin
if (new.AutoInd is null) then
new.AutoInd = gen_id(gen_Adresse_id,1);
end


SET TERM ; ^ 

SET TERM ^ ;

create procedure sp_gen_Adresse_id
returns (AutoInd integer)
as
begin
AutoInd = gen_id(gen_Adresse_id, 1);
suspend;
end


SET TERM ; ^
Edit1: Fehler in den BBCodes bereinigt.

moelski 21. Feb 2010 07:54

Re: Firebird / UniDac - Insert über Query?
 
Moin Rolf,

Danke für den Tip. werde ich gleich mal testen.
Aber könnte man nicht auch "procedure sp_gen_Adresse_id" verwenden?
Die ist zwar in deinem Create dabei, wird aber ansonsten nie genutzt. :gruebel:

Und hast du eine Idee warum das nicht klappt:
Delphi-Quellcode:
Query.Close;
Query.SQL.Text := 'Select max(ID) from DataStore;';
Query.Active := True;
Obwohl das Feld ID definitiv vorhanden ist (ist der Primary Key).

RWarnecke 21. Feb 2010 08:27

Re: Firebird / UniDac - Insert über Query?
 
Delphi-Quellcode:
Query.Close;
Query.SQL.Text := 'Select max(ID) from DataStore;';
Query.Open;
Probiere es mal so. Dann kannst Du über Query.Fields[0].AsInteger oder über Query.FieldByName('MAX').AsInteger den Wert abfragen.

moelski 21. Feb 2010 08:40

Re: Firebird / UniDac - Insert über Query?
 
Moin !

"mit der Hand vor den kopf hau" ....

Zitat:

Query.FieldByName('MAX').AsInteger
Und ich versuche die ganze Zeit ID abzufragen. Oh Mann. Da kann ich ja Tage suchen :)


Ok. Kann mir jetzt noch jemand einen Tip geben wie ich einen Strem in einem Blob ablege?

moelski 21. Feb 2010 08:45

Re: Firebird / UniDac - Insert über Query?
 
Moin !

Habs gefunden mit dem BLOB:

Delphi-Quellcode:
begin
  Query.SQL.Text := 'SELECT * FROM DataStore WHERE ID=12';
  Query.Open;
  Query.Edit;
  Stream := Query.CreateBlobStream(Query.FieldByName('MEMO'), bmWrite);
  try
    Memo1.Lines.SaveToStream(Stream);
  finally
    Stream.Free;
  end;
  Query.Post;
end;

norwegen60 5. Apr 2010 11:43

Re: Firebird / UniDac - Insert über Query?
 
Hallo zusammen,

mir geht es gerade ähnlich wie moelski. Ich habe zuerst von Paradox auf MsSQL umgestellt und teste jetzt Firebird. Beim Transferieren einer Paradox-Tabelle zu Firebird wurde automatisch u.a. ein Trigger
SQL-Code:
SET TERM ^ ;
ALTER TRIGGER TRIG_DIAS_BI INACTIVE
BEFORE INSERT POSITION 0
AS BEGIN
      IF(NEW."ID" IS NULL) THEN NEW."ID" = GEN_ID("GEN_DIAS_ID",1);
    END^
SET TERM ; ^
angelegt. Der funktioniert innerhalb FlameRobin auch einwandfrei. Wenn ich jetzt aber in einer Delphianwendung per UniDac TUniQuerry.Insert einen Datensatz anlege und per TUniQuerry.post speichere, kommt die Fehlermeldung dass das Feld ID keinen Wert hat (ID = primarykey = integer = not null). Bei Verwendung von MsSQL passiert das nicht. Wie kann/muss ich das Programm jetzt aufbauen, dass es sowohl mit Firebird als auch MsSQL läuft. Der Ansatz
Zitat:

Zitat von RWarnecke
Den nächsten Wert eines Triggers kannst Du mit dem folgenden SQL-Befehl Abfragen
SQL-Code:
SELECT NEXT VALUE FOR <generator_name> FROM RDB$DATABASE;
Im Feld Gen_ID findest Du dann den nächsten Wert vom Trigger.

ist bei MsSQL nicht notwendig. Und den Zusatz
Zitat:

Zitat von RWarnecke
Edit2 : Aber aufpassen, wenn der SELECT-Befehl ausgeführt wird, dann wird der Trigger angestossen und um eins erhöht. Ich habe dann nochmal den Befehl
SQL-Code:
ALTER SEQUENCE &lt;generator_name&gt; RESTART WITH &lt;ergebnis aus select - 1&gt;;
ausgeführt, damit der Trigger wieder auf dem alten Wert steht.

verstehe ich auch nicht ganz. Ich möchte ja, dass der neue Wert gesperrt ist. Nicht dass ein anderer Anwender ihn auch vergibt.
Wie muss ich das ganze gestalten, dass ich den Code für alle Tabellen einer DB verwenden kann ohne mich jedes mal aufs neue damit auseinanderzusetzen.
Eiegntlich fehlt mir nur so eine Art Refresh, der nach dem Insert-Befehl mein ID-Feld mit dem generierten Wert belegt. Und der so, dass er sowohl mit MsSQL und Firebird arbeitet.

Mein Hauptjob ist die Steuerung komplexer Maschinen und die DB nur ein notwendiges Übel. :cry:


Viele Dank für jegliche Unterstützung
Gerd

mkinzler 5. Apr 2010 17:37

Re: Firebird / UniDac - Insert über Query?
 
Lass mal die Abfrage auf NULL im Trigger weg, dann wirkt der autoinc in jedem Fall. Sonst müsste das Feld NULL oder nicht belegt sein und darf auch keinen Standardwert haben

daywalker9 5. Apr 2010 17:41

Re: Firebird / UniDac - Insert über Query?
 
Oder frag auf 0 ab.
SQL-Code:
New."ID" = 0
Edit: ich meine frage neben NULL auch 0 ab.

mkinzler 5. Apr 2010 17:49

Re: Firebird / UniDac - Insert über Query?
 
Dann muss es aber auch 0 sein

norwegen60 5. Apr 2010 20:07

Re: Firebird / UniDac - Insert über Query?
 
Schön, dass an Ostern auch noch jemand schafft

Leider haben mir die Tips nicht weiter geholfen ich habe beides probiert:
SQL-Code:
BEGIN
  NEW."ID" = GEN_ID("GEN_DIAS_ID",1);
END
und
SQL-Code:
BEGIN
  IF ((NEW."ID" IS NULL) or (NEW."ID" = 0)) THEN NEW."ID" = GEN_ID("GEN_DIAS_ID",1);
END
und beide male blieb es bei der Meldung "Feld 'ID' muss einen Wert haben". Mir ist noch nicht ganz klar, wie dem Feld ID der neu generierte Wert zugewiesen wird, bzw. wie meine UniQuerry den Wert bekommt und bei Post auch mit abspeichern kann. Denn so einfach wie bei Paradox und MsSQL scheint es nicht zu funktionieren.

mkinzler 5. Apr 2010 20:09

Re: Firebird / UniDac - Insert über Query?
 
SQL-Code:
BEGIN
  NEW.ID = GEN_ID('GEN_DIAS_ID',1);
END

norwegen60 5. Apr 2010 20:19

Re: Firebird / UniDac - Insert über Query?
 
Nein, leider nicht. FlameRobin verwendet ". Bei ' gibts ne Fehlermeldung. Und wenn ich direkt in FlameERobin einen neuen Satz anlege, bekomme ich ja auch eine neue ID. Nur aus Delphi raus funktioniert es nicht. Irgendwie bekommt die UniQuerry die neue ID nicht mit. Am liebsten wäre es mir sowieso, ich könnte diese auch gleich in einem Edit- oder Label-Feld anzeigen

mkinzler 5. Apr 2010 20:24

Re: Firebird / UniDac - Insert über Query?
 
Wie sind die Felder deklariert ( case sensitiv)?
Wie rufst du den Insert auf?
Zitat:

Am liebsten wäre es mir sowieso, ich könnte diese auch gleich in einem Edit- oder Label-Feld anzeigen
Du könntest den Wert auch in einem Select vorher holen
SQL-Code:
select GEN_ID( ...
oder die Funktionlität der Komponente verwenden
Den Wert kanst du dir durch das returning zurückgeben lassen:
SQL-Code:
insert .... into ... returning id;

norwegen60 5. Apr 2010 20:53

Re: Firebird / UniDac - Insert über Query?
 
Wenn ich einen neuen Satz anlegen will rufe ich
Delphi-Quellcode:
UniQuery.Insert
auf.
Die Werte selber werden direkt in dbEdit-Feldern mit Werten gefüllt.
Zum sichern rufe ich
Delphi-Quellcode:
UniQuery.post
auf.
Die UniQuerry selber ist mit dem SQL
SQL-Code:
select * from dias order by nr
definiert.
In der DB selber habe ich keine Casesensitivtät deklariert sondern ich arbeite bei der Abfrage mit upper....

Den SQL-Aufbau
SQL-Code:
SELECT gen_ID(Gen_Dias_ID,0) FROM DIAS
habe ich ja noch gefunden, aber wie stehts hier mit der Kompatibilität zu MsSQL? Ist das mit Firebird "für einen Anfänger" wirklich so kompliziert? Habe ich eventuell in UniQuery vergessen irgendeinen Parameter zu setzen? Die verwende ich nämlich auch zum ersten mal.

Als ich durch die diversen Foren bin musste ich feststellen dass einige das Problem mit der Meldung "Feld ID muss einen Wert haben" aber leider fand ich nirgends eine Lösung.

mkinzler 5. Apr 2010 21:06

Re: Firebird / UniDac - Insert über Query?
 
Wie sieht Query.InsertSQL aus?
Zitat:

In der DB selber habe ich keine Casesensitivtät deklariert sondern ich arbeite bei der Abfrage mit upper....
Wenn du die Feldnamen aber mit "" angibst wird es casesensitiv (Wenn bei der Anlage angegeben für immer: id ist dann was anderes als Id oder ID)
Mit
SQL-Code:
select GEN_ID( GEN_DIAS_ID,1) from RDB$DATABASE;
kanst du den nächsten Wert holen, dieser ist dann reserviert (GEN_ID ist eine Semaphorenfunktion)
Du kannst natürlich auch die Funktionalität der Komponente verwenden
Zitat:

Wie muss ich das ganze gestalten, dass ich den Code für alle Tabellen einer DB verwenden kann ohne mich jedes mal aufs neue damit auseinanderzusetzen.
Für alle Tabellen den gleichen Generator(Sequenz) verwenden
Zitat:

Ist das mit Firebird "für einen Anfänger" wirklich so kompliziert?
Eigentlich nicht
Zitat:

Habe ich eventuell in UniQuery vergessen irgendeinen Parameter zu setzen?
Ich vermute eher es liegt an der Groß-/Kleinunterscheisung

norwegen60 5. Apr 2010 21:57

Re: Firebird / UniDac - Insert über Query?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Markus,

wenn das eigentlich nicht so kompliziert ist, komme ich irgendwie nicht weiter. Ich habe jetzt eine ganz einfache Anwendung mit D2010 und UniDac erstellt die auf die Firebird-Beispiel-DB Employees zugreift. Da habe ich genau das Problem, das ich auch bei meiner DB habe. Ich habe das Beispiel im Anhang als ZIP. Wäre es möglich, dass du dir das mal anschaust.

Gibt es eigentlich auch eine Möglichkeit, UniConnection vom Ablagepfad der DB unabhängig zu machen, im Grunde so wie mit den Alias bei Paradox?

Vielen Dank
Gerd

mkinzler 5. Apr 2010 22:00

Re: Firebird / UniDac - Insert über Query?
 
Es fehlt das .InsertSQL

scrat1979 5. Apr 2010 22:22

Re: Firebird / UniDac - Insert über Query?
 
Zitat:

Zitat von norwegen60
Gibt es eigentlich auch eine Möglichkeit, UniConnection vom Ablagepfad der DB unabhängig zu machen, im Grunde so wie mit den Alias bei Paradox?

Vielen Dank
Gerd

Im Verzeichnis des Firebird-Servers gibt es eine Datei namens "aliases.conf". Das ist der Schlüssel zum Erfolg. Dann kannst du die Datenbank mittels dem angegebenen DB-Alias ansprechen, unabhängig davon, wo sich die Datei physikalisch befindet.

norwegen60 5. Apr 2010 22:58

Re: Firebird / UniDac - Insert über Query?
 
Und was ist .InsertSQL? Diesen Aufruf gibt es bei UniQuery nicht und auch sonst habe ich von dem noch nie gehört.

Was jetzt nach langem Probieren aber funktioniert, ist
Delphi-Quellcode:
UniQuery.Options.RequiredFields := false  { keine Fehlermeldung mehr "Feld ID muss einen Wert ..."    }
UniQuery.DMLrefresh := true               { getriggerter Wert von ID wird nach post zurückgegeben }
und als ich nach RequiredFields gegoogelt habe, fand ich dass schon mal jemand so ein Problem mit Access und UniDac gehabt hat. Sieht also so aus, als wenn es ein Problem von uniDac wäre.
Zitat:

eine Datei namens "aliases.conf"
Die werde ich mir morgen mal anschauen

mkinzler 5. Apr 2010 23:01

Re: Firebird / UniDac - Insert über Query?
 
Zitat:

Und was ist .InsertSQL? Diesen Aufruf gibt es bei UniQuery nicht und auch sonst habe ich von dem noch nie gehört.
In dieser Eigenschaft wird die Abfrage festgelegt, welche bei .Insert() ausgeführt wird.
Ist eine Eigenschaft eines TDataSets


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:50 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