QuickReport Master-Detail Darstellung



  • Ich möchte den Inhalt zweier relational verknüpfter Tabellen in einem Quickreport darstellen.
    Die Mastertabelle enthält Kopfdaten, die Detailtabelle einzelne Prüfungsergebnisse.
    Verknüpft sind beide Tabellen 1:n über ein Feld mit Datumsinformationen.

    Den Quickreport habe ich folgendermaßen erstellt:

    PageHeaderBand
    --------------
    Detailband
    --------------
    Subdetailband

    Im Pageheaderband sind nur Labels untergebracht, es ist somit obsolet.
    Im Detailband habe ich den Inhalt der Kopfdatentabelle dargestellt, den ich mir über einen ADOQuery hole. Das funktioniert.
    Im Subdetailband möchte ich die Prüfungsergebnisse, die zu den Kopfdaten gehören, anzeigen. Dafür habe ich ein zweites ADOQuery erstellt, welches die Daten aus der Detailtabelle anhand der schon für die Kopfdaten gültigen Suchkriterien abruft.
    Momentan ist es so, dass zwar das Detailband korrekt gefüllt wird und der Seitenumbruch bei einem neuen Datensatz auch wie erwartet erfolgt, aber im Subdetailband stehen immer alle Prüfungsergebnisse, auch die, die nicht zu den Kopfdaten passen:

    Beispiel:

    Kopfdaten
    Prüfungsdatum: 18.02.1998 19:08:08
    Prüfzeit: 02:11
    Prüfungsergebnis: i.O.

    Detailinformationen

    Prüfungsdatum Stufe Druck Ergebnis
    18.02.1998 19:08:08 1 500bar i.O.
    18.02.1998 19:08:08 2 800bar i.O.
    18.02.1998 19:08:08 3 1200bar i.O.
    29.04.1998 16:00:02 1 750bar i.O.
    29.04.1998 16:00:02 2 1400bar i.O.
    29.04.1998 16:00:02 3 2300bar n.i.O.

    ---
    Seitenumbruch
    ---

    Kopfdaten
    Prüfungsdatum: 29.04.1998 16:00:02
    Prüfzeit: 01:03min
    Prüfungsergebnis: n.i.O.

    Detailinformationen

    Prüfungsdatum Stufe Druck Ergebnis
    18.02.1998 19:08:08 1 500bar i.O.
    18.02.1998 19:08:08 2 800bar i.O.
    18.02.1998 19:08:08 3 1200bar i.O.
    29.04.1998 16:00:02 1 750bar i.O.
    29.04.1998 16:00:02 2 1400bar i.O.
    29.04.1998 16:00:02 3 2300bar n.i.O.

    Richtig sollte die Darstellung so sein:

    Kopfdaten
    Prüfungsdatum: 18.02.1998 19:08:08
    Prüfzeit: 02:11
    Prüfungsergebnis: i.O.

    Detailinformationen

    Prüfungsdatum Stufe Druck Ergebnis
    18.02.1998 19:08:08 1 500bar i.O.
    18.02.1998 19:08:08 2 800bar i.O.
    18.02.1998 19:08:08 3 1200bar i.O.

    ---
    Seitenumbruch
    ---

    Kopfdaten
    Prüfungsdatum: 29.04.1998 16:00:02
    Prüfzeit: 01:03min
    Prüfungsergebnis: n.i.O.

    Detailinformationen

    Prüfungsdatum Stufe Druck Ergebnis
    29.04.1998 16:00:02 1 750bar i.O.
    29.04.1998 16:00:02 2 1400bar i.O.
    29.04.1998 16:00:02 3 2300bar n.i.O.

    Jetzt habe ich des öfteren gelesen, dass das richtige Stichwort die Eigenschaft Masterfields ist. Allerdings gibt es die nur in der Komponente ADOTable, die ich nicht verwenden möchte, da ich mit ADOQuery arbeite.
    Das Subdetailband hat verschiedene Eigenschaften (z.B. "Master", "HeaderBand", "LinkBand"), die ich eigentlich passend für eine Master-Detail-Darstellung finde, aber egal was ich da eintrage, es werden entweder die falschen Daten angezeigt, oder gar keine.

    Ich hoffe, die Beschreibung ist einigermaßen verständlich.

    Vielen Dank schon mal.



  • Hi CHLINDE,

    vergiss ADOQuerry, das ist auch nur (wie ADOTable) ein schlecht nachgebautes um mit den alten BDE-Typen vergleichbar zu sein. Dein Favorit sollte ADODataset sein. Das kannst Du je nach Bedarf als Table oder Query betreiben.

    Im übrigen brauchts die Möglichkeit Mastefields nicht. Du kannst im AfteScroll-Ereignis der Mastertabelle entweder jeweils den Select-String (Commandtext) der Clienttabelle ("select * from Tabelle where a = :a") mit einem entsprechenden Wert versehen in dem Du den Parameter setzt und Requery aufrufst oder Du setzt den Filter der Clienttabelle jeweils entsprechen neu.

    Alternativ kannst Du auch den Filter der Clienttabelle entsprechend voreinstellen bzw. in OnFilterRecord aussieben was Du nicht brauchst. Da musst Du jeweils nur in der AfterScroll-Routine der Mastertabelle ein Requery der Clienttabelle veranlassen.

    Gruß Mümmel



  • Hallo Muemmel!

    Vielen Dank für den sehr guten Tipp mit dem AfterScroll-Ereignis. Darüber konnte ich nicht nur das beschriebene Problem lösen, sondern auch eine zweite Sache.

    Hier noch kurz eine Beschreibung, was ich im AfterScroll-Ereignis der Kopfdatentabelle grob mache:

    void __fastcall TDataTable_Master::ADOQueryAfterScroll(TDataSet *DataSet)
    {
        DataTable_Detail->ADOQuery->Active=false;
        DataTable_Detail->ADOQuery->SQL->Clear();
    
        String StrSelectString = "SELECT * FROM Detailtabelle WHERE Name = 'Test'";
    
        DataTable_Detail->ADOQuery->SQL->Append(StrSelectString);
        DataTable_Detail->ADOQuery->Active = true;
    }
    

    Dadurch wird das ADOQuery der Detailtabelle nur mit den Daten gefüllt, die den Kriterien im SELECT entsprechen.

    Der Report sieht dann folgendermaßen aus:

    Kopfdaten
    Prüfungsdatum: 18.02.1998 19:08:08
    Prüfzeit: 02:11
    Prüfungsergebnis: i.O.

    Detailinformationen

    Prüfungsdatum Stufe Druck Ergebnis
    18.02.1998 19:08:08 1 500bar i.O.
    18.02.1998 19:08:08 2 800bar i.O.
    18.02.1998 19:08:08 3 1200bar i.O.

    ---
    Seitenumbruch
    ---

    Kopfdaten
    Prüfungsdatum: 29.04.1998 16:00:02
    Prüfzeit: 01:03min
    Prüfungsergebnis: n.i.O.

    Detailinformationen

    Prüfungsdatum Stufe Druck Ergebnis
    29.04.1998 16:00:02 1 750bar i.O.
    29.04.1998 16:00:02 2 1400bar i.O.
    29.04.1998 16:00:02 3 2300bar n.i.O.

    Eine weitere Zielsetzung war, dass ich in einem OLE-Objekt-Datenbankfeld ein Bild im JPG-Format gespeichert habe. Die QRDBImage-Komponente lässt sich aber leider nur mit Feldern verknüpfen, die Bitmaps enthalten.
    Diesen Umstand konnte ich umgehen, indem ich ebenfalls im AfterScroll der Mastertabelle das Bild aus dem Datenbankfeld in einen Stream lade, diesen dann in eine TJPEGImage-Variable übertrage und diese dann einer normalen QRImage-Komponente zuweise.

    void __fastcall TDataTable_Master::ADOQueryAfterScroll(TDataSet *DataSet)
    {
        TMemoryStream * Stream = new TMemoryStream();
        TGraphic * myGraphic   = new TJPEGImage();
    
        try
        {
            Stream = dynamic_cast<TMemoryStream*>(ADOQuery->CreateBlobStream(ADOQuery->FieldByName("Bild"), bmRead));
    		myGraphic->LoadFromStream(Stream);
    
            Form1->QRImage1->Picture->Bitmap->Assign(myGraphic);
        }
        __finally
        {
        	delete Stream;
    	    delete myGraphic;
        }
    }
    

    Dadurch kann ich auf jedem Report das JPG-Bild aus dem jeweiligen Datensatz abbilden. Logischerweise befinden sich beide Codeschnipsel letztendlich in einer Methode, ich habe sie hier nur zum besseren Verständnis separat aufgeführt.



  • Hi CHLINDE,

    wen Du jetzt noch mit Parametern arbeitest, und nur jeweils dem Parameter einen neuen Wert zuweist und mit Requery aktualisierst geht es noch einfacher.
    Versuch einfach mal das Buch "ADO und Delphi" von Andreas Kosch irgendwo zu kriegen, da ist alles bestens drin beschrieben.

    Gruß Mümmel


Anmelden zum Antworten