Benutzer mit den meisten Antworten
Cursor mit SQL erzeugen und refreshen

Frage
Antworten
-
Hallo Martin,
um den Schreibschutz zu umgehen habe ich folgende Möglichkeit gefunden.
SELECT * FROM MyTable INTO CURSOR MyCursor NOFI
USE DBF() IN 0 ALIAS MyEditCursor AGAIN
USE IN MyCursor
SELECT MyEditCursor
Cursor unter anderem Namen noch einmal aufmachen und mit diesem weiterarbeiten.
Evtl. gibt es aber noch mehr Möglichkeiten.
Gruss Uli
- Als Antwort markiert M Blume Montag, 19. Dezember 2011 07:48
Mittwoch, 14. Dezember 2011 07:20 -
Hi Martin,
NOFI (=NOFILTER) ist eine Ergänzung der INTO CURSOR Klausel die alternativ mit NOFILTER oder READWRITE ergänzt werden kann.
Mit der Einführung von READWRITE ist es nicht mehr notwendig einen zweiten (alias) Cursor wie in Uli's Beispiel zu erzeugen. Heute können wir auf Basis von Tom K.s Beispiel arbeiten. Zumindest, wenn man eine entsprechend aktuelle Version von VFP einsetzt :-)
Gruss / Best regards -Tom 010101100100011001010000011110000101001001101111011000110110101101110011- Als Antwort markiert M Blume Montag, 19. Dezember 2011 07:48
Mittwoch, 14. Dezember 2011 12:33 -
Der Requery eines Views ist doch nichts anderes, als den View durch die erneute Abfrage der Daten zu refreshen.
Wenn Du also auf den View verzichtest, weil der View Designer Dich z.B. zu sehr einschränkt, dann bleib bei Deinem SQL und führe den Requery sozusagen zu Fuss aus. Das einzige was wegen des Grids zu beachten ist, ist, daß der SQL immer in einen Tempcursor gehen muß, der dann in den Gridcursor kopiert werden muß. Im Gridcursor machst Du ein ZAP und dann hängst per APPEND oder per INSERT INTO Gridcursor FROM SELECT * FROM Temp eben die Daten wieder ans Grid.Anders geht die Umschiffung der Gridproblematik nun einmal nicht, dafür hast Du mehr Flexibilität bei den Abfragen als in einem View möglich ist.
Du kannst allerdings auch den CREATE SQL VIEW Befehl nutzen, um eine beliebige Abfrage als View aufuzbauen, der dann den Vorteil des Requery() hat und nicht selten auch updatebar gestaltet werden kann. Für meinen Geschmack bieten Cursoradaptoren die bessere Alternative dazu und haben ebenfalls den Vorteil mittels Requery() zu funktionieren. Und ich meine wirklich Requery() und nicht Cursoradapter.CursorRefresh(). Der Cursor ist mit dem Cursoradapter verbunden und ein Requery(Cursoradapter.Alias) löst die CursorRefresh() Methode aus, genauso wie ein Tableupdate(Cursoradapter.Alias) die interaktion des Cursoradapters mit der Datenbank auslöst, alle nötigen Updates, Inserts und Deletes.
Der Mehraufwand mit Readwrite-Cursoren statt View oder Cursoradaptern hat auch auch seine Berechtigung, weil die Befüllung solcher Cursoren nicht alleine mit einem SQL bewerkstelligt werden muß, es geht auch komplexerer Code, je nachdem was den besten Kompromiss aus Performanz und Wartbarkeit ausmacht. Es stehen viele Möglichkeiten offen und es gibt kein richtig und falsch dabei, sondern alles hat seine Berechtigung.
Tschüß, Olaf.
- Als Antwort markiert M Blume Montag, 19. Dezember 2011 07:48
Samstag, 17. Dezember 2011 17:37
Alle Antworten
-
Hallo Martin,
um den Schreibschutz zu umgehen habe ich folgende Möglichkeit gefunden.
SELECT * FROM MyTable INTO CURSOR MyCursor NOFI
USE DBF() IN 0 ALIAS MyEditCursor AGAIN
USE IN MyCursor
SELECT MyEditCursor
Cursor unter anderem Namen noch einmal aufmachen und mit diesem weiterarbeiten.
Evtl. gibt es aber noch mehr Möglichkeiten.
Gruss Uli
- Als Antwort markiert M Blume Montag, 19. Dezember 2011 07:48
Mittwoch, 14. Dezember 2011 07:20 -
Hallo Uli und Tom,
Danke für die Antworten.
Natürlich habe ich viel zu wenig geschrieben, meine Schuld.
Ich erzeuge den Cursor mit Readwrite aus 3 Tabellen.
Dieser Cursor ist Grundlage eines Grids.
Wenn sich in einer der 3 Tabellen etwas ändert, soll der Cursor natürlich aktualisiert werden und dann auch das Grid.
Ohne, dass ich dem Grid die Datengrundlage entziehe und wieder zuweise.
Bei Views gibt es doch diese requery Funktion, gibt es so etwas auch für Cursor.
Ich habe mir jetzt so geholfen:
Ich erzeuge den Cursor leer mit Create Cursor und leere und fülle ihn ein einer Funktion,
die ich bei einer Änderung immer wieder aufrufe.
Mir wäre die SQL Anweisung lieber, aber wenn es so etwas nicht gibt, dann lasse ich es so.
Uli was bewirkt NOFI?
Vielen Dank und Gruss Martin
Windows XP/7 Visual FoxPro9 SP2Mittwoch, 14. Dezember 2011 10:05 -
Hi Martin,
NOFI (=NOFILTER) ist eine Ergänzung der INTO CURSOR Klausel die alternativ mit NOFILTER oder READWRITE ergänzt werden kann.
Mit der Einführung von READWRITE ist es nicht mehr notwendig einen zweiten (alias) Cursor wie in Uli's Beispiel zu erzeugen. Heute können wir auf Basis von Tom K.s Beispiel arbeiten. Zumindest, wenn man eine entsprechend aktuelle Version von VFP einsetzt :-)
Gruss / Best regards -Tom 010101100100011001010000011110000101001001101111011000110110101101110011- Als Antwort markiert M Blume Montag, 19. Dezember 2011 07:48
Mittwoch, 14. Dezember 2011 12:33 -
Der Requery eines Views ist doch nichts anderes, als den View durch die erneute Abfrage der Daten zu refreshen.
Wenn Du also auf den View verzichtest, weil der View Designer Dich z.B. zu sehr einschränkt, dann bleib bei Deinem SQL und führe den Requery sozusagen zu Fuss aus. Das einzige was wegen des Grids zu beachten ist, ist, daß der SQL immer in einen Tempcursor gehen muß, der dann in den Gridcursor kopiert werden muß. Im Gridcursor machst Du ein ZAP und dann hängst per APPEND oder per INSERT INTO Gridcursor FROM SELECT * FROM Temp eben die Daten wieder ans Grid.Anders geht die Umschiffung der Gridproblematik nun einmal nicht, dafür hast Du mehr Flexibilität bei den Abfragen als in einem View möglich ist.
Du kannst allerdings auch den CREATE SQL VIEW Befehl nutzen, um eine beliebige Abfrage als View aufuzbauen, der dann den Vorteil des Requery() hat und nicht selten auch updatebar gestaltet werden kann. Für meinen Geschmack bieten Cursoradaptoren die bessere Alternative dazu und haben ebenfalls den Vorteil mittels Requery() zu funktionieren. Und ich meine wirklich Requery() und nicht Cursoradapter.CursorRefresh(). Der Cursor ist mit dem Cursoradapter verbunden und ein Requery(Cursoradapter.Alias) löst die CursorRefresh() Methode aus, genauso wie ein Tableupdate(Cursoradapter.Alias) die interaktion des Cursoradapters mit der Datenbank auslöst, alle nötigen Updates, Inserts und Deletes.
Der Mehraufwand mit Readwrite-Cursoren statt View oder Cursoradaptern hat auch auch seine Berechtigung, weil die Befüllung solcher Cursoren nicht alleine mit einem SQL bewerkstelligt werden muß, es geht auch komplexerer Code, je nachdem was den besten Kompromiss aus Performanz und Wartbarkeit ausmacht. Es stehen viele Möglichkeiten offen und es gibt kein richtig und falsch dabei, sondern alles hat seine Berechtigung.
Tschüß, Olaf.
- Als Antwort markiert M Blume Montag, 19. Dezember 2011 07:48
Samstag, 17. Dezember 2011 17:37 -
Hallo Olaf,
ich habe mich jetzt für die Cursor-Variante entschieden.
1. weil ich den Code schon geschrieben habe und es funktioniert.
2. weil ich von Cursoradaptern nichts gewusst habe und keine Ahnung habe.
3. aktuell keine Zeit habe mich in das Thema Cursoradapter einzuarbeiten.
Es werden mir wohl einige Geheimnisse von VFP verborgen bleiben.
Trotzdem an Alle
Danke und Gruß
Martin
Windows XP/7 Visual FoxPro9 SP2Montag, 19. Dezember 2011 07:48 -
Cursoradapter sind nicht so kompliziert. Wenn Du schon Views kennst, bist Du doch schon weiter als so manch anderer. Und Du kennst das Prinzip schon im Kern.
Man hat beim CA Builder voll auf einen visuellen Abfragegenerator verzichtet, den bietet z.B. SQL Server Management Studio oder Access sowieso viel besser, aber die Viewfeatures Updateable, Keyfieldlist, Updatable Fieldlist etc. existieren für CA ja auch. Die neuen Events wie Before/AfterInsert, -Update, -Delete und viele weitere muß man ja anfags nicht nutzen.
Wie auch immer, ich sagte ja, alles hat seine Berechtigung. Die Technik mit Cursoren ZAP und APPEND wird gern bei Foxite genommen und hat da schon den Namen "Safe Select" bekommen. Oder Andy Kramek hat das schon vor Verbreitung bei Foxite so genannt. Egal, auf jeden Fall ist das hier von ihm beschrieben: http://weblogs.foxite.com/andykramek/archive/2005/03/19/174.aspx
inkl. Erläuterung, warum man einen zweiten Alias braucht und das Grid sonst sein Layout und Code verliert.Tschüß, Olaf.
- Bearbeitet Olaf Doschke Dienstag, 20. Dezember 2011 15:47
Dienstag, 20. Dezember 2011 15:44 -
Hallo Martin,
ich verwende für Deine Aufgabenstellung immer eine einfache Methode, die hier noch nicht erwähnt wurde:
1) Erstellen des Cursors mit SQL:
SELECT ... FROM .. INTO CURSOR mycursor READWRITE
(wenn mycursor initial leer sein soll, kann man einfach ein WHERE .F. im statement haben)
Für die späteren Updates dann einfach:
ZAP IN mycursor
INSERT IN mycursor SELECT ... FROM ..
(die Felder in diesem SELECT müssen anzahl- und typ-mäßig natürlich dem ersten entsprechen)
Einfacher geht's doch kaum, oder?
Gruß,
WiWo
Freitag, 10. Februar 2012 12:17 -
...Für die späteren Updates dann einfach:
ZAP IN mycursor
INSERT IN mycursor SELECT ... FROM ...
WiWo, das wurde doch schon gesagt...
...SQL immer in einen Tempcursor gehen muß, der dann in den Gridcursor kopiert werden muß. Im Gridcursor machst Du ein ZAP und dann hängst per APPEND oder per INSERT INTO Gridcursor FROM SELECT * FROM Temp eben die Daten wieder ans Grid....
Statt Temp cursor schlägst Du nur gleich INSERT INTO gridcursor SELECT ... nach dem ZAP vor.
Das spart einen Umkopierschritt, aber Du hast dann den SQL-Select einmal an der Stelle als INSERT INTO ... SELECT und einmal beim initialisieren ud hast zwei Stellen zu ändern, wenn die Abfrage sich ändern soll.
Mal abgesehen davon wird intern so eine INSERT ... SELECT Abfrage auch mit einem temp Ergebnis gemacht und nicht direkt in den Zielcursor selektiert, soweit ich weiß. Das hat also auch keinen echten Performancevorteil.
Um das zu überprüfen, mach einfach mal folgendes:
Close Tables All Use browser In 0 Copy To (Addbs(GetEnv("TEMP"))+"insertselect.dbf") For .F. Use (Addbs(GetEnv("TEMP"))+"insertselect.dbf") In 0 Insert into insertselect Select * from browser where debug() Procedure debug() Set Step On Endproc
Während des SQLs werden zusätzlich zu browser.dbf und insertselect.dbf noch die Aliase C,D und E geöffnet und Interselect.dbf bleibt leer, es sammeln sich die Datensätze in C und E erst am Schluss wird die Zieltabelle befüllt.
Von daher spricht auch nichts dagegen selbst einen tempcursor zu generieren und per append an den gezappten gridcursor zu hängen.
INSERT...SELECT hat demnach keinene Performancevorteil. und wie schon angedeutet: Der Nachteil von INSERT...SELECT ist es, nur ein zweites Statement nach dem initialen erzeugen des Gridcursors sein zu können, man hat also einen SELECT ... INTO gridcursor und einen INSERT INTO gridcursor SELECT....
Es sei denn Du machst Dir immer den Aufwand den Gridcursor vorab per CREATE CURSOR zu generieren.
Ich ziehe vor, denselben SQL als initiale und als refresh Abfrage auszuführen, dazu muß nur das Ziel initial der Gridcursor und ab dem zweiten Mal ein Tempcursor sein, was leicht per INTO CURSOR (lcZielalias) machbar ist, mit lcZielalias je nach Fall.
Tschüß, Olaf.
Sonntag, 12. Februar 2012 09:12 -
Hallo Olaf,
weshalb ich inzwischen "meine" Lösung favorisiere liegt daran, dass in den meisten Fällen bei mir die Update-SQL-Selects doch irgendwie variieren. Da die Macro-Auflösung bei den Views bereits an der Stelle geschieht, wo das SELECT steht, kann man eigentlich nichts mehr variabel gestalten oder muss irgendwelche Klimmzüge mit sehr komplizierten und verschachtelten Abfragen machen, was mir nicht so liegt und letztlich auch laufzeit-intensiv ist.
Gruß,
Winfried
Dienstag, 14. Februar 2012 12:28 -
Hallo Olaf,
weshalb ich inzwischen "meine" Lösung favorisiere liegt daran, dass in den meisten Fällen bei mir die Update-SQL-Selects doch irgendwie variieren. Da die Macro-Auflösung bei den Views bereits an der Stelle geschieht, ...
Wer sprach denn von Views? Ich sprach von "der Abfrage", wobei das auch eine abgetrennte Methode sein kann, die direktes SQL into cursor (readwrite) nutzt, datenzugriffsklassen, cursoradadaptoren, was auch immer.
Ich sprach z.B. von INTO CURSOR (lcZielalias) und diese Klausel hat ein View ja schon gar nicht.
Nennen wir es doch einfach DatenRefresh-Methode, die aber über diverse Parameter aufgerufen wird. Aber dann idealerweise eben für den Erstzugriff den Gridcursor generiert und in allen weiteren Aufrufen den Gridcursor nur nach ZAP neu befüllt.
In den meisten einfachen Fällen wird diese Methode ein einzelnes SQL absetzen können, was aber für die Wiederverwendbarkeit kein INSERT INTO gridcursor sein kann, wenn der initial noch nicht da ist. Wenn Du wie auch immer genau zwischen DatenRefresh und DatenInit unterscheidest, hast Du ja wenigstens zwei Abfragen. Das paßt natürlich zu Deiner Aussage, daß bei Dir die SQL-Select sowieso variieren. Dann stört das die Wartbarkeit vielleicht weniger, aber vielleicht nutzt Du dann auch eine zu kleine Kanonengröße für den Spatz ;).
Tschüß, Olaf.
- Bearbeitet Olaf Doschke Donnerstag, 16. Februar 2012 13:07
Donnerstag, 16. Februar 2012 13:05