| Autor |
Beitrag |
JRegier
      
Beiträge: 1268
Win XP Home, Prof, 2003 Server
D6 Enterprise
|
Verfasst: Fr 19.08.05 07:11
Hi, wie ich gelesen habe wird davon abgeraten bei eine Client-Server-Modell einfach
SELECT * FROM `tabelle` auszuführen! Sondern die Transactionmenge so gering wie möglich
zu halten, vorzugsweise nur ein Datensatz!
Ich habe keine Ahnung wie solch ein Befehl in SQL aussehen könnte, also ich möchte dass z.B.
beim Start der Erste Datensatz abgefrufen wird und beim Befehl Fisrt/Next/Prior/Last immer
jeweils der richtige Datensatz selektiert wird! OK ich könnte einfach:
SELECT * FROM `tabelle` WHERE ID = :X
ausführen! Aber wer sagt mir das diese ID überhaupt noch vorhanden ist wenn die nicht schon
bereits gelöscht wurde! (Ich meine hier mit ID ein AutoInc Feld) aber sagt mal wie ist es
wenn eine Tabelle kein AutoInc Feld hat?
Ich müßte also ein Next/Prior.. an der Physikalischen Tabelle ausführen also in der Art
SELECT FIRST, SELECT PRIOR, SELECT NEXT, SELECT LAST aber die Befehlkombination gibts
wohl nicht oder?
|
|
noidic
      
Beiträge: 851
Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
|
Verfasst: Fr 19.08.05 08:26
Hi!
Nein, solche Befehle gibt es zumindest bei den mir bekannten Datenbanken nicht. Ist auch eigentlich nciht nötig, denn normalerweise bieten die Zugriffskomponenten wie TQuery u.ä. die gewünschte Funktionalität bereits mit ( nennt sich dann FetchAll oder sowas in der Art, mal die OH befragen ).
Ansonsten macht es Sinn, um die Datenmenge zu begrenzen, nicht select * aufzurufen, sondern die Spalten einzeln zu selektieren ( ausser man braucht wirklich alle ). Das hat außerdem den Vorteil, das nach einer Änderung der Tabelle Code-Stellen leichter gefunden werden, die noch das alte Format erwarten ( es schlägt direkt die Abfrage fehl, nicht irgendwas später ).
_________________ Bravery calls my name in the sound of the wind in the night...
|
|
davidbaumann
      
Beiträge: 39
Win XP
D7PE
|
Verfasst: Fr 19.08.05 09:03
SELECT * FROM `tabelle` WHERE ID >= X order by X limit 1
|
|
noidic
      
Beiträge: 851
Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
|
Verfasst: Fr 19.08.05 09:22
Limit gibts nicht bei allen Datenbanken ( ich kenne ausser MySQL keine, dies kann ), ausserdem kriegst du damit zwar wunderbar nur einen Datensatz, aber auch immer den selben.
_________________ Bravery calls my name in the sound of the wind in the night...
|
|
JRegier 
      
Beiträge: 1268
Win XP Home, Prof, 2003 Server
D6 Enterprise
|
Verfasst: Fr 19.08.05 09:23
noidic hat folgendes geschrieben: | Hi!
Nein, solche Befehle gibt es zumindest bei den mir bekannten Datenbanken nicht. Ist auch eigentlich nciht nötig, denn normalerweise bieten die Zugriffskomponenten wie TQuery u.ä. die gewünschte Funktionalität bereits mit ( nennt sich dann FetchAll oder sowas in der Art, mal die OH befragen ).
Ansonsten macht es Sinn, um die Datenmenge zu begrenzen, nicht select * aufzurufen, sondern die Spalten einzeln zu selektieren ( ausser man braucht wirklich alle ). Das hat außerdem den Vorteil, das nach einer Änderung der Tabelle Code-Stellen leichter gefunden werden, die noch das alte Format erwarten ( es schlägt direkt die Abfrage fehl, nicht irgendwas später ). |
Vieleicht hast mich falsch verstanden?
Vorerst mal möchte ich, das mit den Spalten, ein Sachverhalt erläutern:
-----------------
Nehmen wir mal an ich habe eine INNER JOIN Abfrage und kann nicht die Datenmenge editieren,
nun verwenden ich eine andere Query in der ich den UPDATE Statement reinschreibe!
z.B ich habe eine Tabelle:
PERSON
-------------------------------
ID* | NAME | VORNAME | STRASSE | PLZ | ORT
Am besten ich selektiere bei der INNER JOIN Abfrage mit
Delphi-Quelltext 1:
| SelectQuery.SQL.Text := 'SELECT * FROM `PERSON` A INNER JOIN `FIRMA` B ON A.`ID` = B.`PERSON_ID` WHERE B.`ID` = 12'; |
Weil ich hier mit * Selektiert habe kann ich den Datensatz auch dann identifizieren auch wenn
es keinen Primary Key gibt!
Also ich schreibe einfach in die UpdateQuery rein:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| with UpdateQuery do begin SQL.Text := 'UPDATE PERSON SET NAME = :NAME, VORNAME = :VORNAME, STRASSE = :STRASSE, '+ 'PLZ = :PLZ, ORT = :ORT '+ 'WHERE ID = :OLD_ID AND NAME = :OLD_NAME AND VORNAME = :OLD_VORNAME AND '+ 'STRASSE = :OLD_STRASSE AND PLZ = :OLD_PLZ AND ORT = :OLD_ORT';
ParamByName('NAME').AsString := NewName; ... ... ParamByName('OLD_ID).AsInteger := SelectQuery.FieldByName('ID').AsInteger; ParamByName('OLD_NAME).AsInteger := SelectQuery.FieldByName('Name').AsString; ... |
Wenn ich alle Felder angebe kann also immer ein Datensatz identifiziert werden! Oder auch nicht?
Wenn es mehrere gleiche Datensätze gibt werden die ja alle hiermit aktualisiert!
Gibt es einen Weg bei mehreren Gleichen Datensätzen das nur einer geupdatet wird?
ABER WAS ICH MIT DIESEM THREAD HIER SAGEN WOLLTE:
Wenn es um Cleint Server Modell geht, wird davon abgeraten alle Datensätze
mit : SELECT * FROM `tabelle` ohne WHERE zu selektieren also
vorzüglich nur ein Datensatz! Darum die Frage nach SELECT FIRST, SELECT NEXT usw.
|
|
noidic
      
Beiträge: 851
Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
|
Verfasst: Fr 19.08.05 09:33
Du hast recht, habe dich falsch verstanden  Ich dachte, es ginge dir darum, möglichst wenige Datensätze in einem Schwung vom Server zu ziehen ( warum auch immer ).
Nun verstehe ich dein Problem nicht mehr...
Ob du mit Select * selektierst oder die Spalten konkret aufführst hat keinen Einfluss darauf, dass du einen Datensatz identifizieren kannst, denn dafür ist ja der Primärschlüssel da ( in deinem Fall das Feld ID nehme ich an ). Also nimmst du die entpsrechende Spalte einfach mit auf.
Zu der Frage nach dem Update: Wenn mehrere Datensätze die Bedingung erfüllen, werden auch alle geändert. Punkt.
Und zum letzten Punkt:
Selects ohne Bedingung sollte man nach Möglichkeit vermeiden. Zumeist ist nur eine Teilmenge der Daten relevant, und die sollte man dann schon beim Select eingrenzen. Dies geht nur mit geschickt formulierten Where-Klauseln.
_________________ Bravery calls my name in the sound of the wind in the night...
|
|
JRegier 
      
Beiträge: 1268
Win XP Home, Prof, 2003 Server
D6 Enterprise
|
Verfasst: Fr 19.08.05 09:54
noidic hat folgendes geschrieben: | Du hast recht, habe dich falsch verstanden Ich dachte, es ginge dir darum, möglichst wenige Datensätze in einem Schwung vom Server zu ziehen ( warum auch immer ).
Nun verstehe ich dein Problem nicht mehr...
|
Nein dann hast du es doch verstanden, wenn du meinst möglichst wenige Datensätze in einem Schwung zu selektieren, nur weil du was von
Spalten geschrieben hast darum dieser umfangreiche Beitrag!
noidic hat folgendes geschrieben: |
Ob du mit Select * selektierst oder die Spalten konkret aufführst hat keinen Einfluss darauf, dass du einen Datensatz identifizieren kannst, denn dafür ist ja der Primärschlüssel da ( in deinem Fall das Feld ID nehme ich an ). Also nimmst du die entpsrechende Spalte einfach mit auf.
|
Aber haben den die Tabellen immer einen Primärschlüssel?
noidic hat folgendes geschrieben: |
Zu der Frage nach dem Update: Wenn mehrere Datensätze die Bedingung erfüllen, werden auch alle geändert. Punkt.
|
Na ja habe ich mir auch gedacht, aber vorher wollte ich mit Select Edit und dann Post der Query ausführen dann müßte eigentlich
nur ein Datensatz geupdatet werden! Aber das mit Query.Post funzte nicht, ich benutze z.Z. Zeos ZQuery und greife auf eine MySQL
Datenbank zu!
noidic hat folgendes geschrieben: |
Und zum letzten Punkt:
Selects ohne Bedingung sollte man nach Möglichkeit vermeiden. Zumeist ist nur eine Teilmenge der Daten relevant, und die sollte man dann schon beim Select eingrenzen. Dies geht nur mit geschickt formulierten Where-Klauseln. |
[/quote]
OK, Selects ohne Bedingungen verstehe ich, bei Master-Detail-Verknüfungen sind bei den Detail-Tabellen sowiese nur Teildaten Selektiert
aber in der Haupttabelle/Mastertabelle die von keiner Abhängig ist sind ja alle Datensätze selektiert also wollte ich da sowas realisieren
dass beim Navigieren jeweils nur ein Datensatz selektiert ist also quasi SELECT FIRST beim Transactionstart und dann beim Navigieren
SELECT NEXT .. etc.
Wie könnte denn die Where Clausel aussehen? Irgendjemand eine Idee?
|
|
noidic
      
Beiträge: 851
Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
|
Verfasst: Fr 19.08.05 10:19
Hi!
Ich kenn die Komponenten nicht, die du verwendest, aber schau dir meine erste Antwort bezüglich den Möglichkeiten des TQuery nochmal an. Da müsste es eigentlich eine Möglichkeit geben, der Komponente zu sagen, sie soll die Datensätze nach Bedarf ziehen.
Zum Thema Primärschlüssel:
Jede aktive Tabelle ( also alles ausser History-Tabellen ) sollte einen Primärschlüssel haben, alles andere ist imo schlechtes DB-Design da:
1. Keine Eindeutige Datensatz-Identifizierung möglich ist ( wenn ich dafür nen unique index baue, kann ich daraus direkt nen pk machen ).
2. Joins mit dieser Tabelle elend langsam werden, da immer ein full table scan gemacht wird
_________________ Bravery calls my name in the sound of the wind in the night...
|
|
JRegier 
      
Beiträge: 1268
Win XP Home, Prof, 2003 Server
D6 Enterprise
|
Verfasst: Fr 19.08.05 11:10
noidic hat folgendes geschrieben: | Hi!
Ich kenn die Komponenten nicht, die du verwendest, aber schau dir meine erste Antwort bezüglich den Möglichkeiten des TQuery nochmal an. Da müsste es eigentlich eine Möglichkeit geben, der Komponente zu sagen, sie soll die Datensätze nach Bedarf ziehen.
|
Ja ich habe mir FetchAll: in der Delphi Hilfe angesehen!
Da steht:
begin
Mit FetchAll können Sie die Belastung des Netzwerks verringern, wenn die Zwischenspeicherung von Aktualisierungen aktiv ist. FetchAll ruft CheckBrowseMode auf, um alle Änderungen einzutragen. Anschließend werden alle Datensätze von der aktuellen Cursorposition bis zum Dateiende abgerufen und lokal gespeichert.
Hinweis
Die Verwendung von FetchAll ist nicht immer sinnvoll. Wird beispielsweise in einer Anwendung auf eine Datenbank zugegriffen, die von mehreren Clients gleichzeitig verwendet wird, und werden häufig Datensätze von mehreren Clients aktualisiert, sollten nicht alle Datensätze gleichzeitig abgerufen werden, da einige dieser Datensätze möglicherweise in anderen Anwendungen geändert wurden. Sie müssen also die Vorteile einer geringeren Netzwerkbelastung gegen die Nachteile abwägen, die aus Konflikten in den Datensätzen entstehen.
end;
Also alle Datensätze werden abgerufen und lokal gespeichert! Also doch nicht das richtige!
|
|
noidic
      
Beiträge: 851
Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
|
Verfasst: Fr 19.08.05 11:18
Eben genau das solltest du ja dann abschalten 
_________________ Bravery calls my name in the sound of the wind in the night...
|
|
JRegier 
      
Beiträge: 1268
Win XP Home, Prof, 2003 Server
D6 Enterprise
|
Verfasst: Fr 19.08.05 14:12
noidic hat folgendes geschrieben: | Eben genau das solltest du ja dann abschalten  |
FetchAll ist eine procedure! Nicht eine Eigenschaft! Oder einfach not FetchAll aufrufen? 
|
|
hansa
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Fr 19.08.05 14:46
Hi,
Du mußt etwas mehr Systematik in das Programm reinbringen. Der * hat mit Fetchall usw. nur bedingt etwas zu tun. Warum steht das Update bei dir im Source ? Dafür sind normalerweise die Zugriffskomponenten zuständig (insbesondere TDataSet und Nachfolger). Da wird der Kram hinterlegt (auch für insert, delete usw.). Im Programm benutzt Du dann nur noch Dataset.Edit um zu ändern und dann mit Dataset.Post speichern. Alternativ kann man (so mache ich es) Stored Procedures zum speichern benutzen. MySql kann das (zumindest noch) nicht.
Der * spielt bei Select allerdings schon eine große Rolle.
Beispiel : Brauche Kunden-Tel.Nr. Liste.
SELECT * FROM KUNDE liefert mir jetzt auch Skonto, Lieferadresse usw. vielleicht auch Firlefanz wie Geburtstag. Also unwichtiges Zeug für meine Liste. Die bräuchte nur SELECT ID,NR,NAME,ORT,TELNR FROM KUNDE
Je nach Anzahl der Dataset-Felder oder der Größe des Ganzen macht sich der Unterschied sogar bei einem Einzelplatz-System richtig bemerkbar.
Jetzt zu Deinem SELECT NEXT. Im Programm mußt Du mit Dataset.First, next und DataSet.EOF hantieren. Dies bedeutet, daß eine per WHERE möglichst eingeschränkte Ergebnismenge von der Datenbank zur Verfügung steht. Sofern auch auf den * verzichtet wird, dann geht das auch Ratzfatz.
_________________ Gruß
Hansa
|
|
JRegier 
      
Beiträge: 1268
Win XP Home, Prof, 2003 Server
D6 Enterprise
|
Verfasst: Fr 19.08.05 15:19
hansa hat folgendes geschrieben: | Hi,
Du mußt etwas mehr Systematik in das Programm reinbringen. Der * hat mit Fetchall usw. nur bedingt etwas zu tun. Warum steht das Update bei dir im Source ? Dafür sind normalerweise die Zugriffskomponenten zuständig (insbesondere TDataSet und Nachfolger). Da wird der Kram hinterlegt (auch für insert, delete usw.). Im Programm benutzt Du dann nur noch Dataset.Edit um zu ändern und dann mit Dataset.Post speichern. Alternativ kann man (so mache ich es) Stored Procedures zum speichern benutzen. MySql kann das (zumindest noch) nicht.
Der * spielt bei Select allerdings schon eine große Rolle.
Beispiel : Brauche Kunden-Tel.Nr. Liste.
SELECT * FROM KUNDE liefert mir jetzt auch Skonto, Lieferadresse usw. vielleicht auch Firlefanz wie Geburtstag. Also unwichtiges Zeug für meine Liste. Die bräuchte nur SELECT ID,NR,NAME,ORT,TELNR FROM KUNDE
Je nach Anzahl der Dataset-Felder oder der Größe des Ganzen macht sich der Unterschied sogar bei einem Einzelplatz-System richtig bemerkbar.
Jetzt zu Deinem SELECT NEXT. Im Programm mußt Du mit Dataset.First, next und DataSet.EOF hantieren. Dies bedeutet, daß eine per WHERE möglichst eingeschränkte Ergebnismenge von der Datenbank zur Verfügung steht. Sofern auch auf den * verzichtet wird, dann geht das auch Ratzfatz. |
Also nochmal, ich schreibe ein Programm mit dem man sich eine DB Anwendungs - Oberfläche zusammenbaut, d.h.
ich verwende schonmal Zeos mit denen ich schon einigermaßen Universal bin um auf verschiedenste DB's zugreifen
zu können! Nun muß mein Programm die Statements zur Laufzeit beim Start erstellen, so!
Also ich habe z.B. eine N:1 Verknüpfung, so und da ist z.B. die "Slave" Tabelle mit dieser N_ID verknüpft
und es gibt auch Tabellen bei denen da Kein AutoInc Feld nicht sinnvoll ist, und wenn kein AutoInc Feld
vorhanden ist dann kann ich den Datensatz ja nur über Werte aller Felder identifizieren von daher
habe ich auch gemeint mit * zu selektieren um nur den Datensatz immer identifizieren zu können!
Aber vieleicht sollte ich eifach als Voraussetzung für mein Programm dem Anwender mitteilen dass er in jeder
Tabelle ein AutoInc Feld anlegt das würde die sache erhenblich erleichtern!
Aber nun zum Problem, Teilselektion!
Also wie hier in diesem Topic schon erwähnt wurde:
First) SELECT * FROM `tabelle` WHERE ID = SELECT MIN(ID) FROM `tabelle` LIMIT 1';
Next ) SELECT * FROM `tabelle` WHERE ID > LASTID LIMIT 1';
Prior) SELECT * FROM `tabelle` WHERE ID < LASTID LIMIT 1';
Last ) SELECT * FROM `tabelle` WHERE ID = SELECT MAX(ID) FROM `tabelle`';
Aber was ist wenn ich nach einem anderen Feld sortiere?
First) SELECT * FROM `tabelle` WHERE '+Sortierfeld+' = ' SELECT MIN('+Sortierfeld+') FROM `tabelle` LIMIT 1';
Next ) SELECT * FROM `tabelle' WHERE '+Sortierfeld+' > LastValue LIMIT 1';
...
So könnte es klappen oder?
|
|
noidic
      
Beiträge: 851
Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
|
Verfasst: Fr 19.08.05 15:20
Also ich schreibe updates und inserts ausschließlich als SQL-Statements selbst. Liegt zum grössten Teil daran, dass ich selten Statements ohne Joins habe und ich es einfach übersichtlicher finde. Allein wenn ich das Problem habe, dass irgendwas innerhalb einer Software was in ne Tabelle schreibt und ich rausfinden muss, was.
_________________ Bravery calls my name in the sound of the wind in the night...
|
|
JRegier 
      
Beiträge: 1268
Win XP Home, Prof, 2003 Server
D6 Enterprise
|
Verfasst: Fr 19.08.05 15:29
noidic hat folgendes geschrieben: | | Also ich schreibe updates und inserts ausschließlich als SQL-Statements selbst. Liegt zum grössten Teil daran, dass ich selten Statements ohne Joins habe und ich es einfach übersichtlicher finde. Allein wenn ich das Problem habe, dass irgendwas innerhalb einer Software was in ne Tabelle schreibt und ich rausfinden muss, was. |
Updates und Insert muß mein Programm aber in diesem Fall selbst erstellen, siehe mein letzter Beitrag, um welche Art Software
es sich handelt an der ich zur Zeit bastle!
Ah jetzt Fällts mir ein: Wie ich auch beim letzten Beitrag erwähnt habe wenn ich anders sortiere also nicht nach ID
dann wenn es nach mehreren Feldern Sortiert wird kann ich die Art Selection doch nicht machen, es wird nicht einfach
wenn ich da Sorierungen noch mit ASC und DESC gemischt habe! Oder, ich denke mal nach dem Ersten Feld nach dem Sortiert
wird werden alle Teildatensätze einfach Selektiert und demenstprechend die Anderen Sortiert und wenn ich EOF bekomme
kommen die nächsten Teildatensätze!
Zuletzt bearbeitet von JRegier am Fr 19.08.05 15:37, insgesamt 1-mal bearbeitet
|
|
noidic
      
Beiträge: 851
Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
|
Verfasst: Fr 19.08.05 15:36
Mein Hinweis bezog sich auf die Idee mit Dataset.Edit und .Post, also ich mache das halt auch so, wie du.
Ich glaube bei dir gibts noch eine Verwirrung mit AutoInc und Primärschlüssel.
Auch Tabellen ohne AutoInc-Feld können einen Primärschlüssel haben, evtl. auch über mehrere Felder hinweg, das ist nicht das selbe. Und über den Primärschlüssel identifizierst du die Datensätze, dazu brauchst du nicht alle Werte.
Wenn du nun Tabellen hast, wo kein Primärschlüssel ist, musst du dich auf die DB-spezifischen Möglichkeiten zur Datensatzidentifkikation verlassen ( bei Oracle z.B. die RowID ).
_________________ Bravery calls my name in the sound of the wind in the night...
|
|
JRegier 
      
Beiträge: 1268
Win XP Home, Prof, 2003 Server
D6 Enterprise
|
Verfasst: Fr 19.08.05 15:41
noidic hat folgendes geschrieben: | Mein Hinweis bezog sich auf die Idee mit Dataset.Edit und .Post, also ich mache das halt auch so, wie du.
Ich glaube bei dir gibts noch eine Verwirrung mit AutoInc und Primärschlüssel.
Auch Tabellen ohne AutoInc-Feld können einen Primärschlüssel haben, evtl. auch über mehrere Felder hinweg, das ist nicht das selbe. Und über den Primärschlüssel identifizierst du die Datensätze, dazu brauchst du nicht alle Werte.
Wenn du nun Tabellen hast, wo kein Primärschlüssel ist, musst du dich auf die DB-spezifischen Möglichkeiten zur Datensatzidentifkikation verlassen ( bei Oracle z.B. die RowID ). |
Ah kann sein, bei einem AutoInc Feld wird immer dafür gesorgt das der immer unterschiedlich ist von Datensatz zu Datensatz weil der ja
zählt! Und wer sorgt bei eine Primary Key dafür dass der bei jedem Datensatz unteschiedlich ist?
|
|
noidic
      
Beiträge: 851
Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
|
Verfasst: Fr 19.08.05 16:16
Die Datenbank. Wenn du versuchst, einen Datensatz einzufügen bzw. so zu ändern, das ein PK doppelt vorhanden wäre, schmeisst die Datenbank nen Fehler.
_________________ Bravery calls my name in the sound of the wind in the night...
|
|
hansa
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Fr 19.08.05 18:44
JRegier hat folgendes geschrieben: | | ...Und wer sorgt bei eine Primary Key dafür dass der bei jedem Datensatz unteschiedlich ist? |
Verwende dafür immer eine ID. Der Rest muß dann über UNIQUE (notfalls zusammengesetzte) und FOREIGN Keys gemacht werden. Ein Trigger vergibt die ID. Ein Generator enthält den Wert, der vom Trigger hochgezählt wird. Den Rest kann ich mir aber sparen. Trigger gehen bei MySql ja auch nicht.  Es gibt jetzt 2 Möglichkeiten : anständige DB verwenden oder neue MySql-Beta Version.
_________________ Gruß
Hansa
|
|
JRegier 
      
Beiträge: 1268
Win XP Home, Prof, 2003 Server
D6 Enterprise
|
Verfasst: Fr 19.08.05 20:58
|
|
|