Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Insert SQL (https://www.delphipraxis.net/6098-insert-sql.html)

Hansa 29. Jun 2003 13:44


Insert SQL
 
Hi,

ich komme mit dem insert einfach nicht klar. Um überhaupt etwas in der DB sehen zu können habe ich kurzerhand folgendes probiert:

Code:
DS.Close;
DS.UpdateSQL.Text := 'INSERT INTO LAGER (MENGE) VALUES (11)';
DS.Open;
Da scheint aber fast alles verkehrt zu sein. 8) Aber es kommt keine Fehlermeldung. Für die ID habe ich einen Trigger, würde das so gehen ?

r_kerber 29. Jun 2003 14:02

Wenn Du mit TUpdateSQL ein INSERT-Statement an dei DB schicken willst, dann mußt Du das Statement in die Eigenschaft InsertSQL eintragen.

Hansa 29. Jun 2003 19:28

Der Code geht so schon, auch der Trigger feuert, aber im Delphi Programm geht es nicht. Ist das Dataset vielleicht verkehrt ? Aber ich setze doch nur den DB-Befehl damit ab, so wie mit ohne Delphi auch. Mich stört, daß keine Fehlermeldung kommt und sich nichts tut.

Lemmy 30. Jun 2003 07:13

Hi Hansa,

Zitat:

Zitat von Hansa
Der Code geht so schon, auch der Trigger feuert, aber im Delphi Programm geht es nicht.

Das ist doch genau das, was r_kerber gesagt hat. Das SQL-Statement ist schon richtig, nur wird es nicht ausgeführt:

1. Durch ein Open werden die Update, Refresh, Insert und Delete-Statements der DataSet NICHT ausgeführt, sondern nur durch die entsprechende Methode (.Update, .???, .Insert, .Delete).
2. steht das Ding im Update-SQL drin, so dass zum Ausführen ein Update notwendig währe (funktionieren sollte es aber dann).

Wenn Du so was machen willst (ein DML-Statement ausführen ohne vorher eine Datenmenge zu holen) dann schreib das SQL in die normale SelectSQL Eigenschaft rein und führe die SQL dann mit einem ExecSQL aus (nicht Open verwenden!).

Grüße
Lemmy

Hansa 30. Jun 2003 09:36

Zitat:

Zitat von Lemmy
... Wenn Du so was machen willst (ein DML-Statement ausführen ohne vorher eine Datenmenge zu holen) dann schreib das SQL in die normale SelectSQL Eigenschaft rein und führe die SQL dann mit einem ExecSQL aus (nicht Open verwenden!).

Da da ist mir zu hoch. Was hat das jetzt mit leeren Datenmengen zu tun ? Ich habe ja extra den Lagerbestand genommen, da kann ich vorher nicht wissen, ob die Datenmenge leer ist. Das Dataset hat zudem keine Eigenschaft "ExecSQL". Je nach Lage muß das eben ein Insert, oder ein Update sein. Im Moment sieht der relevante Code so aus:

Code:
LagDS.Close;
LagDS.InsertSQL.Text := 'INSERT INTO LAGER (MENGE) VALUES (33)'
LagDS.Open;
Transaction.Commit;

Alfons_G 30. Jun 2003 10:04

Jedes TQuery (und auch dessen Nachkommen in Fremdkomponenten) besitzt die Methode ExecSQL. Diese verwendest Du für Datenmanipulationsabfragen, also INSERT, UPDATE und DELETE, welche keine Datenmenge als Ergebnis zurückliefern.
Delphi-Quellcode:
DS.SQL.Text := 'INSERT INTO LAGER (MENGE) VALUES (33)';
DS.ExecSQL;
...
Damit wird die SQL-Abfrage ausgeführt. Für SELECT-Anweisungen musst Du dagegen open verwenden, um danach auf die zurückgelieferten Daten zugreifen zu können.
Ein explizites Schließen des Datasets ist nicht nötig, dies wird beim Zuweisen eines neuen SQL-Befehls automatisch erledigt.

:coder:

Hansa 30. Jun 2003 10:29

Ich muß also TQuery statt Tdataset verwenden ? Probiere es sofort aus, aber was ist bei dem Lagerbeispiel ? Angenommen ich habe einen neuen Artikel, dann ist sowieso keine Datenmenge da, aber bei einem bestehenden Bestand muß ich ja zuerst diesen lesen und dann aktualisieren, z.B. Zugänge verbuchen. Muß ich da jetzt ein Dataset UND ein Query benutzen ? Ersteres zum lesen der vorhandenen Daten und die Query zum updaten, oder wie ?

Lemmy 30. Jun 2003 10:56

HI Hansa,


nochmal anders: Übliches Vorgehen bei einer TDataSet:

1. Über eine Select-SQL wird eine Datenmenge vom Server geholt:
Code:
DataSet.SelectSQL.Text:='Select * from Tabelle';
DataSet.Open;
2. Über visuelle Felder werden die Daten angezeigt und können bearbeitet werden. Dazu steht z.B. in der DeleteSQL Eigennschaft die entsprechende SQL:

Code:
delete from Tabelle
where
  ID = :OLD_ID
Diese Standard-SQL-Statements werden bei den entsprechenden Methodenaufrufen (Delete) entsprechend ausgeführt ohne dass der Benutzer noch was machen muss.

Für Dein Beispiel würde das heißen:

Code:
LagDS.Close
LagDs.SelectSQL.Text:='Select * from Lager;';
LagDs.DeleteSQL:Text:='Delete from Lager where ????';
LagDs.UpdateSQL.Text:='Update Lager Set.....';
ÖagDs.RefreshSQL.Text:='.....';
LagDs.InsertSQL.Text:='Insert into Lager (Menge) VALUES (:Menge)';
Das sind genau die SQL-Statements die z.B. die TIBDataset automatisch generiert (Rechter Mausklick auf die TDataSet). Nun kannst Du mit folgendem Code Inserts durchführen:


Code:
  LagDS.Open;
  LagDS.Insert;
  LagDS['Menge']:=33;
  LagDs.Post;
  LagDS.Close;
  Transaction.Commit;
Du siehst das ist ein riesen Aufwand, speziell dann, wenn man eigentlich keine Daten vom Server holen will. Deshalb gehe ich in diesen Fällen her und verwende direkt die TDataSet.SelectSQL-Eigenschaft, schreibe da die entsprechende SQL rein und führe diese über ein ExecSQL aus, so wie ich es im vorherigen Post geschrieben habe.


Grüße
Lemmy

Hansa 30. Jun 2003 12:10

Zitat:

Zitat von Lemmy
...Du siehst das ist ein riesen Aufwand, speziell dann, wenn man eigentlich keine Daten vom Server holen will. Deshalb gehe ich in diesen Fällen her und verwende direkt die TDataSet.

So weit habe ichs jetzt geschnallt. Habe es frei nach Alfons_g gemacht. :mrgreen: Eine Query und ein ExecSQL, geht auch soweit mit insert. Aber was ist wenn ich einen vorhandenen Lagerbestand von 10 habe und da noch 10 Teile ins Lager kommen ? Dann muß ich doch updaten odewr nicht ? Vorher muß ich dann mit select den alten Bestand suchen und die Zahl von 10 auf 20 erhöhen ? Oder soll ich das Löschen und durch 20 ersetzen ???

Lemmy 30. Jun 2003 12:29

Wie kommen die 20 neuen Teile in das "lager"? Durch die explizite Eingabe eines Users in einer Maske oder durch "automatische" Eingabe z.B. bei der Eingabe einer Rechnung?

Im ersten Fall wirst Du doch sowieso die Daten des Lagers irgendwie in einer Tabelle anzeigen lassen, d.h. du hast schon eine TDataSet in Verwendung, die Du dann auch für die Neueingabe verwenden kannst.

Im zweite Fall würde ich es über eine spezielle TDataSet/TQuery machen, in der du das Insert eben in die SelectSQL-Eigenschaft schreibst...

Grüße
Lemmy

Hansa 30. Jun 2003 12:37

Zitat:

Zitat von Lemmy
Im ersten Fall wirst Du doch sowieso die Daten des Lagers irgendwie in einer Tabelle anzeigen lassen, d.h. du hast schon eine TDataSet in Verwendung, die Du dann auch für die Neueingabe verwenden kannst.

Und wie soll ich das machen ? Was ist mit dem Dataset zu machen? Und was ist bei Zugängen von neuen Artikeln, wo halt gar kein Lagerbestand da ist, auch nicht mit Bestand=0?

Sharky 30. Jun 2003 13:30

Zitat:

Zitat von Hansa
Und wie soll ich das machen ? Was ist mit dem Dataset zu machen? Und was ist bei Zugängen von neuen Artikeln, wo halt gar kein Lagerbestand da ist, auch nicht mit Bestand=0?

Warenwirtschaftstechnich kann es ja keinen Zugang von Artikeln geben die nicht im Programm erfasst sind.
Wenn also ein neuer Artikel angelegt wird, wird ersteinmal der Lagerbestand auf 0 gesetzt.

Wenn nun dieser Artikel im Wareneingang gebucht wird :

- erzeugst Du in deiner Lagerwebewegung-Tabelle einen Eintrag mit den Daten
- Änderst Du (wenn Du es denn möchtest) den Bestand in der Tabelle deiner Artikel.

Lemmy 30. Jun 2003 13:31

Hi,

wir posten aneinander vorbei! Nochmal anders: Du musst doch irgendwo eingeben welche Artikel in Deinem Lager sind, oder? Dazu machst Du doch sicherlich ein Formular in dem der User neue Artikel anlegen kann, bzw. bei bestehenden Artikel die Menge editieren kann u. ä. Für dieses Formular wirst Du doch sicherlich eine TDataSet/TIBDataSet/TirgendwasDataSet verwenden um die Daten die schon erfasst sind, anzeigen zu lassen, d.h. Du setzt visuelle DB-Komponenten (TDBEdit, ....) auf das Formular und verbindest das mit der TDataSet.

So und jetzt kommen wir wieder zum eigentlichen Thema:

In diesem Szenario wirst Du der TDataSet in die SelectSQL-Eigenschaft so eine ähnliche SQL eingeben:

Code:
Select * from Lager;
Mit einem RMK (rechten Mausklick) kannst Du dann (zumindest bei IBX) einen Editor öffnen, in dem Du die Insert, Update, Delete und Refresh-SQL Statements automatisch erzeugen lassen kannst. Dann musst Du nur noch die TDataSet mit der Datenbank verbinden und schon kannst Du loslegen. In Diesem Fall sorgt die TDataSet selbst dafür, dass bei einem Aufruf der Methoden Insert/Edit/Post/Delete die entsprechende SQL die du eingegeben/erzeugt hast ausgeführt wird.

Nun zum großen Unterschied: Wenn du selbst einfach so ein Insert-Statement ausführen willst, ohne eine vorbereitete TDataSet zu haben (wie oben), dann musst Du das entsprechende SQL-Statement auch anders ausführen: entweder in einer TQuery (dann ist eigentlich alles klar) oder eben in einer TDataSet. Dann musst du das Statement eben in die SelectSQL eingeben und dann mittels ExecSQL ausführen. Da spielt es dann keine Rolle was in der Tabelle schon drinsteht, bzw. dass die Eigenschaft des TDataSet "SelectSQL" heißt obwohl Du eine Insert oder Delete-Anweisung eingibst. Denn diese SelectSQL wird bei ExecSQL verwendet und ausgeführt.

Grüße
Lemmy

Hansa 30. Jun 2003 18:28

Zitat:

Zitat von Sharky
Warenwirtschaftstechnich kann es ja keinen Zugang von Artikeln geben die nicht im Programm erfasst sind. Wenn also ein neuer Artikel angelegt wird, wird ersteinmal der Lagerbestand auf 0 gesetzt.

Wenn nun dieser Artikel im Wareneingang gebucht wird :

- erzeugst Du in deiner Lagerwebewegung-Tabelle einen Eintrag mit den Daten
- Änderst Du (wenn Du es denn möchtest) den Bestand in der Tabelle deiner Artikel.

Eben, so ähnlich ist das. Kein Lager-Dataset: Insert, aktualisieren : Update und nun kommen die Datenmangen ins Spiel. Beim Insert ist eben keine da und beim Update muß die vorhandene angepaßt werden. Nur wie ?

@Lemmy: Deine Frage vorher habe ich nicht sofort verstanden. Es geht um nicht visuelle Sachen. Das soll hinter den Kulissen laufen.

r_kerber 30. Jun 2003 18:37

Zitat:

Zitat von Hansa
Insert, aktualisieren : Update und nun kommen die Datenmangen ins Spiel. Beim Insert ist eben keine da und beim Update muß die vorhandene angepaßt werden. Nur wie ?

Wen Du Daten einfügen willst (z.B. einen Lagerartikel mit Art-Nr, Beschreibung, Menge etc), dann müssen dies Informationen selbstverständlich eingegeben werden.
Ich vermute mal Du meinst folgendes: Das Lager bekommt einen Zugang der Menge x des Artikels y:
  1. Überprüfen ob Artikel vorhanden -
    SQL-Code:
    Select * from blabla where ArtNr = Y
  2. Erhältst Du keinen Datensatz -> Eingabemaske für Artikeldaten + Menge Zugang -> Anschließend
    SQL-Code:
    Insert Into
  3. Erhälts Du einen Datensatz für den Artikel heißt das er ist schon auf Lager -> also Erfassung der Zugangsmenge ->
    SQL-Code:
    Update blabla Set menge = vorhanden + zugang

Hansa 30. Jun 2003 18:46

Zitat:

Zitat von r_kerber
...Ich vermute mal Du meinst folgendes: Das Lager bekommt einen Zugang der Menge x des Artikels y:
  1. Überprüfen ob Artikel vorhanden -
    SQL-Code:
    Select * from blabla where ArtNr = Y
  2. Erhältst Du keinen Datensatz -> Eingabemaske für Artikeldaten + Menge Zugang -> Anschließend
    SQL-Code:
    Insert Into
  3. Erhälts Du einen Datensatz für den Artikel heißt das er ist schon auf Lager -> also Erfassung der Zugangsmenge ->
    SQL-Code:
    Update blabla Set menge = vorhanden + zugang

Ja, das kommt der Sache schon recht nahe. Schlau werde ich aber immer noch nicht so recht. Wie mache ich das mit vorhanden und Zugang ? Und was ist mit den leeren Datenmengen? Was muß man da beachten ?

JoelH 30. Jun 2003 18:54

hmm,
 
du prüfst ja eh mit select ob was da ist da kannst du dass vorhanden ja auch auslesen und dann den zugang addieren und wieder reinschreiben mit Update. Bei leeren Mengen musst du darauf achten ob die DBSpalte NULL sein darf oder auf NOT NULL steht.Achtung '' also ein Leerstring ist nicht NULL.

Hansa 30. Jun 2003 19:00

Re: hmm,
 
Zitat:

Zitat von JoelH
...Bei leeren Mengen musst du darauf achten ob die DBSpalte NULL sein darf oder auf NOT NULL steht.Achtung '' also ein Leerstring ist nicht NULL.

NULL <> 0, schon klar und wie soll ich es jetzt machen? Was ist, wenn das SELECT etwas liefert und was, wenn nicht ?

JoelH 30. Jun 2003 19:03

hmm,
 
naja wenn halt die Zeile schon da ist recordcount > 0 dann UPDATE, ansonste INSERT

Hansa 30. Jun 2003 19:10

Re: hmm,
 
Zitat:

Zitat von JoelH
naja wenn halt die Zeile schon da ist recordcount > 0 dann UPDATE, ansonste INSERT

Das geht einfacher mit
Code:
IsEmpty
nur mal so nebenbei bemerkt. 8) Lemmy hat mich mit seinen leeren Datenmengen trotzdem verwirrt. Lemmy, wo bist Du :?:

Lemmy 30. Jun 2003 19:19

Re: hmm,
 
Zitat:

Zitat von Hansa
Lemmy hat mich mit seinen leeren Datenmengen trotzdem verwirrt. Lemmy, wo bist Du :?:

zuhause... soso.. jetzt bin ich wieder schuld.... :lol:

Wenn Du das kapiert hast, was die anderen so geschrieben haben dann vergiss die leere Datenmenge einfach...

Wenn Du es dennoch wissen willst, dann schreib nochmal, nicht dass ich dich noch mehr verwirre....

Grüße
Lemmy

Hansa 30. Jun 2003 19:25

bist hoffentlich nicht beleidigt. Ich mach jetzt einfach notfalls "Try and Error" :mrgreen:

Lemmy 1. Jul 2003 07:28

Guten Morgen,

Zitat:

Zitat von Hansa
bist hoffentlich nicht beleidigt.

Weshalb denn..?? :bounce1:

Grüße
Lemmy

Ralf Stehle 15. Okt 2004 16:55

Re: Insert SQL
 
Beschäftigt sich derzeit noch jemand mit dem Problem ?

Ich habe auf Grund eurer Beiträge folgenden Code versucht

Delphi-Quellcode:
   DM.IBTagesplan.Close;
   DM.IBTagesplan.DeleteSQL.Text := 'Delete from UDAT';
   //DM.IBTagesplan.InsertSQL.Text := 'Insert Into UDAT (Patient) VALUES (''BlaBla'')';
   DM.IBTransaction.Commit;
   DM.IBTagesplan.Open;
Die Daten verschwinden auch zunächst im DBGrid.
Bei Neustart des Programmes sind sie aber wieder vorhanden.

Mit
Delphi-Quellcode:
DM.IBTagesplan.ExecSql
bekomme ich nur die Fehlermeldung "Verwenden Sie Open für eine Select-Anweisung"

kiar 15. Okt 2004 17:05

Re: Insert SQL
 
tausche mal commit und open

Ralf Stehle 15. Okt 2004 19:56

Re: Insert SQL
 
es funktioniert einfach nicht:

Mit dieser Anweisung sollte doch eigentlich ein neuer Datensatz eingefügt werden:

Delphi-Quellcode:
   DM.IBTagesplan.Close;
   DM.IBTagesplan.InsertSQL.Text := 'Insert Into UDAT (ID,UNTERSUCHUNGSDATUM, PATIENT) VALUES (50,''15.10.2005'',''Thomas Cook'')';
   DM.IBTagesplan.Open;
   DM.IBTransaction.Commit;

kiar 15. Okt 2004 20:13

Re: Insert SQL
 
hallo ralf, ich mache soetwas immer mit einer query und zwar so
Delphi-Quellcode:
with DM1.IBQuery3 do
        Begin
           Close;
           SQL.Clear;
           SQL.Add('insert Into Tab_Mitarbeiter (VNummer
                                              , Name
                                              , Vorname
                                              , Beruf
                                              , Firmen_Id)'+
          'values          (:VNummer,:Name,:Vorname,:Beruf,:Firmen_id)');
                   ParamByName('VNummer') .AsString := Edit1.Text;
                   ParamByName('Name')    .AsString := Edit3.Text;
                   ParamByName('Vorname') .AsString := Edit2.Text;
                   ParamByName('Beruf')   .AsString := Edit4.Text;
                   ParamByName('Firmen_Id').AsInteger:= x[ComboBox1.ItemIndex];
           Open;
        end;
        DM1.IBTrans1.Commit;
also ich versuche immer paramisierte felder zu nehmen .versuche es mal auf dein dataset umzusetzen.

raik

edit :ich hoffe du hast nicht 800*600 als auflösung, bei mir sieht es schrecklich aus

Hansa 16. Okt 2004 01:34

Re: Insert SQL
 
Wie kiar das beschrieben hat, so geht es im Prinzip. Wenn schon, dann aber direkt eine stored Procedure verwenden. Ja, man lernt eben nie aus. :zwinker: Das von mir anfangs eingeführte Lager-Beispiel habe ich so realisiert (Menge soll vom Bestand abgezogen werden) :

Delphi :

Delphi-Quellcode:
procedure SchreibeLager (menge : integer);
begin
  with EingDM do begin // EingDM : DataModule
    LagSP.ParamByName('ID_ART').AsInteger := ArtDS.FieldByName ('ID').AsInteger;
...
    LagSP.ParamByName('MENGE').AsInteger := menge;
    LagSP.ExecProc;
  end;
end;
Voraussetzumg ist natürlich, daß diese SP in der DB definiert ist.

DB:

SQL-Code:
SET TERM ^ ;

CREATE PROCEDURE LAGSP (
    ID_ART INTEGER,
    MENGE INTEGER)
AS
DECLARE VARIABLE AENDERN INTEGER;
begin
  AENDERN = -1;
  SELECT ID FROM LAGER WHERE ID_ART= :ID_ART INTO :AENDERN;
  IF (AENDERN < 0) THEN BEGIN
    INSERT INTO LAGER8 (ID_ART,MENGE) VALUES (:ID_ART,-1*:MENGE);
  END
  ELSE BEGIN
    UPDATE LAGER SET MENGE = MENGE - :MENGE
    WHERE ID_ART = :ID_ART;
  END
  suspend;
end
^

SET TERM ; ^
Das ist jetzt allerdings noch stark verkürzt. Nicht relevante Felder und Statements habe ich weggelassen.

Außerdem ist ein guter Trick integriert : nämlich die DB entscheiden zu lassen, ob ein INSERT oder ein UPDATE ausgeführt werden muß. Würde ich auf keinen Fall vernachlässigen :!:

Es muß also im Programm nur "SchreibeLager" ausgeführt werden, egal ob der Lagerbestand schon existiert oder nicht !!


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:38 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz