SQL and Delphi: recursive mechanism for creating a tree from a table SQL and Delphi: recursive mechanism for creating a tree from a table mysql mysql

SQL and Delphi: recursive mechanism for creating a tree from a table


I suggest you not load the whole tree at once, why should you ? no man can view at the moment a thousand of items. And it can be long and your program would look frozen. And it makes a huge load pike over network and server.

You better use VirtualTreeView approach, where each item loads its children items on request. That would require one parametrized prepared query like

 Select ID, Title, This, That from TREE where Parent_ID = :ID

And yes, don't make new SQL text for every item. It is both dangerous and slow (you need to drop all the data gathered for an old request and parse the new one)

You should make one parametrized query, Prepare it and just do close/change param values/open.

See reasons and Delphi sample at http://bobby-tables.com/


One example of "load it all at once altogether" rush is at dynamically create popup menu tree from sql server table in Delphi - though i don't think rush is good approach for more or less large trees.

Note about this approach: you fill in root elements, then you find one way or another to fill in elements, not filled yet, but already referenced by others until there is no such elements at last.

You can do it recursively of course, traversing tree to its ends - but that would ask for many nested database queries.

You may make a recursive SQL request, but it would probably be very server-dependent and RDBMS engines usually impose their limits on recursion depth.

An approach maybe slightly worse on tree control but more clean and easier on RDBMS would be to make a dedicated TQueue of just added tree items. After you load some element - initially all root ones - you remember it in the queue. Then you remove one by another from the queue and fill in (load and enqueue) its children. Until the queue gets empty.


I like using a hash table to create an index of all nodes indexed by keyID and use this to build the tree.It requires 2 passes of the table. The first pass creates a root tree node for each recordand adds a hash entry of keyID against tree node. the second pass walks the table looking up the parentId in the hash. If it finds it, then it moves the current node under the parent node otherwise ignores it. At the end of the second pass, you have the complete tree built.

    var i,imax,ikey,iParent : integer;        aNode,aParentNode : TTreeNode;        aData : TMyData;        aContainer : TSparseObjectArray; // cDataStructs , delphi fundamentals        aNodeIndex : TSparseObjectArray; // delphi 7    begin      try        aContainer := TSparseObjectArray.Create(true);        aNodeIndex := TSparseObjectArray.Create(False);        imax := 10000;        // create test data;        for i := 1 to imax do        begin          aData := TMyData.Create;          aData.iKey := i;          aData.iParent := Random(imax); // random parent          aData.Data := 'I:' + IntToStr(aData.iKey);          aContainer.Item[i] := aData;        end;        tv1.Items.Clear;        tv1.Items.BeginUpdate;        // build tree        // First Pass - build root tree nodes and create cross ref. index        for i := 1 to imax do        begin          aData := TMYData(aContainer.Item[i]);          aNode := tv1.Items.AddChild(nil,aData.Data);          aNodeIndex.Item[aData.iKey] := aNode;        end;        // Second Pass - find parent node using index and move node        for i := 1 to imax do        begin          aData := TMYData(aContainer.Item[i]);          aNode := TTreeNode(aNodeIndex.Item[aData.iKey]);          if aNodeIndex.HasItem(aData.iparent)          then begin                 aParentNode := TTreeNode(aNodeIndex.Item[aData.iparent]);                 aNode.MoveTo(aParentNode,naAddChild);               end;        end;        tv1.Items.EndUpdate;        tv1.Select( tv1.Items.GetFirstNode);      finally        aContainer.Free;        aNodeIndex.free;      end;  end;


procedure TdfmMed.Button1Click(Sender: TObject);var    NodePai : TTreeNode;         procedure MontaFilho(Node : TTreeNode; Cod : integer);         var            qry : TFDQuery;            node1 : TTreeNode;         begin            qry := TFDQuery.Create( nil );            qry.Connection := dm1.FDConnection1;            qry.close;            qry.SQL.Add('SELECT cod, nome_grupo FROM teste WHERE parent_cod = :cod ORDER BY nome_grupo ASC');            qry.ParamByName('cod').AsInteger := cod;            qry.Open();            qry.First;            while not qry.EOF do            begin                node1 := TreeView1.Items.AddChild(NODE, qry.Fields[1].Value);                MontaFilho(node1, qry.Fields[0].Value );                qry.Next;            end;         end;begin    TreeView1.Items.Clear;    qryGrupoPai.close;    qryGrupoPai.Open;    qryGrupoPai.First;    while not qryGrupoPai.EOF do    begin        NodePai := TreeView1.Items.Add(nil, qryGrupoPai.Fields[1].Value);        MontaFilho( NodePai, qryGrupoPai.Fields[0].Value);         qryGrupoPai.Next;    end;end;