Daten aus Tabelle mit ADO


scherzkecks

Mitglied
Hallo,
ich moechte aus einer Tabelle xyz

---------------------------------
| id | owner_id | text |
---------------------------------
| 1 | 0 | bla |
---------------------------------
| 2 | 1 | bla |
---------------------------------
| 3 | 2 | bla |
---------------------------------
| 4 | 1 | bla |
---------------------------------

so eine ausgabe des baumes:

1 ->
2 ->
3
4

wie bekomme ich das hin?
 

WieGehts

Erfahrenes Mitglied
Hallo,
kannst du bitte deine Ausgabe etwas genauer definieren. Mir ist nicht klar, was du in deiner Darstellung unter Baumn verstehst.
 

WieGehts

Erfahrenes Mitglied
Hallo,
weil zur Zeit kein Datenbankserver verfügbar, habe ich das mal mit einem ClientDataSet ausprobiert. Für die Verwendung von ADOTable und ADOQuery habe ich den Codeteil der einen Server zur Ausführung voraussetzt, nur als Kommentar eingebaut - sollte aber, wenn die Serverdaten entsprechend ergänzt werden, funktionieren.

Wenn du die Unit ausprobieren willst, leg ein neues Projekt an. Ziehe auf die Form ein ClientDataSet, eine ADOQuery, eine ADOTable, einen BitBtn und ein Memo. Dann sollte es klappen.
Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, DBClient, StdCtrls, Buttons, ADODB;

type
  TForm1 = class(TForm)
    ClientDataSet1: TClientDataSet;
    Memo1: TMemo;
    BitBtn1: TBitBtn;
    ADOTable1: TADOTable;
    ADOQuery1: TADOQuery;
    procedure FormCreate(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Datenfelder erstellen - hast du in deiner DB schon
  with ClientDataSet1.FieldDefs.AddFieldDef do
  begin
    DataType := ftInteger;
    Name := 'ID';
  end;
  with ClientDataSet1.FieldDefs.AddFieldDef do
  begin
    DataType := ftInteger;
    Name := 'OwnerID';
  end;
  with ClientDataSet1.FieldDefs.AddFieldDef do
  begin
    DataType := ftString;
    Size := 20;
    Name := 'Text';
  end;
  ClientDataSet1.CreateDataSet;
  // Tabelle mit daten füllen - hast du in deiner DB schon
  ClientDataSet1.AppendRecord([ 1,  0, 'Eintrag 0']);
  ClientDataSet1.AppendRecord([ 2,  1, 'Eintrag 1,1']);
  ClientDataSet1.AppendRecord([ 3,  1, 'Eintrag 1,2']);
  ClientDataSet1.AppendRecord([ 4,  2, 'Eintrag 2,1']);
  ClientDataSet1.AppendRecord([ 5,  2, 'Eintrag 2,2']);
  ClientDataSet1.AppendRecord([ 6,  4, 'Eintrag 4,1']);
  ClientDataSet1.AppendRecord([ 7,  4, 'Eintrag 4,2']);
  // Erweiterung zu deinen Beispieldaten
  ClientDataSet1.AppendRecord([ 8,  4, 'Eintrag 4,3']);
  ClientDataSet1.AppendRecord([ 9,  4, 'Eintrag 4,4']);
  ClientDataSet1.AppendRecord([10,  4, 'Eintrag 4,5']);
  ClientDataSet1.AppendRecord([11,  2, 'Eintrag 2,3']);
  ClientDataSet1.AppendRecord([12,  1, 'Eintrag 1,3']);
  ClientDataSet1.AppendRecord([13, 11, 'Eintrag 11,1']);
end;

procedure TForm1.BitBtn1Click(Sender: TObject);

  procedure ClientDataSet1Ausgabe(Owner, Ebene: Integer);
  var RecNr: Integer;
  begin
    // Daten filtern
    ClientDataSet1.SetRange([Owner], [Owner]);
    // Alle Datensätze in diesem Bereich bearbeiten
    while not ClientDataSet1.Eof do
    begin
      // die Datensatznummer merken
      RecNr := ClientDataSet1.RecNo;
      // Daten ausgeben
      Memo1.Lines.Add(StringOfChar(' ', Ebene * 4) + '->' +
                  ClientDataSet1.FieldByName('ID').AsString + '  ' +
                  ClientDataSet1.FieldByName('OwnerID').AsString + '  ' +
                  ClientDataSet1.FieldByName('Text').AsString);
      // Ausgabe eines untergeordneten Zeiges aufrufen
      ClientDataSet1Ausgabe(ClientDataSet1.FieldByName('ID').AsInteger, Ebene + 1);
      // nach rückkehr von ausgabe eines untergeordneten zweiges den vorherigen zustand wieder herstellen
      ClientDataSet1.SetRange([Owner], [Owner]);
      ClientDataSet1.RecNo := RecNr;
      // zum nächsten Datensatz gehen
      ClientDataSet1.Next;
    end;
  end;

  procedure ADOTable1Ausgabe(Owner, Ebene: Integer);
  var RecNr: Integer;
  begin
    ADOTable1.Filter := 'OwnerID=' + IntToStr(Owner);
    while not ADOTable1.Eof do
    begin
      RecNr := ADOTable1.RecNo;
      Memo1.Lines.Add(StringOfChar(' ', Ebene * 4) + '->' +
                  ADOTable1.FieldByName('ID').AsString + '  ' +
                  ADOTable1.FieldByName('OwnerID').AsString + '  ' +
                  ADOTable1.FieldByName('Text').AsString);
      ADOTable1Ausgabe(ADOTable1.FieldByName('ID').AsInteger, Ebene + 1);
      ADOTable1.Filter := 'OwnerID=' + IntToStr(Owner);
      ADOTable1.RecNo := RecNr;
      ADOTable1.Next;
    end;
  end;

  procedure ADOQuery1Ausgabe(Owner, Ebene: Integer);
  var RecNr: Integer;
  begin
    ADOQuery1.Filter := 'OwnerID=' + IntToStr(Owner);
    while not ADOQuery1.Eof do
    begin
      RecNr := ADOQuery1.RecNo;
      Memo1.Lines.Add(StringOfChar(' ', Ebene * 4) + '->' +
                  ADOQuery1.FieldByName('ID').AsString + '  ' +
                  ADOQuery1.FieldByName('OwnerID').AsString + '  ' +
                  ADOQuery1.FieldByName('Text').AsString);
      ADOQuery1Ausgabe(ADOQuery1.FieldByName('ID').AsInteger, Ebene + 1);
      ADOQuery1.Filter := 'OwnerID=' + IntToStr(Owner);
      ADOQuery1.RecNo := RecNr;
      ADOQuery1.Next;
    end;
  end;

begin
  ClientDataSet1.IndexFieldNames := 'OwnerID;ID';                 // Index einstellen
  ClientDataSet1Ausgabe(0, 0);                                    // Ausgabe starten
{
  ADOTable1.TableName := deine Tabelle;
  ADOTable1.IndexFieldNames := 'OwnerID;ID';
  ADOTable1.Open;
  ADOTable1.Filtered := True;
  ADOTable1Ausgabe(0, 0);

  ADOQuery1.SQL.Text := 'SELECT * FROM deine_Tabelle ORDER BY OwnerID, ID';
  ADOQuery1.Open;
  ADOQuery1.Filtered := True;
  ADOQuery1Ausgabe(0, 0);                                                     {}
end;

end.
 

scherzkecks

Mitglied
klappt wunderbar.
Vielen Dank.
Aber es muss in einem TreeView ausgegen werden, damit ich die knoten zu laufzeit verschieben kann und sich das in der DB aendert.

Vielen Dank fuer die Muehe, echt klasse von Dir

:)
 

WieGehts

Erfahrenes Mitglied
Hallo,
ich habs befürchtet, dass du sowas machen willst. Aber aus deinem Beispiel war das nicht erkennbar.
Schau dir die Tree-Komponente von Delphi an (Online Hilfe). Du kannst dann den Code verwenden, aber anstatt der Ausgabe ins Memo musst du einen Knoten erstellen (Create). Anstatt der Ebene übergibst du den Knoten, zu dem du den erzeugten Knoten als Unterknoten dranhängst.
Möchte dich aber gleich warnen - wenn du eine größere Menge von Knoten benötigst, wird das (sehr) langsam. Dann solltest du dir eine andere Komponente suchen. Angeblich gibt es welche, die schneller sind als das Delphi-Original.