Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Suche Datensenitive ExportToExcel-Funktion (https://www.delphipraxis.net/169164-suche-datensenitive-exporttoexcel-funktion.html)

Jumpy 4. Jul 2012 09:01

AW: Suche Datensenitive ExportToExcel-Funktion
 
Stimme als TE omata i. Iwo Asnet zu. Der Einwurf ist gerechtfertigt. Wir haben hier u.a. auch ein komplexes Framework für Excel, mit dem man komfortabel Reports generieren kann. Nur passt das für diese Anwendung nicht so ganz. Es handelt sich um ein internes Programm, mit dem man SQL-Statements zusammenbauen und speichern und verwalten kann. Hier kam der Wunsch auf, dass man gelegentlich die durch das gerade gebaute Statement erstellte Datenmenge (via Grid angezeigt) auch mal exporieren können sollte. CSV-Export war schnell umgesetzt und läuft super schnell. Dagegen ist der Excel-Ole-Export wirklich eine Schnecke, aber man will die Daten ja in Excel haben. Daher geh ich jetzt den o.g. Weg und schau jetzt mal, wie ich es formatiert kriege.

Ich denke aber auch mal drüber nach, ob man unser Excel-Framework so erweitern kann, dass man einem vorbereiteten Report ein SQL-Statement übergibt und Excel von da aus weiterarbeitet.

Experimetiere jetzt mal mit dem Formatieren weiter und meld mich dann mal, was bei rausgekommen ist.

tgvoelker 4. Jul 2012 09:38

AW: Suche Datensenitive ExportToExcel-Funktion
 
Das Problem liegt in der Implementierung: Excel erwartet für Range.Value eine Variante. Wenn Du einen String übergibst, dann wandelt den die Excel-Logik um - und das führt zu den beschriebenen Problemen.

Ich hatte das Problem bei TJVGExportExcel aus JVCL Globus, da war genau so vorgegangen worden.

Die lösung war, die Source zu ändern:

Code:
            if ForceTextFormat or
               (Dataset.Fields[I].Datatype in [ftString,ftMemo,ftFmtMemo,ftFixedChar,ftWideString,ftGuid
                                             ,ftFixedWideChar,ftWideMemo,ftBoolean,ftVariant,ftUnknown
                                             ,ftBytes,ftVarBytes,ftBlob,ftGraphic,ftParadoxOle
                                             ,ftDBaseOle,ftTypedBinary,ftCursor,ftADT,ftArray,ftReference
                                             ,ftDataSet,ftOraBlob,ftOraClob,ftInterface,ftIDispatch,ftOraInterval
                                             ,ftConnection,ftParams,ftStream])or
               (Dataset.Fields[I].IsNull) then Sheet.Cells[RecNo, ColNo + I] := GetFieldValue(DataSet.Fields[I])
            Else Sheet.Cells[RecNo, ColNo + I].Value :=GetFieldValueVar(DataSet.Fields[I]);
In der ursprünglichen Implementierung wurde nur die Funktion GetFieldValue aufgerufen:

Code:
function TJvgCommonExport.GetFieldValue(const Field: TField): string;
begin
  if jeoOutputFormattedStrings in Options then
    Result := Field.DisplayText
  else
    Result := Field.AsString;
  if Assigned(FOnExportField) then
    FOnExportField(Self, Field, Result);

  if FTransliterateRusToEng then
    Result := Transliterate(Result, True);

  if (FMaxFieldSize > 0) and (Field.DataType in [ftString, ftMemo, ftFmtMemo]) then
    if Length(Result) > FMaxFieldSize then
      Result := Copy(Result, 1, FMaxFieldSize) + '...';
end;
Konkret tritt das Problem bei Gleitkommazahlen und BCD auf, weil bei Field.AsString ein Punkt ausgegeben wird, anstelle eines Komma. Die Funktion GetFieldValueVar übergibt daher eine Variante:

Code:
function TJvgCommonExport.GetFieldValueVar(const Field: TField): Variant;
//Erweiterung zum korrekten export von Nicht-Zeichenkettendaten.
var i:Int64;d:DWord;
begin
  if jeoOutputFormattedStrings in Options then Begin
    Result := Field.DisplayText;
    Exit;
  End;
  if Field.DataType in [ftSmallint,ftInteger,ftWord,ftAutoInc,ftShortint,ftByte] then Result:=Field.AsInteger
  Else if Field.Datatype=ftLargeint Then Result:=Field.Value
  Else if Field.DataType=ftLongWord Then Begin
    d:=Field.Value;
    i:=d;
    Result:=i;
  End Else if Field.DataType in [ftFloat,ftExtended] Then Result:=Field.AsExtended
  Else if Field.DataType = ftCurrency Then Result:=Field.AsCurrency
  Else if Field.DataType in [ftBCD,ftFMTBcd] Then Result:=BcdToDouble(Field.AsBCD)
  Else if Field.DataType in [ftDate,ftTime,ftDateTime,ftTimeStamp,ftOraTimeStamp] Then Result:=Field.AsDateTime
  Else Result:=Null;
//  if Assigned(FOnExportField) then FOnExportField(Self, Field, Result); //Abgeschaltet, da hier zwingend ein String erwartet wird.
end;
Allerdings ist hier anzumerken, daß der export von 16T Tupeln mit 60 Spalten ewig dauerte - nach 2 Stunden habe ich den abgebrochen. Verwende nun die Native Excel Suite, da ist der Export dieser Datenmenge nach 20 Sekunden fertig.

Furtbichler 4. Jul 2012 09:59

AW: Suche Datensenitive ExportToExcel-Funktion
 
Wer in Gottes Namen benötigt 16 Tausend Zeilen mit je 60 Werten?

tgvoelker 4. Jul 2012 10:28

AW: Suche Datensenitive ExportToExcel-Funktion
 
Rechnungsdaten aus einem Geschäftsjahr.

Jumpy 4. Jul 2012 11:46

AW: Suche Datensenitive ExportToExcel-Funktion
 
Eine Frage zu #12:

Einmal wird der Zelle etwas zugewiesen via:

Sheet.Cells[RecNo, ColNo + I] :=

im anderen Fall via

Sheet.Cells[RecNo, ColNo + I].value :=

Warum?
Afaik ist .value die Default-Property des Range-Objectes, somit sind die beiden Zuweisungen (auf der linken Seite!) doch gleichwertig, oder?

p80286 4. Jul 2012 12:19

AW: Suche Datensenitive ExportToExcel-Funktion
 
Rein theoret. hast du recht, aber in der Praxis empfehle ich .Value da Excel und Word sich manchmal nicht an die Theorie halten.


Gruß
K-H

tgvoelker 4. Jul 2012 12:27

AW: Suche Datensenitive ExportToExcel-Funktion
 
Theoretisch schon. Mein erster Ansatz war daher auch, die "Sonderbehandlung" String/sonstiges nicht durchzuführen, sondern grundsätzlich als Variant zu übergeben. Dabei hatte ich aber das Problem, daß die Zellen, an die Strings übergeben wurden, einfach leer blieben. Im nächsten Schritt habe ich dann den alten Code wieder reingenommen und eine Sonderbehandlung für alles gemacht, das ich nicht als String übergeben wollte. Ich erinnere mich auch dunkel, daß ich zunächst versucht hatte, die Varianten an die Range zuzuweisen und das nicht funktionierte - weshalb ich dann .value verwendete.

Wäre das Zeitverhalten akzeptabler gewesen, dann hätte ich weitergemacht damit, die nächsten Schritte wären dann gewesen, daß Zeichenkettenfelder grundsätzlich im Excel hart als Zeichenkette formatiert worden wären (damit z.B. keine führenden Nullen weggemacht werden) und nur eine Funktion zu verwenden (schätze mal, das Excel mit dem Stringformat, welches ich ursprünglich in der Variante übergeben hatte, nicht klarkam - das wäre also ebenso anzupassen). Und natürlich, um das Zeitverhalten zu verbessern, die Übergabe das Daten Zeilenweise in einem varianten Array. Aber wie schon gesagt war das Ding so langsam, daß ich mich umorientieren mußte und das auch tat.

Edit: KH, das ist sogar ein Feature: in Abhängigkeit der Ausprägung des Range-Objekts variiert die default property. Auch wenn "Daily dose of Excel" hier: http://www.dailydoseofexcel.com/arch...trange-object/

schreibt, das läge am VBA-Parser, so bin ich eher der Ansicht, daß das implementiert wurde (warum auch immer) und zudem versionsabhängig ist.

p80286 4. Jul 2012 12:54

AW: Suche Datensenitive ExportToExcel-Funktion
 
Zitat:

Zitat von tgvoelker (Beitrag 1173498)
.. und zudem versionsabhängig ist.

Das kann man im Zusammenhang mit Word und Excel nicht laut genug betonen.

Gruß
K-H

Iwo Asnet 4. Jul 2012 13:16

AW: Suche Datensenitive ExportToExcel-Funktion
 
Es scheint sowohl eine Diskussion um Formatierung und dieses leidige "EXCEL ist klüger als Du und daher interpretiert es für dich die Daten" zu sein.

Ich empfehle die Verwendung von nativen BIFF-Writerklassen. Einige sind Freeware, andere kosten etwas. Prüfe doch, ob die Freewarekomponenten nicht ausreichend sind, deine Bedürfnisse zu erfüllen. Einge XLS-Writer basieren jedoch auf OLE, die kannst Du gleich vergessen.

Wenn man vor dem Problem steht, 2 Stunden auf die Erzeugung einer großen EXCEL-Datei zu warten (z.B. als Basis für BI-Auswertungen), dann wäre z.B. folgende Vorgehensweise relativ schnell umzusetzen und dürfte performant genug sein:
1. CSV-Datei erzeugen
2. EXCEL als OLE starten, CSV einlesen und formatieren
3. Speichern und fertig

Das ist ratzfatz umgesetzt und sollte brauchbare Ergebnisse liefern

Klar, ein Sheet mit 16k Daten als BI-Rechenbasis für die Geschäftsleitung muss schon nach was aussehen, aber so richtig interessiert sich kaum jemand für die einzelnen Daten.

Ich würde ein EXCEL Template erstellen, das alle Auswertungen bereitstellt, die Rohdaten (CSV) auf Sheet999 ;-) per OLE einlesen, hübsch machen (per Makro) und den Klotz speichern. Im Template kann man nachträglich das 'Hübschmachenmakro' erweitern, verändern etc.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:17 Uhr.
Seite 2 von 2     12   

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