Entwickler-Ecke

Datenbanken - Ergebnis einer Abfrage nach Schließen der Connection halten


Nico B. - Do 24.06.10 14:21
Titel: Ergebnis einer Abfrage nach Schließen der Connection halten
Hallo Leute,

ich hab mal ne Frage.
Ich frage eine DB über ADOQuery's ab.
Was passiert, wenn ich die ADOConnection nach einer Abfrage schließe?

Bsp.:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
ADOConnection.Connected:=true;
ADOQuery.SQL.Clear;
ADOQuery.SQL.Append('SELECT * FROM Datenbank');
ADOQuery.ExecSQL;
ADOQuery.Open;

//nun kann ich mir meine Abfrage-Ergebnisse anschauen

ADOConnection.Connected:=false;

//Kann ich mir jetzt immer noch meine Abfrage-Ergebnisse anschauen?


Ändern kann ich nichts. Das ist klar.
Aber kann ich noch in der Ergebnisliste von Zeile zu Zeile springen und die Ergebnisse verarbeiten?


Gerd Kayser - Do 24.06.10 16:10

user profile iconNico B. hat folgendes geschrieben Zum zitierten Posting springen:
Was passiert, wenn ich die ADOConnection nach einer Abfrage schließe?

Dann verlierst Du den Cursor auf die Ergebnismenge. Die bis dahin ausgewerteten Datensätze sind verarbeitet, der Rest nicht.


Delphi-Quelltext
1:
2:
3:
ADOConnection.Connected:=true;
ADOQuery.SQL.Clear;
ADOQuery.SQL.Append('SELECT * FROM Datenbank');

Es muß heißen "SELECT * FROM Datenbanktabelle".

Delphi-Quelltext
1:
2:
ADOQuery.ExecSQL;
ADOQuery.Open;

Das sind verschiedene Paar Schuhe. ExecSQL wird bei Inserts, Deletes und Updates verwendet. Open nur bei Abfragen (also reinen Selects).

Delphi-Quelltext
1:
//nun kann ich mir meine Abfrage-Ergebnisse anschauen                    

Wie und wo? Ich sehe da nichts.

Delphi-Quelltext
1:
2:
ADOConnection.Connected:=false;
//Kann ich mir jetzt immer noch meine Abfrage-Ergebnisse anschauen?

Nein, weil mit dem Schließen der Connection die Query-Komponente den Cursor auf die Ergebnismenge verliert.

Hier hast Du mal ein Abfragebeispiel:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
  DatenModul.IBQuery1.SQL.Clear;
  DatenModul.IBQuery1.SQL.Add('select distinct Monat from TabKalender  ');
  DatenModul.IBQuery1.SQL.Add('where                                   ');
  DatenModul.IBQuery1.SQL.Add('  (TSYSDP2A = TSYSDP2B);                ');
  DatenModul.IBQuery1.Open;
    while not DatenModul.IBQuery1.Eof do
      begin
        Monat := DatenModul.IBQuery1.FieldByName('Monat').AsInteger;

        if Monat > 0 then
          for Schleife := 0 to DMonatsauswahl.ComponentCount - 1 do
            if (Components[Schleife] is TLMDSpeedButton) and
              (TLMDSpeedButton(Components[Schleife]).Tag = Monat) then
              begin
                TLMDSpeedButton(Components[Schleife]).Enabled := true;
                TLMDSpeedButton(Components[Schleife]).Color := clMoneyGreen;
              end;

        DatenModul.IBQuery1.Next;
      end;
  DatenModul.IBQuery1.Close;


Nico B. - Fr 25.06.10 07:30

Hallo Gerd,

na klar "SELECT * FROM Datenbanktabelle".

Danke für die Info zum ExecSQL und Open... Das hab ich dann bisher immer falsch gemacht.

Nun noch mal zu deinem Beispiel:
Deine While-Schleife würde also nicht funktionieren, wenn ich davor die Connection der Query löse?


Gerd Kayser - Fr 25.06.10 07:41

user profile iconNico B. hat folgendes geschrieben Zum zitierten Posting springen:

Deine While-Schleife würde also nicht funktionieren, wenn ich davor die Connection der Query löse?


Ein kleines Beispiel, wie man das testen kann:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
procedure TForm1.Button1Click(Sender: TObject);
var
  Zaehler : integer;
  Anzahl  : integer;
begin
  Zaehler := 0;
  IBDatabase1.Connected:= true;
  with IBQuery1 do
    begin
      SQL.Clear;
      SQL.Add('select * from TabPlatten');
      // Es sind 593 Datensätze.
      Open;
        Last;
        First;
        Anzahl := RecordCount;
        Label1.Caption := 'Datensätze vorhanden: ' + IntToStr(Anzahl);
        while not Eof do
          begin
            Inc(Zaehler);
            Label2.Caption := 'Datensätze verarbeitet: ' + IntToStr(Zaehler);
            if Zaehler = 100 then
              IBDatabase1.Connected:= false;
            Next;
          end;
      Close;
    end;
end;

Mit Last und First wird bei einem bidirektionalem Cursor die Ergebnismenge komplett geholt. Query hat also hier 593 Datensätze am Wickel. In der Schleife wird beim 100. Datensatz die Verbindung gekappt. Als Folge davon wird die Exception "Operation bei geschlossener Datenmenge nicht ausführbar" geworfen und die Schleife abgebrochen. Die Zählervariable hat dann den Wert 100. Das heißt, 100 Datensätze wurden verarbeitet, aber 493 Datensätze sind verworfen worden, weil IBQuery den Cursor auf die Ergebnismenge verliert.


Nico B. - Fr 25.06.10 08:50

Mhm, Mist.

Gibt es denn eine Möglichkeit die Datensätze zügig irgendwohin zu übertragen, wo ich auf sie zugreifen kann ohne das die Connection bestehen bleiben muss?

Denn mein Problem ist folgendes:
Ich mache eine Abfrage in einer Datenbank X und will dann die Ergebnisse schrittweise mit den Einträgen in einer Datenbank Y vergleichen. Ich möchte jedoch nicht während der gesamten Zeit die Verbindung zur Datenbank X offen halten.

Richtig cool wäre also eine Art Offline-ADOQuery, die die Ergebnisse der Online-ADOQuery einfach übertragen bekommt.


bummi - Fr 25.06.10 08:55

Wenn Du bei Deinem Adodataset den Locktype auf ltBatchOptimistic setzt, kannst Du mit den Daten auch arbeiten nachdem Du die Connection auf nil gesetzt hast.
Lesend, mit IB habe ich keine Erfahrungen funtioniert zuverlässig mit Access und MS SQL-Server