Avatar billede peterfa Nybegynder
04. august 2007 - 13:07 Der er 5 kommentarer og
1 løsning

Indsætte grafstruktur - hvordan findes id'er

Hej

Jeg er igang med et projekt hvor jeg skal lave en database der indeholder records over nogle hændelser i et kundeservice system. Disse hændelser er organiseret i en grafstruktur (noget der minder meget om en træstruktur på hovedet). Hver hændelse har således 2 parents (pånær "root hændelser") og mulighed for 1 child.

Min opgave er at hente database records for de her hændelser fra en række databaser (identiske i struktur, men forskellig) data, og så samle dem i en database og lave lidt kalkulering af værdier til noget OLAP agtigt analyse. Problemet er hvordan jeg får givet dem en id, så at de forskellige records kan referere til hinandens id.  Jeg kan ikke genbruge de id's de har i de enkelte databaser (da de ikke er unikke på tværs af source databaserne).

Problemet er således lidt simplificeret, at jeg skal indsætte A som skal referere B i et child felt, og derefter indsætte B som skal pege på A i et parent felt. jeg kan derfor ikke se hvordan jeg fx kan bruge en autogenereret id, da jeg jo så ikke kender den på det tidspunkt hvor den skal bruges.

Er løsningen at smække alle nodesne ind, se hvilken id de får, og så opdatere hele baljen, eller findes der en smartere løsning til det her?
Avatar billede hrc Mester
04. august 2007 - 18:01 #1
Kan du evt. behandle grafstrukturens data før du gemmer i databasen? Det må alt andet lige være hurtigere end at gemme og efterbehandle.
Avatar billede peterfa Nybegynder
04. august 2007 - 19:34 #2
Jeg kan sagtens behandle dataen inden, så er selvfølgeligt en mulighed at lade min applikation generere unikke id'er og tildele til dem. Import processen er altid "serialiseret", så man kunne måske gemme en "new_id_counter" et andet sted i databasen, og så fortsætte fra den hver gang import koden kører.
Avatar billede peterfa Nybegynder
05. august 2007 - 00:43 #3
Har det fået til at virke med fra applikationen at tildele en unik id til hver record, og så i en "property" tabel at gemme hvor langt jeg kom efter hver import run. Smider du et svar? Vil i øvrigt gerne høre fra folk hvis der er nogle best-practice/smarte måder at holde styr på den her applikations id på.
Avatar billede hrc Mester
05. august 2007 - 20:25 #4
Jeg kan godt smide et svar (hermed gjort). Lige et spørgsmål til det sidste du nævner, at A peger på B, men at B også peger tilbage på A. Er det nødvendigt at B kender A?

Det er ikke det store problem hvis du har hele din grafstruktur i hukommelsen á la (kodeeksempel i Delphi):

type
  TData = class
  private
    fUniqueID : integer;
    fChild : TData;
    fParent1 : TData;
    fParent2 : TData;
  public
    constructor Create(aUniqueID : integer);
    property UniqueID : integer read fUniqueID;
    property Parent1 : TData read fParent1 write fParent1;
    property Parent2 : TData read fParent2 write fParent2;
    property Child : TData read fChild write fChild;
    procedure WriteRecord(aQuery : TADOQuery);
  end;

...

  procedure TData.WriteRecord(aQuery : TADOQuery);
  begin
    aQuery.SQL.Text :=
      'insert into data'+
      '  (ID, Parent1ID, Parent2ID, ChildID)'+
      '  values (:ID, :Parent1ID, :Parent2ID, :ChildID)';
    aQuery.Parameters.ParamByName('ID').Value := fUniqueID;
    with aQuery.Parameters.ParamByName('Parent1ID') do
      if assigned(fParentID1) then
        Value := fParentID1.UniqueID
      else
        Value := NULL;
    with aQuery.Parameters.ParamByName('Parent2ID') do
      if assigned(fParentID2) then
        Value := fParentID2.UniqueID
      else
        Value := NULL;
    with aQuery.Parameters.ParamByName('ChildID') do
      if assigned(fChildID) then
        Value := fChildID.UniqueID
      else
        Value := NULL;
    aQuery.ExecSQL;
  end;

.. Indlæsningen må ske i en overordnet klasse der kan administrere træet og foretage søgninger i det (en eller anden objektliste-klasse):

  TDataContainer.ReadData;
  var
    Query : TADOQuery;
    Data : TData;
    Parent1, Parent2, Child : TData;
  begin
    Query := TADOQuery.Create(nil);
    try
      ...
      Query.SQL.Text := 
        'select ID, Parent1ID, Parent2ID, ChildID from data';
      Query.Open;
      while not Query.Eof do
      begin
        Data := TData.Create(Query.FieldByName('ID').Value,
                            Query.FieldByName('Parent1ID').Value,                                         
                            Query.FieldByName('Parent2ID').Value,
                            Query.FieldByName('ChildID').Value);

        Add(Data); // Føj til contailer

        Parent1 := Lookup(Data.Parent1ID);
        if assigned(Parent1) then
        begin
          Parent1.ChildID := Data;
          Data.Parent1 := Parent1;
        end;

        Parent2 := Lookup(Data.Parent2ID);
        if assigned(Parent2) then
        begin
          Parent2.ChildID := Data;
          Data.Parent2 := Parent2;
        end;

        Child := Lookup(Data.ChildID);
        if assigned(Child) then
        begin
          if assigned(Child.Parent1) then
            Child.Parent2 := Data
          else
            Child.Parent1 := Data;
          Data.Child := Child;
        end;
        Query.Next;
      end;
    finally
      Query.Free;
    end;
  end;

  TDataContainer.WriteData;
  var
    i : integer;
    Data : TData;
    Query : TADOQuery;
  begin
    // Begin work
    try
      for i := 0 to Count - 1 do
      begin
        Data := Items[i] as TData;
        Data.WriteRecord(Query);
      end;
      // Commit work
    except
      // Rollback work
    end;
  end;
 

Indlæsningen vil blive lidt tung, men ikke noget der skulle kunne mærkes (medmindre det bliver kodet i VB (!)). Så fik du lige mit bud.
Avatar billede peterfa Nybegynder
06. august 2007 - 18:26 #5
Takker for inputtet. Tror jeg ender med at gå noget i den retning. Din sidste post blev også en kommentar så du må da gerne lige smide et svar =)
Avatar billede peterfa Nybegynder
15. april 2008 - 16:19 #6
Lukker selv pga manglende svar.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester