Seite 1 von 1

Alle Rows von Resultset in Array eintragen

Verfasst: Sa, 05.01.2019 18:40
von Stephan
Hallo,

Mit Sicherheit wurde der Kern des Thema hier bereits diskutiert, 2 Threads dazu habe ich nachgelesen, aber vielleicht gibt es Neuigkeiten...

Ich führe bei einer in LO angemeldeten DB eine ganz normale Abfrage durch, z.B.:

Code: Alles auswählen

oBaseContext = CreateUnoService("com.sun.star.sdb.DatabaseContext")
oDataSource = oBaseContext.getByName(DB_name)
oCon_3 = oDataSource.getConnection(sUser, sPassword)
sql_string = "Select * FROM ""Person"" ORDER BY ""Nachname"" ASC"
oStatement = oCon_3.createStatement()
oStatement.ResultSetType = 1005
oAbfrageergebnis = oStatement.executeQuery(sql_string)
um nun alle Zeilen (Rows) des Resultsets (oAbfrageergebnis) in ein Array zu bekommen gehe ich wie folgt vor:

Code: Alles auswählen

'...
Do While oAbfrageergebnis.Next
	Redim listeninhalt(16)
	listeninhalt(0) = oAbfrageergebnis.getString(1)
	listeninhalt(1) = oAbfrageergebnis.getString(2)
	listeninhalt(2) = oAbfrageergebnis.getString(3)
	listeninhalt(3) = oAbfrageergebnis.getString(4)
	listeninhalt(4) = oAbfrageergebnis.getString(5)
	listeninhalt(5) = oAbfrageergebnis.getString(6)
	listeninhalt(6) = oAbfrageergebnis.getString(7)
	listeninhalt(7) = oAbfrageergebnis.getString(8)
	listeninhalt(8) = oAbfrageergebnis.getString(9)
	listeninhalt(9) = oAbfrageergebnis.getString(10)
	listeninhalt(10) = oAbfrageergebnis.getString(11)
	listeninhalt(11) = oAbfrageergebnis.getString(12)
	listeninhalt(12) = oAbfrageergebnis.getString(13)
	listeninhalt(13) = oAbfrageergebnis.getString(14)
	listeninhalt(14) = oAbfrageergebnis.getString(15)
	listeninhalt(15) = FORMAT(oAbfrageergebnis.getString(16),"DD.MM.YYYY")
	listeninhalt(16) = oAbfrageergebnis.getString(17)
		
	gesamtarr(jj-jjj) = listeninhalt()
		
	jj = jj + 1
Loop

'oder verkürzt (von dem einen FORMAT() abgesehen:
Do While oAbfrageergebnis.Next
	Redim listeninhalt(16)
	For i = 0 To 16
		listeninhalt(i) = oAbfrageergebnis.getString(i+1)
	Next i
	'...
Loop
Dieser Code funktioniert auch, aber ist langsam.

Gibt es eine Alternative, die schneller ist? Ich fürchte nein, aber vielleicht übersehe ich doch etwas.


Wozu soll das dienen:
Das Array gesamtarr() lässt sich direkt in ein Grid (com.sun.star.awt.grid.UnoControlGrid) schreiben, z.B.:

Code: Alles auswählen

dia_datenbrowser.getControl("MyGrid_6").Model.GridDataModel.addRows(zeilennamen(), gesamtarr())
was natürlich richtig schnell ist (gegenüber dem zeilenweisen Dateneintragen ins Grid). Das nutzt nur nichts solange das Erzeugen des Arrays so langsam ist.



Gruß
Stephan

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Sa, 05.01.2019 18:49
von RobertG
Hallo Stephan,

vielleicht ist dieser Eintrag schon eine Bremse:

Code: Alles auswählen

oStatement.ResultSetType = 1005
Mit diesem Typ kannst Du in den Datensätzen hin- und her scrollen. Er berücksichtigt zusätzlich noch Änderungen an den Originaldaten. Standard ohne diese Einstellung ist Typ 1007 - der lässt nur das Lesen in eine Richtung zu. Das ist ja genau das, was Du machen willst.

Gruß

Robert

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Sa, 05.01.2019 20:07
von Stephan
Hallo Robert,
Mit diesem Typ kannst Du in den Datensätzen hin- und her scrollen.
ja, ich weiß, Ich verwende das weil ich aus Gewohnheit Folgendes tue um die Anzahl der DS zu ermitteln:

Code: Alles auswählen

oAbfrageergebnis.last
result_max = oAbfrageergebnis.Row
oAbfrageergebnis.beforeFirst
Auf die 1005 zu verzichten macht es tatsächlich schneller (ca. 25%), was ich garnicht angenommen hätte, aber 1200 Datensätze brauchen immer noch 3 Sekunden.

Ich hatte schon die Idee die Daten im Hintergrund zu laden, weil das ein mehrseitiger Dialog ist und es genügen würde initial nur das Grid auf der ersten Seite mit Daten zu bestücken, da spielen aber die Grid-Steuerelemente nicht mit, denn irgendwie behindern die sich gegenseitig, d.h. eher nicht alles geladen ist kannst Du auf Dialogseite 1 nichts anklicken und bist zum Warten verdammt. Ich habe auch schon versucht die Grids die gerade bearbeitet werden zu deaktivieren, aber das hebt die Wechselwirkung im Dialog nicht auf.

"Wechselwirkung"?
Ich bin im Moment zu faul eine Beispieldatei fürs Forum zu erstellen, aber der Effekt ist schnell erklärt:
Ein vierseitiger Dialog (Step 1 bis 4) hat auf jeder Seite ein Grid (die Grids sind jeweils fast dialogfüllend und in gleicher Position) und jede Datenzuweisung auf ein beliebiges Grid klaut dem eigentlich sichtbaren Grid kurzzeitig den Fokus, so das jeder Mausklick ein Glücksspiel ist wo er landet.
Ohnehin ist es so, das auch mit Abwarten und ohne jede Mausaktion, nach dem Füllen aller Grids man anschliessend kurz den Dialog (per Code) von Step 1 auf 2 und zurück umschalten muss, sonst lässt sich im Grid auf Seite 1 nicht vernünftig scrollen, sondern das Grid scrollt einige Zeilen und springt dann wieder in Ausgangsposition.
(LO 6.0.3 Windows)


Gruß
Stephan

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Mo, 07.01.2019 17:46
von Toxitom
Hallo Stephan,

Dein geposteter Code ist leider nicht vollständig... insbesondere die Zeile

Code: Alles auswählen

gesamtarr(jj-jjj) = listeninhalt()
würde mich näher interessieren.

Du schreibst etwas von 1200 Datensätzen... ist das immer fix? oder wie wird dieser Wert festgestellt?

Bei meinen Tests haben sich nicht unbedingt die For-Schleife oder die Until-Schleife als "Bremse" erwiesen - wobei beide natürlich in Basic deutlich langsamer sind als in C++ oder Python... sondern die Dimensionierung des Arrays. Jede Vergrößerung "verbraucht" richtig Zeit - insofern die Frage?

Anderer Tipp: gar nicht alle Datensätze einlesen - sondern nur die, die auch angezeigt werden können (also typischerweise 20 oder so) - mit dem SQL Befehl "limit 20" am Ende. Rest erst dann einlesen, wenn tatsächlich gescrollt wird... oder Zeitversetzt dann eben nach Anzeige der ersten 20 Datensätze.

Viele Grüße
Tom

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Mo, 07.01.2019 22:30
von Stephan

Code: Alles auswählen

gesamtarr(jj-jjj) = listeninhalt()
das ist leicht zu erklären:
es gibt insgesamt 2 Resultsets die nacheinander durchlaufen werden müssen und jj ist die Variable die über alle Resultsets läuft und für die Fortschrittsanzeige genutzt wird. jjj hingegen ist die Variable die den Anfang der Abarbeitung des 2. Resultsets kennzeichnet.
gesamtarr() enthält schlussendlich pro Zelle alle Werte für eine Gridzzeile als Array und wird später so zugewiesen:

Code: Alles auswählen

dia_datenbrowser.getControl("MyGrid_6").Model.GridDataModel.addRows(zeilennamen(), gesamtarr())
Du schreibst etwas von 1200 Datensätzen... ist das immer fix
Das ist die Anzahl der derzeitigen Testdatensätze. Diese Anzahl ist veränderlich und wird anwachsen, wenn mehr Datensätze in die Datenbank aufgenommen werden.
Anderer Tipp: gar nicht alle Datensätze einlesen - sondern nur die, die auch angezeigt werden können (also typischerweise 20 oder so) - mit dem SQL Befehl "limit 20" am Ende. Rest erst dann einlesen, wenn tatsächlich gescrollt wird...
Das ist eine interessante Idee, das werde ich probieren.


Überhaupt mir diese ganze Arbeit zu machen hat nur den Grund das auf einem Kundensystem der schnelle Code (nachfolgend für odb-Dokument und nicht für eine Extension) zu keiner sauberen Anzeige führt (LO 6.x UBUNTU 18.04):

Code: Alles auswählen

Sub datentabelle_zeigen(welche As String, sortierung As String)
	'sortierung: auf-aufsteigend, ab-absteigend
	'welche: f-Firmen, p-Personen 
	
	Dim URL as New com.sun.star.util.URL
	Dim Args(5) as New com.sun.star.beans.PropertyValue
	Dim Dispatch As Object
	
	DatabaseContext1 = createUnoService("com.sun.star.sdb.DatabaseContext")
	Datenquelle1=DatabaseContext1.getByName(ThisDatabaseDocument.URL)
	Verbindung = Datenquelle1.GetConnection("","")
	
	If welche = "f" And sortierung = "auf" Then
			sql="Select * FROM ""Firma"" ORDER BY ""Firmenname"" ASC"
		ElseIf welche = "f" And sortierung = "ab" Then
			sql="Select * FROM ""Firma"" ORDER BY ""Firmenname"" DESC"
		ElseIf welche = "p" And sortierung = "auf" Then
			sql="Select * FROM ""Person"" ORDER BY ""Nachname"" ASC"
		ElseIf welche = "p" And sortierung = "ab" Then
			sql="Select * FROM ""Person"" ORDER BY ""Nachname"" DESC"
		Else
			Msgbox "Fehler"
			Exit Sub
	End If
	
    URL.Complete = ".component:DB/DataSourceBrowser"
    Dispatch = StarDesktop.queryDispatch(URL,"_Blank",8)

    Args(0).Name = "ActiveConnection"
    Args(0).Value = Verbindung
    Args(1).Name = "CommandType"
    Args(1).Value = 2
    Args(2).Name = "Command"
    Args(2).Value = sql
    Args(3).Name = "ShowMenu"
    Args(3).Value = True
    Args(4).Name = "ShowTreeView"
    Args(4).Value = False
    Args(5).Name = "ShowTreeViewButton"
    Args(5).Value = False

    Dispatch.dispatch(URL, Args)
End Sub


Gruß
Stephan

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Mo, 07.01.2019 23:03
von Stephan
Das ist eine interessante Idee, das werde ich probieren.
Das Laden geht so tatsächlich schnell, aber derweil ich gerade nachdachte wie ich den Beginn des Scrollens per Ereignis abfange fällt mir ein das sich beim teilweisen Laden der Werte ins Grid dann ja ständig die sichtbare Größe des Scrollbalkens ändert und das ist optisch totaler Mist.
(mich nervt schon das Verhalten von OO/LO das wenn man in Base mal schnell eine große Datentabelle öffnet, das häufig die Darstellung nicht richtig ist und man erst per ">|" zum letzten Datensatz springen muss damit OO/LO sich bequemen die Anzeige 'Datensatz <Nummer> von <Gesamtanzahl>' richtig anzuzeigen)


Gruß
Stephan

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Do, 10.01.2019 18:47
von F3K Total
Hallo Stephan,
es ist vielleicht etwas umständlich, aber man kann ja Abfragen, Ansichten und Tabellen, nach Calc dynamisch importieren.
Da ist dass Array bereits fertig.
Wenn du einen Weg findest die Calc Datei, im Hintergrund geladen, immer aktuell zu halten, sollte das Befüllen des Grids im Dialog in Sekundenschnelle funktionieren, siehe Beispieldatei anbei. Diese Datei ist natürlich nicht dynamisch mit der DB verbunden.

Gruß und viel Erfolg
R

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Fr, 11.01.2019 16:58
von Stephan
Wenn du einen Weg findest die Calc Datei, im Hintergrund geladen, immer aktuell zu halten, sollte das Befüllen des Grids im Dialog in Sekundenschnelle funktionieren
Danke für die Idee, aber das ist doch aber kein Vorteil gegenüber der Möglichkeit gleich ein Array im Hintergrund aktuell zu halten, denn die Datei muss zunächst einmal geladen werden, was doch wahrscheinlich länger dauert als die ca. 3 Sekunden die ich fürs erstellen des Array brauche. Ich will jetzt nicht sagen das eine einfache Calc-Datei nicht auch schneller zu laden wäre, nur in Praxis sieht es doch häufig so aus das Ladenzeiten für ein- und dieselbe Datei stark differieren weil OO/LO noch irgendwas im Hintergrund 'rumrödeln'.

(bitte kein Missverständnis, derzeitig lade ich tatsächlich das Array (bzw. 2 Arrays) jedes Mal erneut, das könnte ich tatsächlich einsparen, und diese nur einmalig laden und danach immer aktuell halten, solange die LO-Sitzung läuft)


Gruß
Stephan

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Fr, 11.01.2019 17:10
von F3K Total
Naja,
hast du meine Datei mal ausprobiert? Das 1200 Zeilen Tabellenkontrollfeld ist in sofort da, weil es so schnell geht das Calc-DataArray einzulesen.
Ich bin nun schon Stunden auf der Suche nach einem Listener, der es detektiert, wenn eine Änderung in der Datenbank vorgenommen wird, wenn ich den finden würde, wäre das Problem meiner Meinung nach gelöst. Denn dann bräuchte man die Calc-Datei nur dann zu aktualisieren, wenn der Datenbankinhalt geändert wurde.
Hast du dazu eine Idee?
EDIT zur Info: Das Aktualisieren der verknüpften Calcdatei mit 1200 Zeilen, vor dem Öffnen des Dialoges, dauert es mit meinem 32-Bit -3GB Rechner nur 0,75 s, das Öffnen des Dialoges dann nochmal 0,1 s.
Gruß R

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Fr, 11.01.2019 17:33
von Stephan
hast du meine Datei mal ausprobiert?
ja, aber ich bekam einen Laufzeitfehler in:

Code: Alles auswählen

 oDataModel.addRows (aHeading(),aData)
und hatte das nicht weiter verfolgt.

OK, ich habe es jetzt verfolgt, es lag an meiner Office-Version, in LO 6.0.3 läuft das Makro durch.
Das 1200 Zeilen Tabellenkontrollfeld ist in sofort da, weil es so schnell geht das Calc-DataArray einzulesen.
Ja, klar, auch will ich ja nicht Deine Lösung schlechtreden, nur bevor es schnell gehen kann muss die Datei offen sein. Deine Idee wäre tadellos wenn meine Daten ohnehin in der Calc-Datei wären, denn dann müsste der Anwender ohnehin damit leben wie langsam die Calc-Datei lädt.
Hast du dazu eine Idee?
Nein, nicht auf die Schnelle.
Für meine Zwecke wäre das aber auch garnicht nötig, denn ich speichere alle Änderungen der Datenbank ohnehin per Makro-Code (es gibt keine Formulare, nur Basic-Dialoge zur Datenanzeige), kein Problem also jeweils eine Calc-Datei zusätzlich zu aktualisieren.


Gruß
Stephan

Re: Alle Rows von Resultset in Array eintragen

Verfasst: Fr, 11.01.2019 17:40
von Stephan
EDIT zur Info: Das Aktualisieren der verknüpften Calcdatei mit 1200 Zeilen, vor dem Öffnen des Dialoges, dauert es mit meinem 32-Bit -3GB Rechner nur 0,75 s,
Das wäre hinreichend schnell, weil das Speichern von Datensatzänderungen in der Gesamtanwendung ohnehin etwas dauert, so das diese Zeit nicht ins Gewicht fiele.
das Öffnen des Dialoges dann nochmal 0,1 s
ja, das merkt man, das ist prima schnell, auch rein vom 'optischen Gefühl' her, wenn ich es laufen lasse, praktisch keine merkliche Verzögerung.


Gruß
Stephan