Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   PL SQL: Zerlegen eines BLOBs (https://www.delphipraxis.net/112704-pl-sql-zerlegen-eines-blobs.html)

sirius 25. Apr 2008 16:43


PL SQL: Zerlegen eines BLOBs
 
Ich spiele derzeit etwas mit Stored Procedures in Oracle rum. Mein Ziel ist, dass ich eine Reihe von Zahlenwerten in einem BLOB (o.ä.) an die SP übergebe. Die SP holt mir dann die Werte aus dem BLOB wieder raus und schreibt sie einzeln in die Datenbank. Ich hoffe, dass dies schneller geht als 10000 Inserts abzusetzen. (Nebenbei wäre es als Schnittstelle in der Datenbank recht günstig.)

Während des Testens habe ich mal folgende SP:
SQL-Code:
CREATE OR REPLACE PROCEDURE "DB1"."TEST" (Daten in BLOB, Amount
    in Integer, Res out Float, Tmp out varChar2)
is
lBuffer VarChar2(30);
lAmount Integer;
lPos Integer:=1;
begin
  lAmount:=Amount;
  dbms_lob.read(Daten,lAmount,lPos,lBuffer);
  tmp:=lBuffer;
  Res := to_number(lBuffer); -- 
end;
Ich greife über ADO (Oracle DB Provider) zu.
Delphi-Quellcode:
var mem:TStream;
    Tmp,Res,BlobParam:TParameter;
begin

  SP.Parameters.Clear;

  BlobParam:=SP.Parameters.CreateParameter('Blob', ftblob, pdinput, 0, null);
  SP.Parameters.CreateParameter('Amount', ftInteger, pdinput, 0, 5); //Länge einer Zahl im Blob
  Res:=SP.Parameters.CreateParameter('Res', ftFloat, pdOutput, 0, 0);
  Tmp:=SP.Parameters.CreateParameter('tmp', ftwidestring, pdOutput, 30, ''); //hier Rückgabe des Buffers
 
  mem:=TStringstream.Create('1.254'); // oder 1,254
  BlobParam.LoadFromStream(mem, ftblob);
  mem.free;
 
  SP.ExecProc;
 
  memo1.lines.Add(Res.Value); // --> 1E126
  memo1.lines.add(Tmp.Value); // --> 312E323534
end;
Nun erhoffe ich mir im Parameter Res die 1,254. Das kann allerdings nicht klappen, da nach dms_lob.read in lBuffer mein BLOB-Auschnitt hexadezimal landet, wie man an Tmp.Value erkennen kann.

Wie bekomme ich daraus eine Fließkommazahl? Oder anders: Kann ich den BLOB auch lesen? Irgendein sinnvoller Typecast würde mir auch reichen. Ich muss ja die Zahlen nicht im Klartext in den BLOB schreiben. Ich kann in dem Stream den Double-Wert auch direkt eintragen (nicht als String)

sirius 27. Apr 2008 16:52

Re: PL SQL: Zerlegen eines BLOBs
 
*piep*

Elvis 27. Apr 2008 18:41

Re: PL SQL: Zerlegen eines BLOBs
 
Zitat:

Zitat von sirius
*piep*

Ich wollte dir erst antworten, wenn ich es in der freien (ersten) Version von AnyDAC getestet hatte.
Mit ADO bist du ziemlich am ... Rektum ... Features angeht, die jenseits von dem sind, was MSSQL kann.
Du kannst damit keine Objekte übergeben und auch keine Arrays von einfachen Typen.

Mit einer Bibliothek, die dir Arrayparameter ermöglicht, könntest du direkt eine Liste übergeben und in einem Postback in die DB schieben.

Du solltest dir erstmal die Liste anlegen:
SQL-Code:
create or replace type DeinSchema.TIntegeList is table of Integer;
Der nötige Code um solch eine Liste möglichst effizient in die DB zu schieben wäre bulk DML.
In Oracle wird das über "forall" gelöst:
Delphi-Quellcode:
begin
  forall i in :deineListe.First .. :deineListe.Last
    INSERT INTO DeinSchema.DeineTabelle
      (DeineSpalte)
    VALUES
      (:deineListe(i));
end;
Auf die Art sparst du dir die ständigen Context switches zwischen SQL und PL/SQL Engine für jeden Datensatz. (Die beiden sind in Ora STRIKT getrennt, mit unterschiedlichen Typen und Features).

Wie gesagt, ich habe es nicht mit AnyDAC1 getestet, kann dir dazu also nix sagen.
Wenn Delphi dir nicht wichtig ist, kann ich dir Beispiele für .Net aus den Fingern saugen. ;-)

sirius 28. Apr 2008 11:03

Re: PL SQL: Zerlegen eines BLOBs
 
Danke Dir, ich habe damit mal ein bisschen rumgespielt. Auf der SQL-Seite ist es (derzeit) kein Problem.
Nur ich bekomme das Array / die Liste / das Objekt nicht aus Delphi rüber. Habe es mit AnyDAC1 probiert. Ich schaffe es nicht, der Komponente das Objekt zu übergeben / bzw. ihm den Datentyp TIntegerList bekannt zu machen.

Auf .Net wollte ich jetzt nicht umsteigen.



Edit:
Viele Varianten versucht und eine ist bisher geglückt.
Ich habe deine Idee eines Tabellentyps übernommen:
SQL-Code:
create or replace type DeinSchema.TIntegerList is table of Integer;
Meine Test-SP sieht mal so aus:
SQL-Code:
Create or Replace Procedure DB1.Test
(Daten in TIntegerList, Amount in Integer, Res out Integer)
is
i Integer; -- for future use *g*
begin
  res:=Daten(Amount);
end;
Und in Delphi habe ich auf Grund dieses Threads
mit den Direct Oracle Access Komponenten folgendes implementiert:
Delphi-Quellcode:
var oraObj:TOracleObject;
begin
  oraObj:=TOracleObject.Create(OracleSession1,'TIntegerList','');
  try
    oraObj.Elements[0]:=13;
    oraObj.Elements[1]:=20;

    OracleQuery1.DeclareVariable('Daten',otObject);
    OracleQuery1.DeclareandSet('Amount',otInteger,1);
    OracleQuery1.DeclareVariable('Res',otInteger);
    OracleQuery1.SetComplexVariable('Daten',oraObj);
    OracleQuery1.SQLW:='begin test(:Daten, :Amount, :Res); end;';
    ORacleQuery1.Execute;
  finally
    OraObj.Free;
  end;
  showmessage(OracleQuery1.GetVariable('Res')); // --> 13

  //OracleQuery1.Close;
end;
Funktioniert.
(Jetzt nagel ich mich hoffentlich nicht zu sehr mit den Komponenten auf Oracle fest. Wobei ich jetzt auch nicht die Machbarkeit dieser SP in mySQL beurteilen kann.)

Jetzt interessiert mich natürlich die Funktionalität dahinter. Und: Warum geht es mit ADO oder anyDAC nicht? Vielleicht war ich nur zu blöd (bei letzterem).

sirius 29. Apr 2008 20:08

Re: PL SQL: Zerlegen eines BLOBs
 
Edit2: gestrichen, ich mach dazu einen neuen Thread auf (neue Frage und passt nicht mehr zum Titel)
Edit3: Da ist er


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:08 Uhr.

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