Announcement

Collapse
No announcement yet.

mehrere Resultsets

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • mehrere Resultsets

    Hallo,<br>
    wenn ich im QueryAnalyser folgenden SQL eingebe und ausführe<br>
    <b><font face="Courier New" size="2">&nbsp;&nbsp;&nbsp; USE msdb<br>
    &nbsp;&nbsp;&nbsp; EXEC sp_help_job @job_name = 'Meine Sicherung'&nbsp;<br>
    </font></b>erhalte <b>4</b> Resultsets ... das ist auch soweit gut.<br>
    <br>
    In meiner Anwendung verwende ich TADOStoredProc um die StoredProcedure
    auszuführen.<br>
    Hier bekomme aber nur ein bzw. nur das erste Resultset gegenüber dem vom
    QueryAnalyser.<br>
    <br>
    Was muss ich tun, damit ich auf alle 4 Ergebnisse zugreifen und darstellen kann?<br>
    <br>
    Gruss und Dank<br>
    &nbsp;&nbsp;&nbsp; Dietmar<br>

  • #2
    Hallo Dietmar,

    ich weiß zwar nicht, ob das mit TADOStoredProc überhaupt geht, als workaraound könnte man aber das sp_help_job 4 mal mit geändertem job_aspect aufrufen, also zB. so:

    USE msdb
    EXEC sp_help_job @job_name = 'Meine Sicherung', @job_aspect = 'JOB'<br>
    EXEC sp_help_job @job_name = 'Meine Sicherung', @job_aspect = 'SCHEDULES'<br>
    EXEC sp_help_job @job_name = 'Meine Sicherung', @job_aspect = 'STEPS'<br>
    EXEC sp_help_job @job_name = 'Meine Sicherung', @job_aspect = 'TARGETS'<br>

    ... bzw. wird man ja nur einen davon wirklich brauchen, oder?

    bye,<br>
    Helmu

    Comment


    • #3
      Mit der Function NextRecordset kannst du zu den anderen Recordsets wechseln. Also z.B.

      <PRE>
      TADOStoredProc.Recordset := TADOStoredProc.NextRecordset;
      </PRE>

      Ral

      Comment


      • #4
        Hallo,

        &gt;Was muss ich tun, damit ich auf alle 4 Ergebnisse zugreifen und darstellen kann?

        Um die Antwort vorweg zu nehmen, ist der Zugriff dank der Fähigkeiten der ADO-Objekte sehr einfach. Aber auch hier soll ein Beispiel das Prinzip verdeutlichen. Zuerst lege ich in der <i>Northwind</i>-Beispieldatenbank des MS SQL Server 2000 eine eigene gespeicherte Prozedur an, die gleich zwei SELECT-Abfragen hintereinander ausführt. Danach teste ich diese Prozedur sofort im Query Analyzer, indem ich sie über EXEC ausführe. Im Ergebnisfenster sind beide Ergebnismengen gleichzeitig als Tabelle zu sehen.
        <pre>
        <b>USE</b> Northwind
        <b>GO</b>
        <b>CREATE</b> <b>PROCEDURE</b> spMultiResultSet
        <b>AS</b>
        <b>SET</b> NOCOUNT <b>ON</b>
        <b>SELECT</b> * <b>FROM</b> dbo.Region
        <b>SELECT</b> * <b>FROM</b> dbo.Categories
        <b>GO</b>
        <b>EXEC</b> spMultiResultSet
        </pre>
        Um das gleiche Verhalten (das gleichzeitige Darstellen beider Ergebnismengen in zwei TDBGrid) auch in der Delphi-Anwendung zu erhalten, gehe ich folgendermaßen vor: <br>
        a) Ich lege zwei TDBGrid-Komponenten auf dem Formular ab, die jeweils eine eigene TDataSource-Komponente erhalten.<br>
        b) Ich konfiguriere eine TADOConnection-Komponente für die vorbereitete Northwind-Beispieldatenbank.<br>
        c) Ich lege die erste TADODataSet-Komponente auf dem Formular ab, um diese gleich über die Eigenschaft <b>Connection</b> mit der TADOConnection-Komponente zu verbinden. Danach setze ich die Eigenschaft <b>CommandType</b> auf den Wert <b>cmdStoredProc</b> und bei der Eigenschaft <b>CommandText</b> wähle ich die eigene Prozedur <i>spMultiResultSet</i> aus, um das Ganze dann über TDataSource an das 1. TDBGrid zu hängen.<br>
        d) Ich lege dann die zweite TADODataSet-Komponente auf dem Formular ab, wobei dort keine Eigenschaften im Objektinspektor konfiguriert werden. Statt dessen verbinde ich diese Komponente sofort über TDataSource mit dem 2. TDBGrid.<br>
        e) In der Uses-Auflistung des Formulars füge ich die Unit <b>ADOInt</b> hinzu.
        <br><br>
        Wenn das Programm gestartet wird, öffne ich zuerst die TADODataSet-Instanz, die über die Eigenschaft CommandText mit meiner gespeicherten Prozedur <i>spMultiResultSet</i> verbunden ist, so dass im ersten TDBGrid sofort die Daten der ersten Ergebnismenge sichtbar sind.
        <pre>
        ADOConnection1.Connected := True;
        ADODataSet1.Active := True;
        </Pre>
        Um gleichzeitig auch an die zweite Ergebnismenge meiner gespeicherten Prozedur zu gelangen, muss ich auf die Interface-Methode <b>NextRecordset</b> des Recordset-Objekts von ADO zurückgreifen. Da die VCL-Komponente TADODataSet über die Eigenschaft <b>Recordset</b> einen Interface-Zeiger auf die im Hintergrund eingebundene Recordset-Objektinstanz bereitstellt, ist der Job schnell erledigt. Als Ergebnis liefert mir die Interface-Methode NextRecordset einen Verweis auf die zweite Ergebnismenge zurück, so dass ich dieses Ergebnis der nicht konfigurierten zweiten TADODataSet-Komponente unterschieden kann. Sobald deren Eigenschaft auf True gesetzt wird, zeigt es die Daten im zweiten TDBGrid sofort an – auch wenn diese TADODataSet-Komponente gar keine eigene Verbindung zur Datenbank nutzt.
        <pre>
        <b>var</b>
        aRS : _RecordSet;
        vRec: OleVariant;
        <b>begin</b>
        aRS := ADODataSet1.Recordset.NextRecordset(vRec);
        ADODataSet2.Recordset := aRS;
        ADODataSet2.Active := True;
        <b>end</b>;
        </pre>
        Die angehängte Abbildung zeigt das Ergebnis

        Comment


        • #5
          Hallo,

          &gt;Was muss ich tun, damit ich auf alle 4 Ergebnisse zugreifen und darstellen kann?

          ich würde ich die Kompatibilitäts-Komponente TADOStoredProc entsorgen, denn dieses Teil arbeitet nicht gerade optimal. Besser geeignet ist <b>TADODataSet</b>. Ein Beispiel verdeutlicht das Prinzip besser. Zuerst lege ich in der <i>Northwind</i>-Beispieldatenbank des MS SQL Server 2000 eine eigene gespeicherte Prozedur an, die gleich zwei SELECT-Abfragen hintereinander ausführt. Danach teste ich diese Prozedur sofort im Query Analyzer, indem ich sie über EXEC ausführe. Im Ergebnisfenster sind beide Ergebnismengen gleichzeitig als Tabelle zu sehen.
          <pre>
          <b>USE</b> Northwind
          <b>GO</b>
          <b>CREATE</b> <b>PROCEDURE</b> spMultiResultSet
          <b>AS</b>
          <b>SET</b> NOCOUNT <b>ON</b>
          <b>SELECT</b> * <b>FROM</b> dbo.Region
          <b>SELECT</b> * <b>FROM</b> dbo.Categories
          <b>GO</b>
          <b>EXEC</b> spMultiResultSet
          </pre>
          Um das gleiche Verhalten (das gleichzeitige Darstellen beider Ergebnismengen in zwei TDBGrid) auch in der Delphi-Anwendung zu erhalten, gehe ich folgendermaßen vor: <br>
          a) Ich lege zwei TDBGrid-Komponenten auf dem Formular ab, die jeweils eine eigene TDataSource-Komponente erhalten.<br>
          b) Ich konfiguriere eine TADOConnection-Komponente für die vorbereitete Northwind-Beispieldatenbank.<br>
          c) Ich lege die erste TADODataSet-Komponente auf dem Formular ab, um diese gleich über die Eigenschaft <b>Connection</b> mit der TADOConnection-Komponente zu verbinden. Danach setze ich die Eigenschaft <b>CommandType</b> auf den Wert <b>cmdStoredProc</b> und bei der Eigenschaft <b>CommandText</b> wähle ich die eigene Prozedur <i>spMultiResultSet</i> aus, um das Ganze dann über TDataSource an das 1. TDBGrid zu hängen.<br>
          d) Ich lege dann die zweite TADODataSet-Komponente auf dem Formular ab, wobei dort keine Eigenschaften im Objektinspektor konfiguriert werden. Statt dessen verbinde ich diese Komponente sofort über TDataSource mit dem 2. TDBGrid.<br>
          e) In der Uses-Auflistung des Formulars füge ich die Unit <b>ADOInt</b> hinzu.
          <br><br>
          Wenn das Programm gestartet wird, öffne ich zuerst die TADODataSet-Instanz, die über die Eigenschaft CommandText mit meiner gespeicherten Prozedur <i>spMultiResultSet</i> verbunden ist, so dass im ersten TDBGrid sofort die Daten der ersten Ergebnismenge sichtbar sind.
          <pre>
          ADOConnection1.Connected := True;
          ADODataSet1.Active := True;
          </Pre>
          Um gleichzeitig auch an die zweite Ergebnismenge meiner gespeicherten Prozedur zu gelangen, muss ich auf die Interface-Methode <b>NextRecordset</b> des Recordset-Objekts von ADO zurückgreifen. Da die VCL-Komponente TADODataSet über die Eigenschaft <b>Recordset</b> einen Interface-Zeiger auf die im Hintergrund eingebundene Recordset-Objektinstanz bereitstellt, ist der Job schnell erledigt. Als Ergebnis liefert mir die Interface-Methode NextRecordset einen Verweis auf die zweite Ergebnismenge zurück, so dass ich dieses Ergebnis der nicht konfigurierten zweiten TADODataSet-Komponente unterschieden kann. Sobald deren Eigenschaft auf True gesetzt wird, zeigt es die Daten im zweiten TDBGrid sofort an – auch wenn diese TADODataSet-Komponente gar keine eigene Verbindung zur Datenbank nutzt.
          <pre>
          <b>var</b>
          aRS : _RecordSet;
          vRec: OleVariant;
          <b>begin</b>
          aRS := ADODataSet1.Recordset.NextRecordset(vRec);
          ADODataSet2.Recordset := aRS;
          ADODataSet2.Active := True;
          <b>end</b>;
          </pre>
          Die angehängte Abbildung zeigt das Ergebnis

          Comment


          • #6
            Hallo,<br>
            und erst mal vielen Dank für die verschiedene Anregungen.<br>
            @Andreas<br>
            Das Beispiel inkl. Anleitung ist tadellos, auch wenn man die StoredProc auf
            weitere Ergebnismengen erweitert wird.</p>
            <blockquote>
            <p><font face="Courier New" size="1"><b>CREATE PROCEDURE spMultiResultSet<br>
            AS<br>
            SET NOCOUNT ON<br>
            SELECT * FROM Region<br>
            SELECT * FROM Categories<br>
            SELECT * FROM Shippers<br>
            SELECT * FROM Suppliers<br>
            RETURN<br>
            GO</b></font></p>
            </blockquote>
            <p>Jedoch bekomme ich einen Fehler (Stacküberlauf) für den 4ten Resultset,
            sobald ich die msdb..sp_help_job aufrufe.<br>
            Komischerweise funktioniert es mit dem Aufruf Northwind..spMultiResultSet.<br>
            Sicherlich könnte ich das jedoch mit den native ADO's überprüfen, aber in
            Hinblick auf @Helmut's Lösung würde ich bei der sp_help_job diese Variante
            bevorzugen.<br>
            <br>
            &gt;ich würde ich die Kompatibilitäts-Komponente TADOStoredProc entsorgen, denn dieses Teil arbeitet nicht gerade optimal.&nbsp;<br>
            &gt;Besser geeignet ist TADODataSet. <br>
            Heißt das nun generell, wenn ich eine StoredProc aufrufen möchte, dass ich die
            TADODataSet verwenden soll?<br>
            <br>
            <br>
            Gruss und Dank<br>
            &nbsp;&nbsp;&nbsp; Dietma

            Comment


            • #7
              Hallo,

              für den generellen Einsatz von TADODataSet sprechen 2 Gründe: <br>
              1. Die Komponente bildet die nativen ADO-Objekte (Command/Recordset) am Besten in der VCL ab. <br>
              2. Nur bei TADOCommand/TADODataSet hat Borland in den letzten Jahren einige Bugs gefixt (aber nicht bei den BDE-Kompatibilitätskomponenten TADOTable/TADOStoredProc).

              &gt;..Jedoch bekomme ich einen Fehler (Stacküberlauf) ..

              Generell ist es eine gute Idee, bei jedem Problem mit dem ADO Express/dbGo-Komponenten zum Test auf die nativen ADO-Objekte auszuweichen

              Comment


              • #8
                Hallo,<br>
                <br>
                &gt;Generell ist es eine gute Idee, bei jedem Problem mit dem ADO Express/dbGo-Komponenten zum Test auf&nbsp;<br>
                &gt;die nativen ADO-Objekte auszuweichen.&nbsp;<br>
                Das habe ich nun mal ausprobiert ...</p>
                <blockquote>
                <p><b><font face="Courier New" size="2">010 cmd := CoCommand.Create;<br>
                020 cmd.Set_ActiveConnection (co);<br>
                030 cmd.CommandType := adCmdStoredProc;<br>
                040 cmd.CommandText := 'sp_help_job';<br>
                050&nbsp;<br>
                060 AddParamObj ('@job_id', adGUID, adParamInput, 0);<br>
                070 AddParamObj ('@job_name', adVarChar, adParamInput, 128);<br>
                080&nbsp;<br>
                090 cmd.Parameters['@job_name'].Value := 'Irgendein Job';<br>
                100&nbsp;<br>
                110 rs := cmd.Execute (vRows, EmptyParam, adOptionUnspecified);<br>
                120<br>
                130 adsTmp.Recordset := rs;</font></b></p>
                </blockquote>
                <p>Jedoch bekomme ich hier in Zeile 130 einen Fehler &quot;<b>Stacküberlauf</b>&quot;.
                <br>
                Habe auch Zeile 060 mal auskommentiert, aber irgendwie wird die gebraucht ...<br>
                <br>
                Gruss<br>
                &nbsp;&nbsp; Dietma

                Comment


                • #9
                  Hallo,

                  &gt;Jedoch bekomme ich hier in Zeile 130 einen Fehler "Stacküberlauf".

                  aber in der Zeile 130 ist doch bereits die dbGo-Komponete (TADODataSet) im Spiel. Was passiert, wenn die Ergebnismenge über die Recordset-Methode <b>GetString</b> angezeigt wird?
                  <pre>
                  <b>var</b>
                  aRS1 : _Recordset;
                  aRS2 : _Recordset;
                  vRec : OleVariant;
                  iRecCount : Integer;
                  swData : WideString;
                  <b>begin</b>
                  ...
                  ...
                  ...
                  iRecCount := aRS1.RecordCount;
                  swData := aRS1.GetString(adClipString, iRecCount, <font color="#9933CC">'; '</font>, #13#10,<font color="#9933CC">'(NULL)'</font>);
                  ShowMessage(swData);
                  ...
                  aRS2 := aRS1.NextRecordset(vRec);
                  iRecCount := aRS2.RecordCount;
                  swData := aRS2.GetString(adClipString, iRecCount, <font color="#9933CC">'; '</font>, #13#10,<font color="#9933CC">'(NULL)'</font>);
                  ShowMessage(swData);
                  ...
                  <b>end</b>;
                  </pre&gt

                  Comment

                  Working...
                  X