[C++Builder] Hilfe zu ADO-Abfragen



  • Hallo zusammen

    ich habe wieder ein Problem mit der ADO-Komponente ADOQuery!

    Ich habe folgenden SQL-Befehl:

    "SELECT m.Vorname FROM Mitarbeiter WHERE m.personalnummer = 1234";

    Wenn ich jetzt diesen Befehl in den BCB-Datenbank Explorer eingebe, bekomme ich genau die Ergebnismenge zurück die ich auch möchte.

    Das ganze möchte ich jetzt auch in meinem Programmcode umsetzen.

    Dazu benutze ich eine ADOQuery-Komponente.

    Ich habe eine Klasse mit der Methode

    "sql_statement_asufuehren" die forlgendermaßen definiert ist

    void Datenbankbearbeiter::sql_statement_ausfuehren(AnsiString sql_befehl, int ausfuehrungsart)
    {
    
       int sql_ausfuehrung = 0;
    
       Transaktion_starten();
    
       if (adoconnection->InTransaction)
       {
    
          adoquery->ConnectionString = "Provider="DB_PROVIDER";Password="DB_PASSWORD";"
                                       "User ID="DB_USER_ID";Data Source="DB_DATA_SOURCE";"
                                       "Persist Security Info=True;";
    
          adoquery->SQL->Add(sql_befehl);
    
          if(ausfuehrungsart == WITHOUT_RESULT)
          {
             adoquery->Active = false;
          }
          if(ausfuehrungsart == WITH_RESULT)
          {
             adoquery->Active = true;
          }
    
          sql_ausfuehrung = adoquery->ExecSQL();
    
       }
       Transaktion_beenden(sql_ausfuehrung);
    
    }
    

    Und zwar wird der SQL-Befehl an die Methode gegeben und eine int-Variable, die entscheidet, ob es eine Ergebnismenge gibt oder nicht.

    In meinem Fall wird ja (da SELECT) eine Ergebnismenge zurückgegeben.Sollte zumindest, denn dies passiert gerade nicht! Und das ist mein Problem.

    Nach dem ausführen "adoquery->ExecSQL()" möchte ich gerne wissen, ob eine Ergebnismenge zurückgegeben wurde! Wie mach ich das? Wie kann ich auf diese Ergebnismenge zugreifen???

    Kann ich auch die Ergebnismenge über einen return an die aufrufende Methode zurück geben?
    Oder kann man das adoquery-Objekt (über eine Pointer) an die aufrufende Methode zurückgeben? Wie mach ich das??

    Vielen Dank für die Antworten!

    Gruß



  • Mit ExecSQL() erhälst Du keine Ergebnismenge, sondern mit Open().
    Du solltest auch Active nicht direkt verwenden, sondern eben Open, Close oder ExecSQL.



  • Hallo

    bei SELECT must du Open anstatt ExecSQL benutzen.
    Das steht auch in der BCB-Hilfe zu beiden Methoden.

    bis bald
    akari



  • Danke für die schnelle Antwort!

    Ich hab das ganze auch mit Open probiert (hatte das auch in der HIlfe nachgelesen) doch es gibt trotzdem keine Ergebnismenge!

    Wie kann ich mir das denn vorstellen, wo die Daten nach einem ausgeführten SQL Befehl stehen?!
    Sind die in einer Variable gespeichert (welche?) und wie komm ich an die ran?

    Brauche ich um eine datenmenge speichern zu können auch eine DataSource - Koponente oder reicht wirklich nur die ADOQuery aus?

    Nachdem ich adoquery->Open() ausgeführt habe, kommt folgender Hinweis (wenn ich mit der Maus über den Befehl gehe):

    E2027 Eine Speicheradresse muss verwendet werden?

    Hat das was damit zu tun warum es nicht geht?



  • Aus der Hilfe:

    Datensensitive Steuerelemente werden über Datenquellen mit einer Datenbank verbunden. Eine Datenquellenkomponente (TDataSource) dient als Bindeglied zwischen dem Steuerelement und der Datenmenge, welche die Daten enthält. Jedem datensensitiven Steuerelement muß eine Datenquellenkomponente zugeordnet sein, damit es Daten anzeigen und bearbeiten kann. Umgekehrt muß auch allen Datenmengen eine Datenquellenkomponente zugeordnet sein, damit die in der Datenmenge enthaltenen Daten in datensensitiven Steuerelementen eines Formulars angezeigt und bearbeitet werden können.

    Hinweis: Datenquellenkomponenten sind auch zum Verknüpfen nicht verschachtelter Datenmengen in Haupt-/Detail-Beziehungen erforderlich.



  • Dein Connection-String ist falsch.

    adoquery->ConnectionString = "Provider="DB_PROVIDER";Password="DB_PASSWORD";"
                                       "User ID="DB_USER_ID";Data Source="DB_DATA_SOURCE";"
                                       "Persist Security Info=True;";
    

    Ich denke Du wolltest

    adoquery->ConnectionString = "Provider="+DB_PROVIDER+";Password="+DB_PASSWORD+";User ID="+DB_USER_ID+";Data Source="+DB_DATA_SOURCE+";Persist Security Info=True;";
    

    weil die Werte Variablen sind und Du ja einen (Ansi)String übergibst.

    Weiterhin würde ich immer vor einen ADOQuery->SQL->ADD ein ADOQuery->SQL->Clear durchführen, um zu gewährleisten, daß da auch ja nichts drin steht.

    Zur SQL-Befehlabarbeitung (Insert,update,delete) ist die Query als DataSet schon genau richtig und nichts weiter notwendig.



  • an die Ergebnismenge kommt man nicht indem man einfach
    sql_ausfuehrung = adoquery->ExecSQL(); oder
    sql_ausfuehrung = adoquery->Open(); macht

    du musst schon mit FieldByName oder Fields[Index] darauf zugreifen
    in einem anderen Thread von dir wurde von caspar_louis schon ein Beispiel gegeben



  • @caspar_louis:

    ich glaube schon, dass mein ConnectionString so richtig ist, da die Variablen
    #define Werte sind. Und mit einem "+" würde es an dieser Stelle nicht gehen!
    Die Verbindung wird auch hergestellt. Ich denke, dass mein Problem an einer anderen Stelle liegt.

    Ich habe jetzt mal dasProgramm zum Testen ein wenig verändert.
    Es lautet jetzt so:

    TDataSet *dataset;
       AnsiString DB_PROVIDER      =     "******";
       AnsiString DB_PASSWORD      =     "******";
       AnsiString DB_USER_ID       =     "******";
       AnsiString DB_DATA_SOURCE   =     "******";
    
       adoc->ConnectionString =  "Provider="+DB_PROVIDER+";Password="+DB_PASSWORD+";"
                                 "User ID="+DB_USER_ID+";Data Source="+DB_DATA_SOURCE+";"
                                 "Persist Security Info=True;";
       adoc->Open();
    
       adoquery->DataSource = datasource;
       adoquery->Connection = adoconnection;
    
       AnsiString sql;
       AnsiString ergebnis;
       int count;
    
       sql = "SELECT bs.emailsperre FROM Bearbeitungsstatus bs WHERE bs.personalnummer = 85/150 AND bs.monat = 3 AND bs.jahr = 2006";
    
       adoquery->SQL->Clear();
       adoquery->SQL->Add(sql);
       adoquery->Open();
    
       dataset = adoquery->DataSource->DataSet;
       count = dataset->FieldCount;
    

    Er kommt jetzt bis zur Stelle

    dataset = adoquery->DataSource->DataSet;
    

    Wenn ich danach die Anzahl abfragen möchte, dann schmeist er mir folgenden Fehler:

    Im Projekt xxxx ist eine Exception der Klasse EAccessViolation aufgetreten. Meldung:
    Zugriffsverletzung bei Adresse 4032C91C in Modul dbrtl60.bpl. Prozeß wurde angehalten. Mit Einzelne Anweisung oder Start
    fortsetzen.

    Das Programm ist doch von Ansatz her richtig, oder?

    Jetzt wollte ich eigentlich mit der TDataSet Komponente auf die Ergebnismenge zugreifen und damit was machen!
    z.B.

    ergebnis = dataset->Fields->Fields[0]->AsString;
    

    Kann mir einer weiterhelfen den Fehler zu beheben?

    Vielen Dank



  • Do sulltest mal den Bereich Datenbanken im Builder Tutorial hier auf dieser Seite durchgearbeiten ...



  • count = dataset->FieldCount;
    

    Welche Anzahl?
    Du fragst die Anzahl der Spalten ab, nicht die die der Datensätze. Willst Du das?
    Sonst

    count =ADOQuery->RecordCount;
    

    BCB-Hilfe

    Mit SQL legen Sie die SQL-Anweisung fest, die mit Hilfe der Methoden ExecSQL oder Open der ADO-Abfragekomponente ausgeführt wird.

    ...

    ADOQuery1->Close();

    ADOQuery1->SQL->Clear();
    ADOQuery1->SQL->Add("SELECT EmpNo, LastName, FirstName, HireDate");
    ADOQuery1->SQL->Add("FROM Employee");

    ADOQuery1->Open();

    Warum "öffnest Du Deine Query, bevor Du was zur Abfrage übergeben hast?

    dataset brauchst Du nicht.

    ergebnis = ADOQuery->Fields[0]->AsString;
    


  • @loggi:

    Im Prinzip hast du schon recht, dass werde ich auch machen, doch ich habe ein kleines Problem mit meinem Programm gerade und ich müsste schon schnell vorwärts kommen;

    Ich brauche vielleicht mal ein kleines Bsp für ADO - Komponenten (welche ich benutzen muss...)
    Damit ich endlich eine Ergbenismenge bekomm und auf die zugreifen kann!

    Sorry wenn ich ein wenig gereizt schreib, aber es nervt mich, dass ich mit dem selben SQL-Befehl im Datenbank Explorer von BCB eine Ergebnismenge bekomm (genau die die ich haben möchte) und mit den Komponenten bekomm ich das gerade nicht hin!

    Mit ist klar, das ich zum Ausführen eines SQL-Befehls eine ADOQuery - Komponente benutzen kann. Wenn eine Ergebnismenge zurück kommt dann ->Open() ansonsten ->ExecSQL();

    Ich brauch auch eine DataSource - Komponente, da diese die Ergebnismenge speichert(??) oder?

    So, jetzt führe ich also mein SQL Statement aus nachdem ich eine Verbindung hergestellt habe aber es kommt keine Ergebnismenge zurück 😡

    HILFE!



  • Ich brauch auch eine DataSource - Komponente, da diese die Ergebnismenge speichert(??) oder?

    Nein, dein Query kann mehr als du denkst.
    Deine Ergebnismenge hast du im Query.



  • OK!
    caspar_louis hat ja auch anhand einem Bsp schön gezeigt, wie man das mit dieser Komponente lösen kann.
    Leider bekomm ich aber keine Ergebnisse übermittelt! Das ist ziemlich komisch da ich wie gesagt mit dem selben SQL Befehl ja im Datenbank Explorer ein Ergebnis bekomm.

    Habe ich vielleicht eine Einstellung vergessen?
    Denn er bringt ja so keine Syntaxfehler sondern er liefert mir immer "0" bei RecoderCount obwohl er in diesem Fall ja "1" sein müsste!

    Ich habe in meine Projekt eine ADOConnection, ADOQuery und eine TDataSource Komponente.

    (fehlen welche?)



  • Komponenten sollten nicht fehlen.

    Was mir aufgefallen ist

    SELECT bs.emailsperre FROM Bearbeitungsstatus bs WHERE bs.personalnummer = 85/150 AND bs.monat = 3 AND bs.jahr = 2006

    Sollte das ein String sein, vovon ich ausgehen, dann gehört das in Hochkommas o.ä. (je nach SQL).
    Sonst fragt er auf bs.personalnummer = 0.56, weil er ja 85/150 rechnet.



  • Ich habe jetzt hinbekommen, dass ADOQuery->FieldCount mir ein Ergegbis liefert.
    Das Ergbenis ist "1";

    Jetzt möchte ich das Ergebnis in einen AnsiString kopieren.

    Und zwar habe ich folgendes probiert:

    ergebnis =  adoq->Fields->Fields[0]->AsString;
    

    Doch er schreibt mir in die Variable "ergebnis" nur den Wert NULL!! Woran kann das denn jetzt liegen?

    Oder muss man ganz anders auf die Ergebnismenge zugreifen?

    Danke für die Antworten (sie helfen mir wirklich weiter)



  • Liest Du die Antworten ?

    Falls ja, dann lies sie nochmal.



  • @caspar_louis:

    Ja ich lese sie 😉
    Aber du hattest mir folgenden Befehl gezeigt:

    ergebnis = ADOQuery->Fields[0]->AsString;
    

    Wenn ich so den Befehl ausführen möchte, dann bringt er mir folgenden Fehler

    [C++ Fehler] Unit1.cpp(50): E2288 Zeiger auf Struktur auf linker Seite von -> oder von ->* erforderlich*

    Was ist deiner Meinung nach damit zu machen?



  • BCB-Hilfe

    Beschreibung

    Mit FieldCount können Sie die Anzahl der in der Eigenschaft Fields aufgelisteten Felder ermitteln. Bei Datenmengen mit dynamisch erstellten Feldern kann der Wert bei jedem Öffnen unterschiedlich sein. Bei Datenmengen mit persistenten Feldern sollte FieldCount bei jedem Öffnen der Datenmenge identisch sein.

    Das sagt Die also nur, daß Du eine Spalte abgefragt hast (Bei dem Select). Es sagt Dir gar nichts über die Ergebnismenge aus. Da mußt Du schon ADOQuery->RecordCount nehmen. Das gibt die Anzahl der Treffer.



  • Oh gott stimmt ja!

    Sorry! Das hatte ich ganz übersehen. Ich habe das Projekt neu gestartet und da waren die Änderungen von vorher nicht übernommen worden.

    Wenn ich jetzt RecordCount nehme dann liefert er mir "-1" als Ergebnis.
    Laut Hilfe:

    RecordCount enthält nur dann einen gültigen Wert, wenn die Datenmenge aktiv ist. Wenn die Anzahl der Datensätze nicht ermittelt werden kann, ist RecordCount -1.

    kann also hier keine Datensätze ermittelt werden.
    Was meinen die denn mit "Datenmenge aktiv ist"?? Muss man noch eine Einstellung vornehmen, damit ich sie abrufen kann?

    Die Werte stehen ja in der DB, aber ich komm nicht dran! So ein scheiß!



  • ergebnis = ADOQuery->Fields[0]->AsString;
    

    Ja das war natürlich falsch. 😮

    ergebnis = ADOQuery->FieldByName("NameDesFeldes")->AsString;
    

    wäre richtig. Aber das scheinst Du nicht so richtig zu mögen.

    Ich setze das immer ein, um nicht von der Reihenfolge im Select abhängig zu sein. Das kann sich ja ändern. Wenn du stur nach Index arbeitest, kann es Dir passieren,daß Du die falschen Werte zuordnest (nicht bei Abfrage von nur einer Spalte).

    Die Datenmenge = Abfragemenge = RecordSet im DataSet von ADOQuery wird mit Open() aktiv, mit Close() inaktiv, also dann wenn Du die Abfrage ausführst.

    Ich denke immer noch, daß Du kein Ergebnis kriegst, weil Deine Where-Bedingung nicht korrekt ist (siehe vorherige Antworten). Dazu hast Du Dich auch noch nicht geäußert.


Anmelden zum Antworten