Access und ODBC



  • Hallo,

    Nach 3 stündigem durchforsten der MSDN und des Forums hier habe ich zwar viel gefunden aber irgendwie kann ich das Alles trotzdem nicht zusammenfügen und gescheit benutzen. Und deshalb gibts hier halt einen weiteren Access-Thread, tut mir Leid. Es geht um folgendes:

    In einer *.mdb Datenbank (bekannterweise Access) sind tausende von Routeninformationen gespeichert. Ich müsste nun eine Datei auslesen (kein Problem, schon mehrmals gemacht und funktioniert wunderbar) und aus dieser Datei die Routeninformation holen, diese mit der Spalte "RouteNr" in der Tabelle "T_Route" vergleichen und dann zwei Spalten in der Datenbank "weitergehen" (wäre Spalte "TD1") wo dann meine gewünschte Information steht und welche ich dann zum weiterverarbeiten brauche. Mein Problem beschränkt sich nur auf die Datenbank. Das fängt schonmal beim öffnen an. In DIESEM Thread habe ich folgendes gefunden:

    SQLConfigDataSource(NULL, ODBC_ADD_DSN, "Microsoft Access Driver (*.mdb)",  
                       "DSN=Name\0"  
                       "Description=Meine Datenquelle\0"  
                       "FileType=MS Access\0"  
                       "DBQ=m_strEditDatabaseLocation\0"  
                       "MaxScanRows=20\0");
    

    Die Member-Variable 'm_strEditDatabaseLocation' enthält den Pfad zu der Datenbank, der Rest sollte eigentlich auch stimmen (ich bin mir nur nicht ganz sicher wofür Description benutzt wird, ist das der Datenbankname oder wie?). 'odbcinst.h' habe ich bereits includet. Beim kompilieren gibt er folgende 2 Fehler aus:

    error LNK2001: unresolved external symbol _SQLConfigDataSource@16

    fatal error LNK1120: 1 unresolved externals

    Warum? Was habe ich falsch gemacht? SQLConfigDataSource sollte er ja kennen? Allgemein ist mir das ganze Datenbankzeugs in C++ noch nicht wirklich so klar, bin eigentlich an MySQL und PHP gewöhnt.

    Danke für die Hilfe...



  • hallo

    linke mal die odbc32.lib odbccp32.lib hinzu.

    als header nutzte ich meist

    #include "windows.h"
    #include "sql.h"
    #include "sqlext.h"
    #include "odbcinst.h"

    und hier nochmal der entscheidende link, falls noch was fehlt:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcodbc_api_reference.asp



  • Ach so, ja das funktioniert jetzt. Ich hab schon die nächste Krise...

    Ich hab, wie im Thread beschrieben, eine CRecordset-Klasse mit dem Namen 'CTRoute' gemacht (weil die Tabelle die ich Abfrage so heisst). In meiner Hauptdialogklasse hab ich nun folgende Funktion:

    void CRouteSortDlg::GetDatabaseInformation()
    {
    	SQLConfigDataSource(NULL, ODBC_ADD_DSN, "Microsoft Access Driver (*.mdb)",  
    					   "DSN=Name\0"  
    					   "Description=SBB Route\0"  
    					   "FileType=MS Access\0"  
    					   "DBQ=m_strEditDatabaseLocation\0"  
    					   "MaxScanRows=20\0");
    
    	CTRoute	*m_pSet;
    
    	m_pSet = new CTRoute(NULL);
    
    	m_pSet->m_strFilter = "RouteNr = 5003";
    
    m_pSet->Open(CRecordset::snapshot, NULL, CRecordset::readOnly);
    
    	m_pSet->Requery();
    }
    

    Die Recordklasse habe ich oben includet, er hat aber trotzdem 28 Fehler. Sachen wie "error C2653: 'CRecordset' : is not a class or namespace name" beim Open() oder Sachen wie "error C2504: 'CRecordset' : base class undefined" in der VOM ASSISTENTEN erstellten Recordsetklasse. Ich bin am verzweifeln...

    Gibt es keine Schritt-für-Schritt Anleitung oder sowas? Ich peil das einfach nicht. Vor allem verstehe ich nicht warum man eine feste Datenbank auswählen muss beim erstellen einer Recordsetklasse. Das ist ja sowas von unsinnig, ich will doch nicht immer die selbe Datenbank öffnen...



  • hi,

    versuch mal folgendes in deiner StdAfx.h dazuzufügen:

    #include <afxdb.h>
    

    sollte dann klappen.( 😉 Höchstwahrscheinlich 😉 )



  • Komisch dass der Assistent das nicht von selber einbindet. Jedenfalls geht es jetzt, vielen Dank. Nur noch eine Frage bezüglich der Datenbank selbst:

    Ist es nicht möglich, variable Datenbanken zu nehmen? In der Applikation die ich schreibe wählt man eine Datenbank von der Festplatte aus und er sollte die öffnen und keine feste. Wenn ich bei SQLConfigDataSource() bei DBQ eine MemberVariable nehme denkt er es wäre der Filename und beim erstellen des Recordsets muss ich ja auch bereits eine feste auswählen. Hab ich einen Denkfehler gemacht?



  • hi,

    Das DBQ=m_bladata\0 übergibst Du ja als String oder Zeichenkette. Steht ja auch in " ".
    Versuch mal was in der Art :
    CString m_strEditDatabaseLocation ="C:\Datenbank\db.mdb"

    "DBQ="+m_strEditDatabaseLocation+"\0" .

    Aber erschieß mich nich wenns nich geht. Bin auch Anfänger was Datenbanken angeht. 🙄
    Viel Glück



  • Das mit dem + ging nicht aber ich habs versucht mit einem formatierten CString, damit hats geklappt. Danke für alle Hilfestellungen, jetzt kommt jedoch noch die letzte Frage:

    Da ich, wie schon gesagt, ein Programm mache bei dem einfach der Pfad zur Datenbank ausgewählt werden soll OHNE jegliche Einstellungen bei den ODBC Datenbanken etc. im Windows vorzunehmen brauche ich da was variables. Denn so wie es jetzt ist hab ich immer die selbe Datenbank zur Hand und ihm ist scheissegal welchen Pfad ich angebe, er nimmt immer die alte. Konkret gesagt muss ich das alles von A - Z im Programm verwalten. Ist das mit ODBC überhaupt möglich und wenn ja, hat jemand vielleicht schonmal sowas in der Art gemacht und könnte mir helfen? Wäre super!



  • BAR schrieb:

    Das mit dem + ging nicht aber ich habs versucht mit einem formatierten CString, damit hats geklappt. Danke für alle Hilfestellungen, jetzt kommt jedoch noch die letzte Frage:

    Da ich, wie schon gesagt, ein Programm mache bei dem einfach der Pfad zur Datenbank ausgewählt werden soll OHNE jegliche Einstellungen bei den ODBC Datenbanken etc. im Windows vorzunehmen brauche ich da was variables. Denn so wie es jetzt ist hab ich immer die selbe Datenbank zur Hand und ihm ist scheissegal welchen Pfad ich angebe, er nimmt immer die alte. Konkret gesagt muss ich das alles von A - Z im Programm verwalten. Ist das mit ODBC überhaupt möglich und wenn ja, hat jemand vielleicht schonmal sowas in der Art gemacht und könnte mir helfen? Wäre super!

    sorry - raff ich nicht.

    was meinst du?! - du kannst keine datenbank an einem ausgwählten speicherplatz öffnen?! - das kann nicht sein, da muss dann ein programmierfehler vorliegen. 🙂

    beim odbc treiber musst du den pfad der datenbank mit angeben. du öffnest die datenbank immer über den odbc-treiber. wenn du die datenbank verschiebst, musst du den pfad im treiber ändern, nicht im program.

    Esco



  • Hi Esco,

    Wenn ich bei den Windows Einstellungen unter 'Systemsteuerung -> Verwaltung -> Datenquellen (ODBC)' gehe habe ich ja dort eine Liste meiner ODBC-Treiber. Wenn ich also eine neue Datenbank habe muss ich da immer einen neuen Eintrag machen weil der Pfad ja immer anders ist. Oder irre ich mich da? Ich gehe mal davon aus dass die Datenquelle "Microsoft Access-Datenbank" bei jeden Windows-PC standardmässig vorhanden ist weil da kein Pfad angegeben wurde. Wenn ich jedoch eine neue CRecordset-Klasse in meinem MFC-Programm erstellen möchte muss ich ja zwingend den Datenbankpfad auswählen.

    Da ich in meinem Programm aber (unabhängig davon wie die Einstellungen auf dem PC sind) den Pfad zu einem BELIEBIGEN mdb-File auswählen lassen muss brauche ich da halt dynamische Pfade. Ist klar was ich meine? Die Datenbank ist nicht immer "C:\Datenbanken\Datenbank1.mdb" sondern halt was beliebiges (z.B. "C:\Anderer Ordner\Datenbank2.mdb"). Ist das mit ODBC realisierbar oder kann man da nur eine feste Datenquelle haben? Wäre schade...





  • Ja danke, das ist es. Bin nun schon seit cirka einer Stunde dran das ganze dynamisch zu machen, natürlich klappts nicht...

    void CRouteSortDlg::MakeNewDataSource()
    {
    	CAdditionalFunctions    AF;
    
    	char dataSourceParams[256];
    	char databaseLocation[256];
    
    	//Convert CString to char
    	strcpy((char*)databaseLocation, m_strEditDatabaseLocation);
    
    	AF.FormatDataSourceParams(dataSourceParams, "Test Dingsda", "Test Dingsda", "MS Access", databaseLocation, "20");
    
    	SQLConfigDataSource(NULL, ODBC_ADD_DSN, "Microsoft Access Driver (*.mdb)", dataSourceParams);
    }
    

    Ist die Funktion wo ich die neue Datenquelle erstellen will.

    BOOL CAdditionalFunctions::FormatDataSourceParams(char* result, const char* DSN, const char* description, const char* FileType, const char* DBQ, const char* MaxScanRows)
    {
       sprintf(result,"DSN=%s\\0\"\"Description=%s\\0\"\"FileType=%s\\0\"\"DBQ=%s\\0\"\"MaxScanRows=%s\\0", DSN, description, FileType, DBQ, MaxScanRows);
    
       return TRUE;
    }
    

    Funktion für das Ganze Parametergedönse.

    Wenn ich mit dem Debugger durchsteppe gibt er mir die Parameter PERFEKT FORMATIERT zurück. Dann macht er das SQLConfigDataSource() und bei der Verwaltung seh ich keine neue ODBC Datenbank. Dann dachte ich er hat n Problem mit dem ersten und dem letzten Anführungszeichen. Also "\"DSN=... gemacht. Geht selbstverständlich auch nicht. Was geht denn bitte? Ich hab mir den String den er zurückgibt Zeichen für Zeichen angeschaut und GENAU SO ins SQLConfigDataSource() geschrieben, einfach statisch. Und siehe da, die Kacke geht. Ich brauch aber einen DYNAMISCHEN PFAD und das scheint eine Sache der Unmöglichkeit zu sein. Übrigens (ich hab da vor dem 0 absichtlich 2 Backslashes denn sonst gibt er mir keine Null zurück, so tut er es).

    Kann man irgendwie bei den Parametern auch nur den DBQ-Pfad dynamisch angeben? Mit "DBQ=" + pfad + "\0" gehts auch nicht. Argh 😡



  • Es scheint so als hätte ich mich nicht so verständlich ausgedrückt. Also nochmal mit Bild:

    http://www.quarz.cc/axd/sprintf.gif

    So sieht meine Variable aus die ich zurückkriege. Und es sollte doch möglich sein diese beim SQLConfigDataSource() einzusetzen? Soweit ich das sehe stimmen alle Zeichen und wenn ich genau diese Zeichenfolge in das SQLConfigDataSource schreibe funktioniert es einwandfrei. Wieso macht er Probleme? Stört ihn das 0, die Anführungszeichen oder was?

    Ich kann nicht glauben dass es so schwer ist einfach einen DYNAMISCHEN PFAD zu benutzen...

    EDIT: Jetzt hab ich noch \n reingemacht und ein \" vorne und eins hinten. Danach das Ganze mit einer AfxMessageBox ausgegeben:
    http://www.quarz.cc/axd/messagebox.gif Was ist denn nun daran falsch? Nichts. Es klappt aber trotzdem nicht...



  • mir ist nicht ganz klar, wie das ergebnis aussehen muss (odbc ist lange her 😉 ), aber ich sehe da oben so viele "" "", die hintereinander stehen...



  • Hi elise,

    Das Ergebnis müsste so aussehen:

    SQLConfigDataSource(NULL, ODBC_ADD_DSN, "Microsoft Access Driver (*.mdb)", 
                       "DSN=New Dingsda\0"
                       "Description=New Dingsda\0"
                       "FileType=MS Access\0"
                       "DBQ=Der Pfad den ich halt dynamisch hier einsetzen will\0"
                       "MaxScanRows=20\0");
    

    Wie du siehst hats hier auch einige "" 😉



  • Also wenn niemand ne Idee hat warum es nicht gehen könnte dann mach ich das einfach manuell bzw. ich schreibe alle Einträge manuell in die Registry. Ich würds eigentlich ungern machen weils halt besser ist gerade die dazugehörende Funktion zu benutzen aber wenn das so weitergeht wirds mir scheissegal wie ichs gemacht hab, es soll einfach funktionieren.


Anmelden zum Antworten