Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Bekomme kein INSERT mit FB und IBDAC hin!?! (https://www.delphipraxis.net/146048-bekomme-kein-insert-mit-fb-und-ibdac-hin.html)

scrat1979 12. Jan 2010 21:03

Datenbank: Firebird • Version: 2.1 • Zugriff über: IBDAC neueste Version

Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Hallo,

ich werd' noch verrückt. Folgende Anweisung wird mit einem Fehler abgewiesen (Token unknown). Hab auch schon
TIBCSQL durch TIBCQuery ersetzt, gleiches Problem... Exakt die gleiche Abfrage funktioniert unter einer Firebird-GUI einwandfrei.
Die Schleife (to 31) sowie das entsprechende Datum habe ich zu Demonstrationszwecken in einen festen Wert geändert.

Delphi-Quellcode:
procedure TPlanner.PCreateMonthInDB(Month: Byte; Year: Integer);
VAR TMPSQL : TIBCSQL;
    i     : Integer;
begin
  (* Kalender in Datenbank erstellen *)
  TMPSQL := TIBCSQL.Create(nil);

  for I := 1 to 31 do begin
    TMPSQL.SQL.Add('INSERT INTO TBLCALENDAR(ISHOLIDAY,DATUM) VALUES(0,''13.07.2010'');');
  end;
  TMPSQL.AutoCommit := True;
  TMPSQL.Execute;

   (* Abfrage freigeben *)
  TMPSQL.Free;
end;
Meine Tabelle sieht so aus:

SQL-Code:
CREATE TABLE TBLCALENDAR (
  ID INTEGER NOT NULL,
  DATUM DATE NOT NULL,
  ANWESEND SMALLINT,
  BEREITSCHAFT SMALLINT,
  NOTARZT SMALLINT,
  ISHOLIDAY SMALLINT DEFAULT 0 NOT NULL);


ALTER TABLE TBLCALENDAR ADD PRIMARY KEY (ID);


SET TERM ^ ;

CREATE TRIGGER BI_TBLCALENDAR_ID FOR TBLCALENDAR
ACTIVE BEFORE INSERT
POSITION 0
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
      NEW.ID = GEN_ID(TBLCALENDAR_ID_GEN, 1);
END^

SET TERM ; ^
Ich greife über Firebird embedded darauf zu, Verbindung und auch Abfragen funktionieren tadellos :(

Danke für Eure Hilfe!

SCRaT

mkinzler 12. Jan 2010 21:19

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Ich würde es mit einer parametrisierten Abfrage veruchen.

RWarnecke 12. Jan 2010 21:19

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Probiere es mal so :
Delphi-Quellcode:
procedure TPlanner.PCreateMonthInDB(Month: Byte; Year: Integer);
VAR TMPSQL : TIBCSQL;
    i     : Integer;
begin
  (* Kalender in Datenbank erstellen *)
  TMPSQL := TIBCSQL.Create(nil);

  for I := 1 to 31 do begin
    TMPSQL.SQL.Add('INSERT INTO TBLCALENDAR(ISHOLIDAY,DATUM) VALUES(:Holiday, :Holidaydatum);');
    TMPSQL.ParamByName('Holiday').AsInteger := 0;
    TMPSQL.ParamByName('Holidaydatum').AsDateTime := StrToDateTime('13.07.2010');
  end;
  TMPSQL.AutoCommit := True;
  TMPSQL.Execute;

   (* Abfrage freigeben *)
  TMPSQL.Free;
end;

scrat1979 12. Jan 2010 21:22

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Delphi-Quellcode:
 [...]
   for I := 1 to 31 do begin
    TMPSQL.SQL.Add('INSERT INTO TBLCALENDAR(ISHOLIDAY,DATUM) VALUES(:Test1,:Test2);');
  end;
  TMPSQL.ParamByName('Test1').AsInteger := 0;
  TMPSQL.ParamByName('Test2').AsDate := Now;
 [...]
Leider dasselbe Problem...

mkinzler 12. Jan 2010 21:23

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Noch besser:
Delphi-Quellcode:
  TMPSQL.SQL.Text := 'INSERT INTO TBLCALENDAR(ISHOLIDAY,DATUM) VALUES(:Holiday, :Holidaydatum);';
  TMPSQL.AutoCommit := True;

  for I := 1 to 31 do
  begin
    TMPSQL.ParamByName('Holiday').AsInteger := 0;
    TMPSQL.ParamByName('Holidaydatum').AsDateTime := StrToDateTime('13.07.2010');
    TMPSQL.Execute;
  end;

scrat1979 12. Jan 2010 21:28

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Vielen Dank für Eure Hilfe, es hat geklappt!! :cheers:

Aber warum MUSS(?) man parametisierte Abfragen benutzen? WARUM funktioniert mein 1. Vorschlag nicht, rein formal ist er doch ok, oder?

mkinzler 12. Jan 2010 21:31

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Um ein Skript auszuführen musst du temporär das Termsymbol (SET TERM) ändern, so dass das Ende eines Befehls und das Ende des Skriptes unterschieden werden kann

scrat1979 12. Jan 2010 21:33

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Werd ich mir mal anschauen...

Gab noch eine kurze Schrecksekunde, die Tabelle war trotz erfolgrechem Insert leer, ein XXXConnection.Commit; hat aber geholfen. Warum muss ich denn das nochmals committen, wenn ich AutoCommit auf True stehen habe? (Ja, bei der Connection steht es auf False...)

sx2008 12. Jan 2010 21:37

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Zu deiner Tabellenstruktur:
Du solltest das Feld ID ganz weglassen und stattdessen das Feld DATUM zum Primärschlüssel machen.
Dann sparst du dir den Trigger, gewinnst mehr Leistung und ausserdem darf es ja pro Datum nur einen Datensatz geben.

scrat1979 12. Jan 2010 21:41

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Zitat:

Zitat von sx2008
Zu deiner Tabellenstruktur:
Du solltest das Feld ID ganz weglassen und stattdessen das Feld DATUM zum Primärschlüssel machen.
Dann sparst du dir den Trigger, gewinnst mehr Leistung und ausserdem darf es ja pro Datum nur einen Datensatz geben.

Hast Recht, ich werde mir das mal anschauen und nach Möglichkeit so machen! Danke für den Tip!

mkinzler 12. Jan 2010 21:42

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Zitat:

Du solltest das Feld ID ganz weglassen und stattdessen das Feld DATUM zum Primärschlüssel machen.
Ist aber auch eine Frag der Philosopie, ob man "Nutzfelder" zum PK macht onder künstliche Schlüssel verwendet

hoika 13. Jan 2010 07:12

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Hallo,

zu deiner Ausgangsfrage, warum es nicht klappt.

Delphi-Quellcode:
  TMPSQL := TIBCSQL.Create(nil);

  for I := 1 to 31 do
  begin
    TMPSQL.SQL.Add('INSERT INTO TBLCALENDAR(ISHOLIDAY,DATUM) VALUES(0,''13.07.2010'');');
  end;
31 mal wird insert into als Befehl eingetragen

Delphi-Quellcode:
 
  TMPSQL.AutoCommit := True;
  TMPSQL.Execute;
Jetzt wird der Code einmal zum Server geschickt.
Der sieht jetzt also folgendes

INSERT INTO TBLCALENDAR(ISHOLIDAY,DATUM) VALUES(0,''13.07.2010'');INSERT INTO TBLCALENDAR(ISHOLIDAY,DATUM) VALUES(0,''13.07.2010'');
INSERT INTO TBLCALENDAR(ISHOLIDAY,DATUM) VALUES(0,''13.07.2010'')

Und das waren nur 3 der 31.

Firebird kann im Untershcied zu MS-SQL immer nur einen Befehl ausführen
(es sei denn, man benutzt irgendeine Script-Komponente).

Durch das Umbauen auf die Parameter ist das TMPSQL.Execute;
mit in die For-Schleife gerutscht.
Somit wird der Befehl auch korrekt 31 mal ausgeführt.

Das war ja auch der ursprüngliche Plan ... ;)


Zum Ändern der Tabellen-Struktur:
Warum soll das bei Firebird mehr Leistung bringen,
vom Trigger abgesehen ?
Index ist Index (bei Firebird zumindestens)

Ich würde das so lassen, falls später mal Replikation ein Thema ist,
ist der künstliche Schlüsel ID ideal.

Heiko

RWarnecke 13. Jan 2010 07:44

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Zitat:

Zitat von scrat1979
Aber warum MUSS(?) man parametisierte Abfragen benutzen?

Bei der Parametisierung brauchst Du nicht auf die Formatierung in der SQL-Anweisung zu achten, ob Du jetzt zum Beispiel ein Hochkomma schreiben musst oder nicht.

Ein Beispiel :
Delphi-Quellcode:
Query.SQL.Add('INSERT INTO TBLCALENDAR(ISHOLIDAY, Reiseziel, Startflughafen) VALUES(0,''''Hawaii'''', ''''Frankfurt'''');');
Wenn Du jetzt noch mehrere solcher Felder hast, tust Du Dich schwer den kompletten SQL richtig vernüpftig zu lesen. Jetzt gibt es zwei Varianten, wie man das ganze etwas überischtlicher gestalten kann.

1. Möglichkeit:
Hier muss ich aber wieder auf die Formatierung in der SQL-Anweisung achten. Ich ersetze die vier Hochkommas durch QuotedStr. Das ganze sieht dann so aus :
Delphi-Quellcode:
Query.SQL.Add('INSERT INTO TBLCALENDAR(ISHOLIDAY, Reiseziel, Startflughafen) VALUES(0,' + QuotedStr('Hawaii') + ', ' + QuotedStr('Frankfurt') + ');');
Das ganze ist zwar schon besser zu lesen und übersichtlicher, aber den kompletten Insert-Befehl kann ich nicht erkennen.

2. Möglichkeit:
Die Werte, die ich über Variablen oder Fest in den SQL-Befehl einfügen will, übergebe ich mit Parametern. Das ganze sieht dann so aus :
Delphi-Quellcode:
Query.SQL.Add('INSERT INTO TBLCALENDAR(IsHoliday, Reiseziel, Startflughafen) VALUES (:IsHoliday, :Reiseziel, :StartFlughafen);');
Query.SQL.ParamByName('IsHoliday').AsInteger := 0;
Query.SQL.ParamByName('Reiseziel').AsString := 'Hawaii';
Query.SQL.ParamByName('StartFlughafen').AsString := 'Frankfurt';
Hier sehe ich einwandfrei den SQL-Befehl und weiss was er macht. In den Zeilen darunter sehe ich dann die übergebenen Parameter. Was auch der Übersichtlichkeit dient. Ein weiterer Vorteil ist, dass ich jetzt die Query nehmen kann und hier immer nur noch die Parameter übergebe und dann den SQL-Befehl ausführen kann ohne jedes mal überlegen zu müssen, was muss ich wohin schreiben.

Bernhard Geyer 13. Jan 2010 07:47

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Zitat:

Zitat von scrat1979
Aber warum MUSS(?) man parametisierte Abfragen benutzen? WARUM funktioniert mein 1. Vorschlag nicht, rein formal ist er doch ok, oder?

Datumsangaben sind im SQL-String immer problematisch, da je nach Server(konfiguration) das ISO/Deutsche/US/EN oder was weiß ich Format erwartet wird. Bei MS Access wird teilweise je nach Zugriffsweg auch ein # am Anfang und Ende der Datumsangabe benötigt. Bei parametrisierten Abfragen treten diese Probleme nicht auf da hier auf jedenfall das richtige Format bei verwendung von "AsDatetime" ankommt.

Und Probleme mit SQL-Injection bekommst du auch keine.

sx2008 14. Jan 2010 03:18

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Zitat:

Zitat von hoika
Zum Ändern der Tabellen-Struktur:
Warum soll das bei Firebird mehr Leistung bringen,
vom Trigger abgesehen ?
Index ist Index (bei Firebird zumindestens)

Das Feld DATUM braucht einen Unique Index, denn es muss verhindert werden, dass man mehrfach das gleiche Datum eintragen kann.
Ohne das Feld ID spart man sich einen weiteren Index (und den Trigger).
Die Tabelle ist kleiner und benötigt so weniger Resourcen.
Wie mkinzler gesagt hat ist das natürlich auch eine Frage der Philosopie.
Wenn man aber einen eindeutigen natürlichen Primärschlüsselkandidaten findet (hier das DATUM), dann sollte man ihn auch benützen.

Also mein Verständnis von Primärschlüsseln ist so:
Gibt es einen natürlichen Primärschlüsselkandidaten bestehend aus nur einem Feld?
Falls ja dann benützen.
Wenn zwei oder mehr Felder benötigt werden um einen Primärschlüssel zu bilden, dann sollte man einen künstlichen Schlüssel einführen.
Das gilt auch, wenn das potentielle Primärschlüsselfeld sehr lang ist.
Wenn die Möglichkeit besteht, dass der Inhalt des Primärschlüsselfelds später geändert wird, dann sollte man auch einen künstlichen Schlüssel bevorzugen. (Beispiel)

hoika 14. Jan 2010 07:03

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Hallo,

Zitat:

Wenn die Möglichkeit besteht, dass der Inhalt des Primärschlüsselfelds später geändert wird, dann sollte man auch einen künstlichen Schlüssel bevorzugen.
Korrekt.

Bsp. Kundennummer

Kunde sagte, die sind immer eindeutig -> Prim Key

2 Jahre später will er, dass das erweitert wirrd
um ein neues 2. Feld (z.B. Kunden-Nr. / Niederlassung).

Man kann so viel vordenken, wie mn will,
es kommt immer anders ;)

Ausserdem werden Prim.-Keys oft auch als ForeignKeys verwendet,
im Fall des Kunden müßte man jetzt an der ganzen DB rumschrauben.


Sch... of die paar Bytes des Integer ;)


Heiko

scrat1979 14. Jan 2010 07:50

Re: Bekomme kein INSERT mit FB und IBDAC hin!?!
 
Ich danke Euch für Eure ausführlichen Erläuterungen!! Vorerst bleibe ich mal bei meinem "künstlichen" Schlüssel. Ein neuer Plan (=Aufrufen des Triggers) wird nur 1x im Monat erstellt, ich denke, damit kann man gut leben :)

SCRAT


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