[C++Builder] Hilfe zu ADO-Abfragen



  • @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.



  • Hmm wenn ich ehrlich bin hat mir die Lösung mit dem "FieldByName" wirklich nicht so gut gefallen!

    Aber deine Argumente scheinen für diese Methode zu sprechen!

    Wahrscheinlich hast du recht mit der where Bedingung!

    Ich habe gedacht, dass wenn ich schreibe:

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

    das er dann alles als String ansieht und diesen dann ausführen kann!
    Müssen also Werte nach denen gesucht werden immer in Hochkomma stehen?

    Wie würde ich das in diesem Fall richtig machen?

    Wenn ich z.B. ein anderes SQL-Statement nehme wie:

    AnsiString persnr = "67/150";
    
    sql = "select a.datum from aida_daten a where a.personalnummer = "+persnr;
    

    dann führt er sogar nicht mehr die Methode adoquery->Open() aus!
    Er meldet EDatabaseError -> Ungültige Feldgröße!

    Was hat das denn jetzt schon wieder zu bedeuten? Alle SQL-Befehle teste ich vorher im DB-Explorer und die funktionieren super.

    Das einzige ist, das es mit diesem Hochkommas zusammenhängen kann!
    Wie kann ich das lösen? 😞



  • Hast Du mal den Debugger benutzt und dabei den Ausdruck sql überwacht?

    Welchen Inhalt hat sql, wenn Du es mit <<ADOQuery->SQL->ADD(sql);>> übergibst?

    Du kannst auch den Ausdruck <<ADOQuery->SQL>> selbst überwachen und sehen, was da rauskommt.

    Ich hätte übrigens auf folgende Syntax für den SQL-Befehl getippt.

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

    Also z.B. so zusammengebaut

    AnsiString persnr = "67/150";
    
    AnsiString sql = "select a.datum from aida_daten a where a.personalnummer = '"+persnr+"'";
    

    Eleganter wäre natürlich die Übergabe von Parametern an das SQL-Konstrukt(nachzulesen in BCB-Hilfe).

    So und nun mach ich erst mal Mittag. 😃



  • Also ich hab schon jetzt des öffteren gedebuggt und bekomme folgenden String der AnsiString-Variablen zugewiesen:

    "select a.datum from aida_daten a where a.personalnummer = '85/150'"

    So müsste es ja eigentlich stimmen oder?
    Er bringt aber trotzdem keine Ergebnismenge!

    Woran kann das denn liegen? 😕



  • Poste bitte mal den Code-Ausschnitt von der Übergabe (Also Zusammenbau SQL-String) über das Öffnen bis zur Abfrage der Ergebnismenge.

    Sonst bleibt das ganze doch bloß Bäume suchen im Wald.

    Mach den Auschnitt lieber zu groß als zu klein.



  • Schau mal ich habe folgenden Teil geändert:

    adoq->SQL->Clear();
    adoq->SQL->Add("SELECT a.datum FROM aida_daten a");
    adoq->SQL->Add("WHERE a.personalnummer = (:Persnr)");
    adoq->Parameters->ParamByName("Persnr")->Value  = "85/150";
    adoq->Open();
    

    Er sagt mal keinen Syntaxfehler, aber ich vertraue mal auf dein Wissen. Kann das so funktionieren?

    Nach dem "adoq->Open()" wird immer noch keine Ergebnismenge geliefert.
    Ich habe es vorher schon mal geschrieben und zwar wird ein ein "Hint" gezeigt wenn ich mit der Maus über den Programmcode "adoq->Open()" gehe.
    Dieser hat folgende Nachricht:

    adoq->Open() = E2027 Eine Speicheradresse muss verwendet werden

    Muss ich mich um diese Meldung kümmern oder sagt diese nicht wichtiges aus?



  • SO hier mal mein kompletter Code:

    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    #include "DB.hpp"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    
       AnsiString DB_PROVIDER      =     "MSDASQL.1";
       AnsiString DB_PASSWORD      =     "root";
       AnsiString DB_USER_ID       =     "root";
       AnsiString DB_DATA_SOURCE   =     "Time_Server";
    
       adoc->ConnectionString =  "Provider="+DB_PROVIDER+";Password="+DB_PASSWORD+";"
                                 "User ID="+DB_USER_ID+";Data Source="+DB_DATA_SOURCE+";"
                                 "Persist Security Info=True;";
    
       adoc->Open();
    
       adoq->DataSource = ds;
       adoq->Connection = adoc;
    
       AnsiString sql;
       AnsiString ergebnis;
       AnsiString persnr = "85/150";
       int count;
    
       //sql = "SELECT bs.emailsperre FROM Bearbeitungsstatus bs WHERE bs.personalnummer = 85/150 AND bs.monat = 3 AND bs.jahr = 2006";
       //sql = "select * from Mitarbeiter m where m.personalnummer = 85/150";
       //sql = "select a.datum from aida_daten a where a.personalnummer = '"+persnr+"'";
    
       adoq->SQL->Clear();
       adoq->SQL->Add("SELECT a.datum FROM aida_daten a");
       adoq->SQL->Add("WHERE a.personalnummer = (:Persnr)");
       adoq->Parameters->ParamByName("Persnr")->Value  = "85/150";
       adoq->Open();
    
       count = adoq->RecordCount;
    
    }
    //---------------------------------------------------------------------------
    

    Hoffe man sieht jetzt mehr! 🙂



  • Und hier auch nochmal die Klasse:

    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include <ADODB.hpp>
    #include <DB.hpp>
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
       TButton *Button1;
       TADOQuery *adoq;
       TDataSource *ds;
       TADOConnection *adoc;
       TADODataSet *adod;
       void __fastcall Button1Click(TObject *Sender);
    private:	// Anwender-Deklarationen
    public:		// Anwender-Deklarationen
       __fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    


  • Natürlich habe ich nicht Deine DB.

    Also habe ich mal folgendes gemacht:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       TADOQuery *adoq = new TADOQuery(this);
       TADOConnection *adoc = new TADOConnection(this);
    
       adoc->ConnectionString =  "...MeinConnectionStringAufMeineDB...";
    
       //adoq->DataSource = ds; //Hier erschließt sich mir der (Un)sinn nicht
       adoc->Open();
    
       adoq->Connection = adoc;  //wahnsinnig aussagekräftige & unterscheidbare Variablen adoc<->adoq
    
       AnsiString sql;
       AnsiString ergebnis;
       int count;
    
       if (adoq->Active)
            adoq->Close();  // immer schön vorsichtig sein
    
       adoq->SQL->Clear();
       adoq->SQL->Add("SELECT AUFTRAG FROM AUFTRAEGE a");
       adoq->SQL->Add("WHERE a.auftrag = (:Auftrag)");
       adoq->Parameters->ParamByName("Auftrag")->Value  = "TEST";
       adoq->Open();
    
       count    = adoq->RecordCount;
       ergebnis = adoq->FieldByName("AUFTRAG")->AsString;
    
       Edit1->Text= count;
       Edit2->Text= ergebnis;
    }
    

    wenn ich auf den Knopf drück (didel didel dum) ->
    Ergebnis ist 1, "TEST". 👍

    Also mein C++ -Code ist funktionsfähig. -> Dein Code sollte auch funktionieren (wenn Du den Quatsch mit der DataSource wegläßt), vorausgesetzt, Dein Select ist OK .



  • Ach ja:
    Da Du die Connection und die Query wo anders erstellst,
    ist

    if (adoc->Connected)
       adoc->Close();
    
    //&
    if (adoq->active)
       adoq->Close();
    

    Pflicht. 😉 Du kannst ja schon vor Event-ButtonClick alles mögliche damit anstellen.

    Und ja ich verschreib mich dauernd mit adoq <->adoc, also aufpassen. 😃



  • JA wunderbar!
    Es funktioniert! JUHU! 😃

    Vielen Dank für deine Hilfe und deine Geduld. Es hat sich aber gelohnt!

    Die ADO-Komponenten müssen erst meine Freunde werden *g* aber das ist schon mal ein guter Anfang!


Anmelden zum Antworten