Entwickler-Ecke

Datenbanken - SQL DBgrid


hansa - Fr 27.09.02 13:59
Titel: SQL DBgrid
Hallo,
:roll:
Habe hier ein DataModul mit:

- Database
- Transaction
- DataSource
- DataSet

Nun will ich eine Datenmenge insoweit eingrenzen, um sie in einem Grid anzeigen zu lassen. Seltsamerweise zeigt das Grid in der IDE alle Datensätze an, lasse ich das Programm laufen ist es leer (das Grid). Muß ich da noch eine Query reinsetzen oder was fehlt sonst ? Vor Wochen hatte ich das schon hingekriegt, weiß aber nicht mehr wie. Das DataModul kommt mir irgendwie mickrig vor.

Gruß
Hansa


bis11 - Fr 27.09.02 14:45

Hi hansa,

ja, Du mußt noch eine Query-Kompo reinsetzen. Dann kannste mit dem SQL-Befehl SELECT * FROM Tabellenname WHERE Spaltenname='xy'. Mit diesem Befehl suchst Du jeden Eintrag aus der Tabelle raus der XY heißt.


hansa - Fr 27.09.02 20:29

Hi bis 11,

um 11 p.m. ist bei mir heute auch Schluß. AAAABER jetzt sehe ich doch noch wo der Fehler ist. Ich Idiot habe die Query in das DataModul gesetzt. :think:

:hair: Dadurch kam ich in der Query nicht an die Datasource heran!!

Gruß
Hansa


hansa - Fr 27.09.02 20:48

Hallo,

habe jetzt eine Query in das Formular gesetzt, aber irgendwo stehe ich aufm Schlauch. Die DataSource ist jetzt verfügbar, aber das Ergebnis dasselbe wie vorher auch. . Ich kann doch der Query nur mitteilen (per SQL ) was ich suche. Der SQL-string wird aber nicht ausgeführt, zumindest nicht automatisch, Fehlermeldung kommt auch keine.

Es geht darum, Daten in einem Grid anzuzeigen, sobald ein Button gedrückt wird. In der IDE werden die Daten ja auch angezeigt, deshalb müßte die DB-Struktur eigentlich richtig sein. :lol:

Gruß
Hansa


bis11 - Fr 27.09.02 21:04

Probiere mal folgende Abfrage :


Quelltext
1:
2:
3:
4:
    Query1.Close;
    Query1.SQL.Clear;
    Query1.SQL.Add('Select * FROM Tabellenname WHERE Datafield1='+QuotedStr('xy'));
    Query1.Open;


So mache ich meine Abfragen und gebe das dann im DBGrid an. Das DBGrid muß mit der DataSource verbunden sein.


hansa - Fr 27.09.02 21:10

Hi bis11,

Zitat:
So mache ich meine Abfragen und gebe das dann im DBGrid an. Das DBGrid muß mit der DataSource verbunden sein.


Nur an welcher Stelle kan ich denn genau sagen, daß er das anzeigen soll? In diesem Fall sollte es so sein, daß beim Drücken eines Buttons das Grid erscheint. :roll:

Gruß
Hansa


bis11 - Fr 27.09.02 21:16

Hi hansa,

folgende Verbindungen müssen bestehen :

DBGrid --> Datasource

Datasource --> Query1

Dann einfach den Code von meinem letzten Posting in ein Button Click Event schreiben und schon sollte es funzen.


hansa - Fr 27.09.02 21:35

Hallo Bis11,

Zitat:

folgende Verbindungen müssen bestehen :

DBGrid --> Datasource

Datasource --> Query1

In der DataSource kann ich nur ein Dataset angeben
Im DBgrid steht die DataSource drin.

Gruß
Hansa


bis11 - Fr 27.09.02 22:22

Die Query1 muß bei Dataset drinstehen.


hansa - Sa 28.09.02 11:25

Hi bis11,

Zitat:
Im DBgrid steht die DataSource drin


Da liegts dran. Ich kann dort keine angeben, zumindest bringt er mir keine zur Auswahl. Vermute, daß vorher noch irgendwas fehlt/falsch ist.

Es sieht jetzt so aus :
Zitat:

Habe hier ein DataModul mit:
- Database
- Transaction
- DataSource
- DataSet


Auf der Form selber liegt noch die Query. um an das DataModul ran zu kommen habe ich es in der Form von Hand so eingebunden :

Quelltext
1:
2:
3:
4:
5:
6:
var
  Form1: TForm1;

implementation

USES DataMod;


Ohne das USES ging gar nichts. Da bin ich sogar selber drauf gekommen :mrgreen: . Zur Runtime kommt nun der Fehler : DataBase not assigned to Query. Ist ja auch klar, bei dem DBgrid ist keine DataSource hinterlegt.

Was mich noch stört : Er beschwert sich, die DataBase not assigned und nicht DataSource. Im DBgrid kann ich doch nur die Datasource angeben.

Moment mal, habe gerade festgestellt, daß mein DataSet gar keine DataSource enthält. Wo ist denn die jetzt ? :shock: Mist, das ganze lief bereits. :hair:

Gruß
Hansa


hansa - Sa 28.09.02 11:29

Kommando zurück. Sowohl Transaction, als auch DataSet waren active=false. Jetzt kann ich mit der Query weitermachen.

Gruß
Hansa


hansa - Sa 28.09.02 13:49

Hi bis11,

Das Grid ist jetzt ungefähr so, wie ich es haben möchte, aber noch Prototyp. D.h. Die Felder weden jetzt alle richtig angezeigt, aber es gibt doch noch einiges :

Bei dem DataSet habe ich jetzt folgende SQLs:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
SELECT * FROM KG8  ORDER BY NR

UPDATE KG8 SET 
    NR = ?NR,
    BEZ = ?BEZ
 WHERE     
            ID = ?OLD_ID

INSERT INTO KG8(
    ID,
    NR,
    BEZ
)
VALUES(
    ?ID,
    ?NR,
    ?BEZ
)

DELETE FROM KG8
WHERE     
            ID = ?OLD_ID
    
select * from KG8
 WHERE 
    (    
            KG8.ID = ?OLD_ID
    )


In dem Grid stehen dann alle Datensätze, im Moment 3 :mrgreen:

Um zu sehen, wie das ganze sich überhaupt verhält, habe ich nun folgendes getan (der code geht so sowieso nicht, aber einfach mal weiter lesen, es geht um das select) :


Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm1.KGgridCellClick(Column: TColumn);
begin
  KGquery.Close;
  KGquery.SQL.Add('Select * FROM KG8 WHERE NR=88');
  KGquery.ExecQuery;
end;


Das erste Problem ist, daß das Grid automatisch, sobald es auf dem Bildschirm erscheint, nur bestimmte Daten anzeigen soll und nicht erst bei CellClick oder so. Wichtiger daran ist aber, daß nicht alle DS angezeigt werden, sondern nur bestimmte. Dafür dient doch die Query ?

Nun kann ich ja dort ein SQL-Statement eintragen. Was ich noch nicht so ganz verstehe ist, wozu genau obige Statements gut sind und der SQL String den ich der Query zuordnen kann. Soweit ich das sehe geht ohne die ersteren gar nix. Will ich aber dem Benutzer die Auswahl lassen, nur bestimmte Datensätze zu sehen, muß ich das dann bei dem ersten select oder bei der Query machen?

Egal was ich bei der Query als SQL eingebe, es tut sich nichts.
Gebe ich statt der obigen SELECT folgendes ein :

select * from KG8 where NR = 88 ORDER BY NR

Dann zeigt er mir im Grid nur den Satz mit der Nr. 88 an. Wozu brauche ich denn dann die Query ? Oder anders rum gefragt : Muß ich die Einschränkung der Datenmenge in der SQL Eigenschaft des Dataset bereits festlegen oder wie oder wo ? :shock:

Ich will dem Benutzer zur Laufzeit z.B. die Möglichkeit geben, alle Datensätze von Nr. 88 bis 90 zu sehen und zu editieren.

Was mir noch nicht gefällt ist, daß die ID auch im Grid steht.

Gruß
Hansa


bis11 - Sa 28.09.02 14:34

Hi hansa,

Zitat:

procedure TForm1.KGgridCellClick(Column: TColumn);
begin
KGquery.Close;
KGquery.SQL.Add('Select * FROM KG8 WHERE NR=88');
KGquery.ExecQuery;
end;


Erstmal hast Du hier einen grundsätzlichen Fehler gemacht. Deine letzte Zeile muß heißen KGquery.Open und nicht KGquery.ExecQuery.

Dann bei Deiner Select-Anweisung ist es klar, das dort nur der Datensatz mit der Nr. 88 angezeigt wird, wenn dieser einmal vorkommt. Die Anweisung bedeutet ja, selektiere alle Datensätze aus der Datenbank die im Feld Nr. 88 stehen haben.

Um jetzt die Datensätze von 88 bis 90 anzuzeigen, sollte es mit folgenden Befehl klappen : (nicht getestet)


Quelltext
1:
Select * FROM KG8 WHERE Nr>=88 AND Nr<=90                    


Ich kann Dir eine recht gute Seite empfehlen für SQL-Befehle [http://home.t-online.de/home/aam_int/de/sqlhelp/index.html]. Von dieser Seite habe ich viel über SQL-Befehle gelernt. 8)


hansa - Sa 28.09.02 14:58

Hi,

Weiß gar nicht wie ich das schreiben soll. :hair:

Select * FROM KG8 WHERE Nr>=88 AND Nr<=90

Das geht bestimmt. :D Aber mir geht es im Moment darum, an welcher Stelle ich solch ein Select einsetzen soll. Wenn ich es bereits in der select Eigenschaft des Datensatzes hinterlege geht das ja jetzt schon.

Aber kann doch kein Programm schreiben, das nur Nummern zwischen 88 und 90 anzeigt. Also müssen Parameter her. Wo und in welches select soll ich die reinsetzen ?

Oder anders gesagt : Kann mir jemand sagen welche GENAUE Bedeutung und Auswirkungen die SQLs in der Property des DataSet haben? Mit Generate SQLs hat er mir sie automatisch erstellt.

Select * FROM KG8 WHERE Nr>=88 AND Nr<=90

Würde ich so etwas mit Parametern dort bei selectSQL reinschreiben, dann geht es ja, aber ist dann nicht diese Eigenschaft festgelegt. Kann ich sie danach mit SQL.clear wieder löschen und mit Add eine andere Abfrage reinsetzen und wo bleiben in diesem Zusammenhang die Queries ?

Guck mir das mit den SQL-Befehlen mal an, aber im groben kenne ich die, wenn auch nicht auswendig :mrgreen: Mir fällt es noch schwer die in Delphi umzusetzen. Überall stehen die SQL-Befehle, aber finde einfach nichts Brauchbares (am besten nachvollziehbare Beispiele) mit Delphi, weder in der Online-Hilfe noch in Büchern (entweder sind sie zu oberflächlich oder gehen davon aus, daß der Leser alles sowieso schon weiß) :bawling:

Gruß
Hansa


bis11 - Sa 28.09.02 15:19

Hi hansa,

Du kannst ja Deinen select Befehl in das FormCreate-Ereignis reinschreiben. So werden gleich die ausgewählten Datensätze angezeigt. Ersetze doch die 88 & die 90 durch variablen.

Das könnte so aussehen :


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  nr_anfang : integer;
  nr_ende : integer;

  KGquery.Close;
  KGQuery.SQL.Clear;  
  KGquery.SQL.Add('Select * FROM KG8 WHERE NR>=' + IntoStr(nr_anfang) + ' AND Nr<=' + IntToStr(nr_ende)); 
  KGquery.Open;


Damit kannst Du jetzt ganz variabel angeben, welche Datensatznummern angezeigt werden sollen. Bei diesem Beispiel muß der Typ des Feldes Nr. numerisch sein.


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  nr_anfang : string;
  nr_ende : string;

  KGquery.Close;
  KGQuery.SQL.Clear;  
  KGquery.SQL.Add('Select * FROM KG8 WHERE NR>=' + QuotedStr(nr_anfang) + ' AND Nr<=' + QuotedStr(nr_ende)); 
  KGquery.Open;


Hast Du Deinen Typ für das Feld Nr. in der Datenbank als Text festgelegt so mußt Du diesen Quelltext verwenden.

Mit dem Befehl KGQuery.SQL.Clear löscht Du jedesmal vor jedem neuen SQL-Befehl den Buffer von der Query-Kompo.


hansa - Sa 28.09.02 15:37

Hi bis11,

Du schreibst was mit QuotedStr. Vielleicht kannst Du dir das hier mal ansehen :

http://www.delphipraxis.net/viewtopic.php?t=934

Gruß
Hansa


bis11 - Sa 28.09.02 15:50

Also, bei mir haut das ganz hervorragend hin. Ich benutze QuotedStr bei Paradox, dbase & MySQL. Da habe ich keine Probleme. Mit den anderen habe ich noch nicht so viel Erfahrung, mag sein das IB statt einfachen Anführungszeichen die doppelten braucht. Dann lässte einfach das QuotedStr einfach weg.


hansa - Sa 28.09.02 15:58

Hi bis11,

Schreibe ich alles groß, brauche ich gar nix (weder " noch '). 8) Hab das nur geschrieben, weil von irgendwoher die " auftauchen, ob in den SQL-Scripten oder Deinen Quelltexten. :mrgreen: Keiner weiß, warum genau.

Gruß
Hansa


LCS - So 29.09.02 09:58

Hi Hansa
Grundsätzlich wäre mal zu sagen, dass du dir den Aufwand mit der Query gar nicht machen musst. TQuery ermöglicht es einen SQL Befehl zur Datenbank zu schicken oder eine Datenmenge aufzubauen (mit SELECT).
Allerdings ist diese Datenmenge in der Regel ReadOnly.
Genau das selbe macht auch ein IBDataSet. Die Eigenschaft SELECTSQL entspricht der Eigenschaft SQL bei der Query. Darüberhinaus verwendet IBDataset auch SQL Anweisungen um Datensaätze einzufügen (InsertSQL), zu löschen (DeleteSQL), zu ändern (UpdateSQL) und zu aktualisieren (RefreshSQL). Das sind die Anweisungen die auf der Basis von deinem SelectSQL automatisch erzeugt werden.
Was du machst ist also im Grunde genommen doppelt gemoppelt. Um die Datenmenge einzuschränken kannst du die SelectSQL mit einer WHERE Klausel versehen. Du musst dabei nur darauf achten, dass sich die Anzahl der Felder oder die Reihenfolge nicht verändert, weil sonst die anderen SQL-Anweisungen nicht mehr passen. Solange du immer mit SELECT * arbeitest ist das kein Problem.
Du könntest also einfach immer mit deinem Dataset arbeiten und bei Bedarf einfach die SelectSQL ändern.
Ich hoffe das hilft dir erst mal weiter.
Gruss Lothar


hansa - So 29.09.02 11:35

Hi Lothar,

Zitat:
Grundsätzlich wäre mal zu sagen, dass du dir den Aufwand mit der Query gar nicht machen musst.


Habs auch schon fast geschnallt.

Zitat:
Du könntest also einfach immer mit deinem Dataset arbeiten und bei Bedarf einfach die SelectSQL ändern.


Also ich hab gedacht, die SQLselect und die anderen des Dataset seien dazu da, daß überhaupt alle Felder zu sehen sind und der Zugriff auf alle Datensätze möglich ist. Trage ich dort nicht SELECT * FROM KG8 ein, ging nämlich gar nichts.

Die anderen Selects brauche ich dann zur Laufzeit, damit der Benutzer sagen kann, was er will. Deshalb wollte ich die SQLs im OI in Ruhe lassen und die selects (WHERE usw.) Bedingungen halt zur Laufzeit erzeugen. So kam ich auf die Query :mrgreen:.

Zitat:
weil sonst die anderen SQL-Anweisungen nicht mehr passen.


Deshalb wollte ich die DataSet SQLs ja nicht verändern. Wie rum soll ichs denn jetzt machen ?

Gruß
Hansa


LCS - So 29.09.02 16:19

Hi
hab ich doch eigentlich schon geschrieben:
LCS hat folgendes geschrieben:
Du musst dabei nur darauf achten, dass sich die Anzahl der Felder oder die Reihenfolge nicht verändert, weil sonst die anderen SQL-Anweisungen nicht mehr passen.

Es ist vollkommen egal ob du schreibst

Quelltext
1:
select Feld1, Feld2, Feld3, Feld4 from Tabelle                    

oder

Quelltext
1:
2:
select Feld1, Feld2, Feld3, Feld4 from Tabelle
where Feld1 like 'A%' und tausend weitere Vergleiche

weil sich dadurch weder die Anzahl noch die Reihenfolge der Felder in der Datenmenge ändert. Die generierten SQL Anweisungen für Insert, Update, Delete oder Refresh passen. Ob die Anzahl der Seätze eingeschränkt wird oder nicht, spielt keine Rolle.
Anders wäre es wenn du aber schreibst

Quelltext
1:
select Feld4, Feld5, Feld1, Feld7 from Tabelle                    

Hier werden im Select andere Felder geliefert als in den anderen SQL-Anweisungen aktualisiert oder geändert werden. Hier müssten jetzt auch die anderen SQL-Anweisungen entsprechend angepasst werden. Geht theoretisch natürlich auch, macht aber viel Arbeit. :(
Und in der Praxis siehts doch immer so aus, dass die benötigten Felder feststehen und nur die Menge der Sätze anhand der Where-Klausel eingeschränkt wird.
Werden unterschiedliche Felder benötigt ist es einfacher mehrere Datasets zu verwenden.

Gruss Lothar


hansa - So 29.09.02 17:05

Hi Lothar,

Zitat:
Werden unterschiedliche Felder benötigt ist es einfacher mehrere Datasets zu verwenden.


Das muß einfacher gehen. Bsp.: es existieren 8 Preisgruppen. D.h. der Anwender hat Endkunden, Wiederverkäufer, Großkunden usw., wofür jeweils eine Preisgruppe kalkuliert und vorgesehen ist. Deine Logik ist mir schon klar, dann müßte ich 8 Datasets auf die Form legen, um alle zu berücksichtigen, die jeweils richtigen Felder auswählen und dementsprechend die SelectSQL anpassen (jeweils pro DataSet). Die Frage stellt sich dann allerdings wieder, welche Untermenge der Daten z.B. auf einer Preisliste erscheint.

Gruß
Hansa


LCS - Mo 30.09.02 07:52

Hi Hansa
das wäre dann aber eher eine Frage des DB-Designs und kein Programmierproblem. Denn wenn ich die Preisgruppen in einer eigenen Tabelle halte und mir die notwendigen Daten über die Kategorie (Endkunden, Wiederverkäufer...) heranhole, dann hab ichs doch auch wieder nur mit einer Einschränkung der Datensätze zu tun. Und damit brauch ich auch wieder nur ein DataSet. :D

Gruss Lothar


hansa - Mo 30.09.02 17:09

Hi,

Habe noch eine Frage : wozu ist das SelectSQL (siehe Code) ein Tstring ?


Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm1.FormShow(Sender: TObject);
begin
  DataModul.KGdatensatz.active := false;
  DataModul.KGdatensatz.SelectSQL [0] := 'SELECT * FROM KG8 WHERE nr = 88';
  DataModul.KGdatensatz.active := true;
end;


So ungefähr geht es jetzt. Den Rest setze ich dann eben entsprechend in die WHERE-Klausel ein, also von Nr. bis Nr., alphabetisch usw. Die Query ist nicht mehr da!

Aber ACHTUNG !
Habe das mit FIBplus gemacht. Statt dem .active wird in IBX open und close benutzt. Glaube zumindest. :D

Ist jemand so verrückt wie ich, sich mit sowas einzulassen, Delphi, SQL,Interbase....Die Fallen lauern überall. :mrgreen:
Für kleinere Sachen würde ich jedem abraten !!!

Gruß
Hansa


LCS - Mo 30.09.02 17:18

hansa hat folgendes geschrieben:

Habe noch eine Frage : wozu ist das SelectSQL (siehe Code) ein Tstring ?

Damit du so ganz nebenbei alle Eigenschaften und Methoden von StringList nutzen kannst. Z. B. mit LoadFromFile den SQL-Text aus einer Datei laden. :D
hansa hat folgendes geschrieben:

Ist jemand so verrückt wie ich, sich mit sowas einzulassen, Delphi, SQL,Interbase....Die Fallen lauern überall. :mrgreen:
Für kleinere Sachen würde ich jedem abraten !!!

Ich verwende für meine Projekte eigentlich nix anderes mehr. Wenn man die ganzen Anfangshürden mal genommen hat, lässt sich damit hervorragend arbeiten.

Gruss Lothar


hansa - Mo 30.09.02 17:43

Hi Lothar,

Aha !

Zitat:
Wenn man die ganzen Anfangshürden mal genommen hat, lässt sich damit hervorragend arbeiten


Macht mir auch Spaß, wenn es irgendwie voran geht. Trotzdem warne ich jeden, für sein privates Musikarchiv und ohne Vorkenntnisse, mit sowas anzufangen. :mrgreen:

Nächste Hürde sind jetzt die Foreign-Keys. In der DB sind sie zwar angelegt, aber wie mach ich jetzt mit Delphi weiter? Die mickrigen Kundengruppen sind soweit klar, das nächste sind halt die Kunden.

Habe was gesehen von ?MAS oder ID_MAS, sind das vordefinierte SQL-Wörter oder kann man die selber erfinden ?

Dann geht es nämlich weiter mit DBlookUp-Boxen, da heutzutage niemand mehr in der Lage ist, sich seine 5 Kundengruppen zu merken.

Zwischendurch versuche ich dann, ca. 2000 Kunden in die IB-DB reinzukriegen. Dazu muß das mit den geerbten Schlüsseln aus den Kundengruppen aber klar sein, dann kommen wieder die Transaktionen dran und dann kommen irgendwann mal die Druckausgaben dran und dann die Schnittstelle zu Excel und dann...und dann....und dann..................... :hair:

Gruß
Hansa


hansa - Mo 30.09.02 18:20

Hi Lothar,

das mit den Tstrings:

Zitat:
Damit du so ganz nebenbei alle Eigenschaften und Methoden von StringList nutzen kannst. Z. B. mit LoadFromFile den SQL-Text aus einer Datei laden


Liege ich mit der Vermutung richtig, daß es hauptsächlich deshalb ist, ein komplettes SQL-Script in Delphi ablaufen zu lassen ?

Gruß
Hansa


LCS - Di 01.10.02 06:27

Hi Hansa
ich denke mal, dass der Hauptgrund war, nicht auf einen String beschränkt zu sein. Aber natürlich lässt sich das auch dazu verwenden ein komplettes Script ablaufen zu lassen. Aber auch da stecken einige Tücken drin.

Gruss Lothar