none
Wo in MS-ACCESS kann man _beliebige_ SQL-Befehle (nicht nur Abfragen) erstellen ?

    Frage

  • Hallo allerseits,
    Zwar kann man in einem Fenster von MS-ACCESS eine SQL-Abfrage zu einer in MS-ACCESS erstellen DB (bzw. Tabelle) reinstellen.
    Aber kann man auch eine DB bzw. Tabelle erzeugen, _ohne_ daß man innerhalb von MS-ACCESS irgendeine DB bzw. irgendeine Tabelle erzeugt hat ?
    Ich brauche also _nur_ einen "SQL-Interpreter" 

    Was muß ich machen, daß dies funktioniert ?

    mfg
    Bh
    Dienstag, 22. November 2016 09:42

Alle Antworten

  • Hallo Bernhart,

    es ist schon zwar schon ewig her, dass ich mit Access gearbeitet habe, frühere Versionen hatten ein solches Feature aber nicht bzw. nur bedingt über die Möglichkeit, eine Abfrage auch in der (extrem bescheidenen) SQL Ansicht anzeigen zu lassen.

    Ich würde hier eher hingehen und ein Formular mit einem Textfeld und einem Button einbauen, das dann über einen Befehl hinter dem Button den eingegebenen Text gegen die Datenbank ausführt. Siehe dazu bspw.:

      https://msdn.microsoft.com/de-de/library/office/ff197654.aspx

      https://msdn.microsoft.com/de-de/library/office/ff194626.aspx


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    • Als Antwort vorgeschlagen Stefan FalzMVP Donnerstag, 2. März 2017 01:05
    Dienstag, 22. November 2016 10:44
  • Aber kann man auch eine DB bzw. Tabelle erzeugen, _ohne_ daß man innerhalb von MS-ACCESS irgendeine DB bzw. irgendeine Tabelle erzeugt hat ?

    Hallo!

    Das klingt für mich wie "Kann man in Word Text schreiben, ohne ein Word-Dokument zu öffnen." Ich verstehe dich aber vermutlich nur falsch. ;)

    Was verstehst du unter einem SQL-Interpreter?
    Für welchen SQL-Dialekt soll er sein?

    Oder willst du aus einer Access-Anwendung auf eine externe Datenbank zugreifen?

    mfg
    Josef


    Code-Bibliothek für Access-Entwickler
    AccUnit - Testen von Access-Anwendungen
    Virtueller Access-Stammtisch

    Dienstag, 22. November 2016 11:31
  • Hallo bh,

    das wie hast Du doch schon bekommen, wenn Du an in das letzte Beispiel-Projekt guckst. Die CreateTable Methode dort erzeugt eine Tabelle mit SQL. Und auch alle anderen Befehle (SELECT, INSERT usw.) werden direkt mit SQL übermittelt.

    Die Access Oberfläche tut letztendlich nichts anderes. In der SQL Ansicht (einer jeglichen Abfrage) von Access kann man die gleichen Befehle eingeben.

    Ein Access ohne Datenbank gibt es prinzipbedingt nicht. Denn schließlich muss die Arbeit auf irgendetwas angewendet werden. Sei es das Erzeugen einer Tabelle oder das Abfragen von Daten (aus der Datenbank).

    Gruß Elmar

    • Als Antwort vorgeschlagen Stefan FalzMVP Donnerstag, 2. März 2017 01:05
    Dienstag, 22. November 2016 12:18
  • Hallo Elmar,

    Wenn Access es so will mach ich es eben so:
    Ich nehme einfach die in meinem letzten C++ Programm dort erstellte mdb-Datei und öffne diese.
    Dann erzeuge ich dort irgendeine Abfrage mit dem Abfrageassistent.
    Dann gehe ich in die SQL-Ansicht und lösche dann den ganzen von Access erzeugten Abfrage-Schrott raus.
    Dann kopiere ich z.B. die folgende Zeile rein:
    CREATE TABLE Atoms (Atom INT NOT NULL);
    Ergebnis: Funktioniert.

    Dann lösche ich alles raus und kopiere rein:
    CREATE TABLE Atoms (Atom INT NOT NULL);
    CREATE TABLE Btoms (Btom INT NOT NULL);
    Ergebnis:
    Fehlermeldung: Sysntaxfehler in CREATE TABLE Anweisung
    wobei der Kursor auf das CREATE TABLE in meiner 2. Zeile zeigt und
    damit diesen SQL-Befehl anzweifelt.
    Wo ist mein Fehler ?

    mfg
    BH

    Dienstag, 22. November 2016 14:16
  • Hallo bh,

    Access kann immer nur einen Befehl je Abfrage ausführen, einen Abfragestapel gibt es dort nicht (im Gegensatz zum SQL Server).

    Wie insgesamt der Umfang von SQL von Datenbanksystem zu Datenbanksystem deutlich variiert. Es gibt zwar so etwas wie ANSI-SQL. Defacto implementieren selbst die großen Systeme (SQL Server, Oracle, Db2 uam.) nur einen Teil davon, dafür kannten und kennen sie jede Menge proprietäre Erweiterungen.

    Access als Desktop-System kann da nicht mithalten, dafür war es zu Urzeiten (1.x) eines der ersten, das z. B. JOINs (aus ANSI-SQL 89) implementierte.

    Gruß Elmar

    Dienstag, 22. November 2016 14:22
  • Hallo Elmar,

    vielen Dank für deine Info.
    Damit hat sich für mich MS-ACCESS als ausführbares System von selbst vorgegebenen SQL-Befehlen erledigt.
    Ich werde vermutlich mal XAMPP benutzen. Dort kann man einen SQL-Befehlsstapel reinkopieren und abarbeiten lassen.

    mfg
    Bh

    Dienstag, 22. November 2016 15:11
  • Hallo bh,

    das wie hast Du doch schon bekommen, wenn Du an in das letzte Beispiel-Projekt guckst. Die CreateTable Methode dort erzeugt eine Tabelle mit SQL. Und auch alle anderen Befehle (SELECT, INSERT usw.) werden direkt mit SQL übermittelt.

    Hallo Elmar,
    Mein Problem ist:
    Ich will in dem Beispiel-Projekt folgenden SQL-Stapel absenden:
    (da ich nicht weiß wie man das in C++ macht, habe ich nach einer SQL-Stapelverarbeitungsmaschine gesucht).
    ===========================

    CREATE TABLE Atoms (Atom BIGINT NOT NULL);
    INSERT INTO Atoms(Atom) VALUES (3),(5);
    WHILE (10000 > (SELECT COUNT(*) FROM Atoms))
    BEGIN
      INSERT INTO Atoms 
      SELECT DISTINCT(a1.atom+a2.atom)
        FROM Atoms a1
               INNER JOIN Atoms a2 ON a1.atom != a2.atom 
     WHERE NOT EXISTS (SELECT atom FROM Atoms a3 WHERE a3.atom = (a1.atom + a2.atom))

    ===========================

    Frage:
    Ist es schwierig diesen Befehlsstapel in C++ umzusetzen, oder hast du da eine Idee ?

    mfg
    Bh

    Dienstag, 22. November 2016 15:31
  • Hallo bh,

    naja, dafür XAMPP benutzen ist mit Kanonenkugeln auf Mücken geschossen ;)

    Zum einen: Access ist nie als SQL System entworfen worden, sondern mit dem Anspruch eines grafischen Entwurfs (woran sich später Legionen von GUIs orientiert haben). Und wie in der ersten Diskussion schon gesagt: Einmal entworfen kann man eine Access-Datenbank leicht kopieren und so ohne (SQL)-Aufwand verbreiten.

    Zum anderen: Wenn Du eh in Visual Studio arbeitest, kannst Du ebenso eines der Produkte nutzen, die dafür verfügbar sind. Das wäre u. a. SQLite und dazu die SQLiteToolbox, die auch SQL Server Compact unterstützt. Für SQLite gibt es auch jede Menge kleinerer Abfragetools.

    Möchtest Du etwas mehr wäre da der SQL Server, angefangen mit der LocalDb, bis hin zu einer vollständigen Developer Edition via Visual Studio Dev Essentials. Dazu gibt es neben dem Management Studio, was u. a. SQL ausführen kann, auch die SQL Server Data Tools, die sich in Visual Studio integrieren.

    Wobei letztere bereits größere Waffen sind ;)

    Gruß Elmar

    Dienstag, 22. November 2016 15:33
  • Zum anderen: Wenn Du eh in Visual Studio arbeitest, kannst Du ebenso eines der Produkte nutzen, die dafür verfügbar sind. Das wäre u. a. SQLite und dazu die SQLiteToolbox, die auch SQL Server Compact unterstützt. Für SQLite gibt es auch jede Menge kleinerer Abfragetools.

    Hallo Elmar,
    1)
    wenn ich auf den blauen SQLite Link oben klicke wird dort SQLite zum Download angeboten, genauso
    SQLiteToolbox. Deswegen meine Frage:
    Sind diese schon beim Kauf von MS Visual Studio enthalten ? (Dann muß ich sie nicht mehr downloaden)

    2)
    wenn man also SQLite und SQLiteToolbox auf dem Rechner hat, gibt es im Programm SQLiteToolboxman
    ein Fenster, in das man SQL-Befehle (Stapel)  schreiben kann uind diese werden dann ausgeführt.
    Habe ich das richtig verstanden  oder brauche ich zusätzlich noch die von dir genannten  "Abfragetools"?

    3)
    Nocmals zu meine letzten Posting:
    ===========================

    CREATE TABLE Atoms (Atom BIGINT NOT NULL);
    INSERT INTO Atoms(Atom) VALUES (3),(5);
    WHILE (10000 > (SELECT COUNT(*) FROM Atoms))
    BEGIN
      INSERT INTO Atoms 
      SELECT DISTINCT(a1.atom+a2.atom)
        FROM Atoms a1
               INNER JOIN Atoms a2 ON a1.atom != a2.atom 
     WHERE NOT EXISTS (SELECT atom FROM Atoms a3 WHERE a3.atom = (a1.atom + a2.atom))

    ===========================

    Ist es schwierig diesen Befehlsstapel in C++ umzusetzen, oder hast du da eine Idee ?

    mfg
    Bh

    Dienstag, 22. November 2016 18:53
  • Hallo bh,

    zu 1.) SQLite und die SQLite Toolbox gehören nicht zum Lieferumfang von Visual Studio, SQLite kann über NuGet eingebunden werden, die Toolbox über Tools->Extensions / Updates. Sie sind kostenfrei.

    zu 2.) SQLite ist nur eine Datenbank (ebenso SQL Server Compact und Access), d. h. es gibt keine "Programmiersprache", wie es 3.) erfordern würde. WHILE ist nun mal kein Standard-SQL.

    zu 3.) Das würde beim SQL Server direkt funktionieren, da alle Elemente im Sprachumfang von TRANSACT-SQL enthalten sind.

    In solchen ohne müsste man die Befehle einzeln ausführen. Die WHILE Schleife kann man mit einem ExecuteScalar (siehe andere Diskussion) nachstellen. Alle anderen über das Schicken der Einzelbefehle. (Denn letztendlich ist ein Abfragestapel nichts weiter als eine Auflistung von Einzelbefehlen).

    Alternativ könnte man LINQ nutzen, um die Liste (z. B. eine List<Int64>) im Programm zu erstellen, was jedoch nicht mit C++/CLI wirklich funktioniert - siehe ebenfalls vorherige Diskussion.

    Bei C++ CLI ginge es lokal über ein Nachbilden der verschachtelten Schleifen - ist zwar nicht elegant aber machbar.

    Gruß Elmar

    • Als Antwort vorgeschlagen Stefan FalzMVP Donnerstag, 2. März 2017 01:06
    Dienstag, 22. November 2016 20:00
  • zu 2.) SQLite ist nur eine Datenbank (ebenso SQL Server Compact und Access), d. h. es gibt keine "Programmiersprache", wie es 3.) erfordern würde. WHILE ist nun mal kein Standard-SQL.

    Hallo Elmar,
    1)
    SQLite ist also nur eine DB.
    Für was ist dann SQLiteToolbox gut ?
    Und kann ich auf den von dir genannten  "Abfragetools" damit SQL-Befehle (Stapel)  ablaufen lassen ?'

    [QUOTE]
    Das würde beim SQL Server direkt funktionieren, da alle Elemente im Sprachumfang von TRANSACT-SQL enthalten sind.
    [/QUOTE]

    2)
    Habe zwar gegoogelt, aber leider weiß ich nicht, was du mit "SQL Server" meinst.
    Ist das ein MS spezifischer SQL-Server, oder was meinst du damit genau ?

    3)
    Würde der von mir angegebene SQL-Stapel (mit der while-Anweisung) auf XAMPP problemlos abgearbeitet werden (sind da auch alle Elemente im Sprachumfang von TRANSACT-SQL enthalten?) ?
    (Wie mir gesagt wurde, ist auf den Rechnern (die ich benutzen kann) auch XAMPP installiert).

    mfg
    Bh

    Mittwoch, 23. November 2016 15:25
  • Hallo Bernhart,

    zur SQLite Toolbox siehe bspw. https://github.com/ErikEJ/SqlCeToolbox

    Dort wird beschrieben, was das ist.

    Mit SQL Server wird hier meistens das Produkt Microsoft SQL Server bezeichnet.

    Zu XAMPP: Ich glaube, Du verwechselst/vermischst hier doch einige/viele Dinge, die rein gar nichts miteinander zu tun haben. XAMPP bspw. hat mit SQL Server/T(ransact)-SQL, Access, SQLite oder ähnlichem gar nichts am Hut. Weder gibt es irgendeine Unterstützung dafür noch ist es dafür erstmal vorgesehen.

    Informier dich bitte mal über XAMPP.

    Grundsätzlich kannst Du nicht einfach irgendwelche SQL Statements für irgendwelche (No)SQL Datenbanken beliebig in irgendeinem Tool absetzen. Für jedes DBMS brauchst Du eine spezielle Anwendung, die die Befehle, die Du da eingibst, an das DBMS weiterleitet. Man kann sich natürlich eine eierlegende Wollmilchsau schreiben, die das für jedes erdenkliche DBMS kann, ob das nun sinnvoll ist oder nicht, sei aber dahingestellt.

    In deinem Fall (da Du ja anscheinend SQLite verwenden willst, wobei ich mir da auch nicht so wirklich sicher bin) wäre die SQLiteToolbox sicher ein guter Anfang.

    Für Microsoft SQL Server könnte man bspw. das SQL Server Management Studio (kurz SSMS) verwenden.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community


    Mittwoch, 23. November 2016 16:29
  • zu 3.) Das würde beim SQL Server direkt funktionieren, da alle Elemente im Sprachumfang von TRANSACT-SQL enthalten sind.

    In solchen ohne müsste man die Befehle einzeln ausführen. Die WHILE Schleife kann man mit einem ExecuteScalar (siehe andere Diskussion) nachstellen. Alle anderen über das Schicken der Einzelbefehle. (Denn letztendlich ist ein Abfragestapel nichts weiter als eine Auflistung von Einzelbefehlen).

    Hallo Elmar,
    "In solchen ohne ...". Da habe ich ein Verständnisproblem:
    Wenn in solchen Systemen die while-Anweisung nicht syntaktisch akzeptiert wird, welchen Sinn hat es dann, diese while-Anweisung _nachzustellen_, d.h. zu simulieren, wenn sie vom Server als inkorrekt nicht akzeptiert wird ?

    mfg
    Bh

    Mittwoch, 23. November 2016 17:20
  • Hallo Bernhart,

    "In solchen ohne ...". Da habe ich ein Verständnisproblem: Wenn in solchen Systemen die while-Anweisung nicht syntaktisch akzeptiert wird, welchen Sinn hat es dann, diese while-Anweisung _nachzustellen_, d.h. zu simulieren, wenn sie vom Server als inkorrekt nicht akzeptiert wird ?

    mit "nachzustellen" war eher gemeint, dass die Schleife in deiner Clientanwendung erstellt und ausgeführt wird, innerhalb der Schleife wird dann jeweils der einzelne SQL Befehl an das DBMS gesendet und bspw. per <Command.>ExecuteNonQuery() ausgeführt.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community


    Mittwoch, 23. November 2016 17:42
  • zu 3.) Das würde beim SQL Server direkt funktionieren, da alle Elemente im Sprachumfang von TRANSACT-SQL enthalten sind.

    In solchen ohne müsste man die Befehle einzeln ausführen. Die WHILE Schleife kann man mit einem ExecuteScalar (siehe andere Diskussion) nachstellen. Alle anderen über das Schicken der Einzelbefehle. (Denn letztendlich ist ein Abfragestapel nichts weiter als eine Auflistung von Einzelbefehlen).

    Gruß Elmar

    Hallo Elmar,

    ===============================

    CREATE TABLE Atoms (Atom BIGINT NOT NULL);

    INSERT INTO Atoms(Atom) VALUES (3),(5);

    WHILE (10000 > (SELECT COUNT(*) FROM Atoms))

    BEGIN

      INSERT INTO Atoms

      SELECT DISTINCT(a1.atom+a2.atom)

        FROM Atoms a1

               INNER JOIN Atoms a2 ON a1.atom != a2.atom

     WHERE NOT EXISTS (SELECT atom FROM Atoms a3 WHERE a3.atom = (a1.atom + a2.atom))

    ==============================

    Das obige SQL-Programm (siehe auch früheres Posting) soll in 7 Minuten ca. 40000 Atome anlegen (so wurde mir zumindest gesagt).

    Nun habe ich versucht dieses obige SQL-Programm durch ein C++ Programm zu simulieren.

    Quellcode ist im nächsten Posting

    Das Laufzeitverhalten ist extrem schlecht: Für nur 500 Atome braucht es schon ca. 10 Minuten.
    ( da werde ich fast neidisch J  )
    Frage:
    Kannst du mir einen Tipp geben, warum das Laufzeitverhalten meines Programms so verheerend schlecht ist bzw. wie man es verbessern könnte?
    PS: Die Methode expandTableDB() erzeugt die Atome in der Tabelle.

    Mfg
    Bh


    Donnerstag, 24. November 2016 13:46
  • #include "stdafx.h"


    using namespace System;
    using namespace System::Data;
    using namespace System::Data::OleDb;

    using namespace System::IO;
    using namespace System::Data;
    using namespace System::Data::OleDb;
    using namespace System::Runtime::InteropServices;

    namespace NativeMethods
    {
     [DllImport("ODBCCP32.DLL", CharSet = CharSet::Unicode)]
     bool SQLConfigDataSource(IntPtr hwndParent, System::UInt16 fRequest, const String^ lpszDriver, const String^ lpszAttributes);
    }

    /***************************************************************************/
    /**                                                                       **/
    /**  Klasse AccessDatabase                                                **/
    /**                                                                       **/
    /***************************************************************************/
    ref class AccessDatabase
    {
     private:
      String^ _accessFileName;

     public:
      AccessDatabase(System::String^ accessFileName);
      property String^ AccessFileName
      {
       String^ get() { return _accessFileName; }
      }

      String^ GetOleDbConnectionString();

      OleDbConnection^ GetOleDbConnection();

      System::Boolean TableExists(String ^ tableName);
      System::Boolean TableExists(OleDbConnection ^ connection, String ^ tableName);

      Boolean DatabaseExists();
      Boolean CreateIfNotExists();
      Boolean CreateFromResourceIfNotExists();
      void DeleteIfExists();

      OleDbCommand^ GetIdentityCommand(OleDbConnection^ connection);

      private:
       Boolean CreateDatabaseObc();
    };

    // Methode
    AccessDatabase::AccessDatabase(String^ accessFileName)
    {
     if (String::IsNullOrWhiteSpace(accessFileName))
      throw gcnew ArgumentNullException("accessFileName");

     if (Environment::Is64BitProcess)
      throw gcnew InvalidOperationException(L"The Jet Driver requires a 32 bit process.");

     this->_accessFileName = accessFileName;
    }

    // Methode
    System::Boolean AccessDatabase::DatabaseExists()
    {
     return System::IO::File::Exists(this->_accessFileName);
    }

    // Methode
    System::Boolean AccessDatabase::CreateIfNotExists()
    {
     if (DatabaseExists())
      return true;
     return CreateDatabaseObc();
    }

    // wird hier nicht benötigt
    Boolean AccessDatabase::CreateFromResourceIfNotExists()
    {
     if (DatabaseExists())
      return true;

     String^ fileName = System::IO::Path::GetFileName(this->_accessFileName);
     for each (String^ resourceName in System::Reflection::Assembly::GetExecutingAssembly()->GetManifestResourceNames())
     {
      // Resource should end with the database name (without path)
      if (resourceName->EndsWith(fileName, StringComparison::OrdinalIgnoreCase))
      {
       Stream^ resourceStream = nullptr;
       Stream^ fileStream = nullptr;
       try
       {
        // Copy resource to file
        resourceStream = System::Reflection::Assembly::GetExecutingAssembly()->GetManifestResourceStream(resourceName);
        fileStream = gcnew FileStream(this->_accessFileName, FileMode::Create);
        resourceStream->CopyTo(fileStream);
        return true;
       }
       finally
       {
        delete fileStream;
        delete resourceStream;
       }
      }
        Console::WriteLine("Resource {0}", resourceName);
     }
     return true;
    }

    // Methode
    void AccessDatabase::DeleteIfExists()
    {
     if (DatabaseExists())
     {
      System::IO::File::Delete(this->_accessFileName);
     }
    }

    // Methode
    OleDbCommand^ AccessDatabase::GetIdentityCommand(OleDbConnection^ connection)
    {
     // connection may be null
     return gcnew OleDbCommand(L"SELECT @@IDENTITY;", connection);
    }

    // Methode
    String^ AccessDatabase::GetOleDbConnectionString()
    {
     auto builder = gcnew OleDbConnectionStringBuilder();
     builder->Provider = L"Microsoft.Jet.Oledb.4.0";
     builder->DataSource = this->_accessFileName;
     
     //builder.Add(L"Jet OLEDB:Database Password", L"EinKennwort");
     //builder.Add(L"Jet OLEDB:System Database", L"system.mdw");
     return builder->ToString();
    }

    // Methode
    OleDbConnection^ AccessDatabase::GetOleDbConnection()
    {
     return gcnew OleDbConnection(GetOleDbConnectionString());
    }

    // Methode
    System::Boolean AccessDatabase::TableExists(String^ tableName)
    {
     return TableExists(nullptr, tableName);
    }

    // Methode
    System::Boolean AccessDatabase::TableExists(OleDbConnection^ connection,  String^ tableName)
    {
     Boolean ownsConnection = false;
     if (connection == nullptr)
     {
      ownsConnection = true;
      connection = GetOleDbConnection();
     }
     ConnectionState state = connection->State;
     try
     {
      if (state != ConnectionState::Open)
       connection->Open();

      array<Object^>^ restrictions = gcnew array<String^>(4);
      restrictions[2] = tableName;
      restrictions[3] = L"TABLE";
      auto tables = connection->GetOleDbSchemaTable(OleDbSchemaGuid::Tables, restrictions);
      return (tables->Rows->Count > 0);
     }
     finally
     {
      if (ownsConnection)
      {
       delete connection;
      }
      else
      {
       if (connection->State != state)
       {
        connection->Close();
       }
      }
     }
    }

    // Methode
    Boolean AccessDatabase::CreateDatabaseObc()
    {
     const System::UInt16 ODBC_ADD_DSN = 1;
     const String^ MS_ACCESS_DRIVER = L"Microsoft Access Driver (*.mdb)";
     
     String^ attribute = String::Format(L"CREATE_DB=\"{0}\" General", this->_accessFileName);
     auto result = NativeMethods::SQLConfigDataSource(IntPtr::Zero, ODBC_ADD_DSN, MS_ACCESS_DRIVER, attribute);
     return (result != 0) ? true : false;
    }


    /***************************************************************************/
    /**                                                                       **/
    /**  Klasse SampleTable                                                   **/
    /**                                                                       **/
    /***************************************************************************/
    ref class SampleTable

     private:
      AccessDatabase^ _accessDb;

     public:
      SampleTable(AccessDatabase^ accessDb);

      void CreateTable();
      void InsertData(int data);
      void ListData();
      void expandTableDB();
    };

    // Methode
    SampleTable::SampleTable(AccessDatabase ^ accessDb)
    {
     if (accessDb == nullptr)
     {
      throw gcnew ArgumentNullException(L"accessDb");
     }
     this->_accessDb = accessDb;
    }

    // Methode
    void SampleTable::CreateTable()
    {
     //Console::WriteLine(L"Create Table.");
     auto connection = _accessDb->GetOleDbConnection();
     try
     {
      connection->Open();

      if (_accessDb->TableExists(connection, L"Tabelle"))
      {
       Console::WriteLine(L"Table 'Tabelle' already exists.");
       return;
      }

      // see https://msdn.microsoft.com/en-us/library/bb208866(v=office.12).aspx
      // and https://support.microsoft.com/de-de/kb/320435

      auto createCommand = gcnew OleDbCommand(L"CREATE TABLE Tabelle ("
       + L"[Zahl] int NULL UNIQUE);",
       connection);
      // Alternativ wäre diese lange unübersichtliche Schreibweise auch möglich:
      // auto createCommand = gcnew OleDbCommand(L"CREATE TABLE Tabelle (ID int IDENTITY(1, 1) NOT NULL PRIMARY KEY, [Name] nvarchar(40) NOT NULL, [Integer] int NULL, [Number] float NULL, [Decimal] decimal(18, 2) NULL, [Datum] datetime NULL, [Guid] uniqueidentifier NULL)",connection);
      createCommand->ExecuteNonQuery();
     }
     catch (OleDbException^ ex)
     {
      Console::WriteLine(L"CreateTable: {0}", ex->Message);
     }
     finally
     {
      delete connection;
     }
    }

    // Methode
    void SampleTable::InsertData(int data)
    {
     // Console::WriteLine(L"Insert Sample Data.");
     auto connection = _accessDb->GetOleDbConnection();
     try
     {
      connection->Open();
      auto identityCommand = _accessDb->GetIdentityCommand(connection);
      // positionelle Parameterreihenfolge!
      auto insertCommand = gcnew OleDbCommand(
       L"INSERT INTO Tabelle ([Zahl]) "
       + L"VALUES (@Zahl);",
       connection);
      auto integerParameter = insertCommand->Parameters->Add("@Zahl", OleDbType::Integer);
      integerParameter->Value = data;
      if (insertCommand->ExecuteNonQuery() == 1)
      {
       //Console::WriteLine("Einfügen hat geklappt");
      }
     }
     catch (OleDbException^ ex)
     {
      // Wenn Daten dopplet eingetragen werden sollen, erscheint diese Fehlermeldung
      // Sie wird aus Laufzeitgründen ausgeblendet
      // Console::WriteLine(L"InsertData: {0}", ex->Message);
     }
     finally
     {
      delete connection;
     }
    }

    // Methode
    void SampleTable::ListData()
    {
     Console::WriteLine(L"Die Zahlen aus der DB lauten:");
     auto connection = _accessDb->GetOleDbConnection();
     try
     {
      auto adapter = gcnew OleDbDataAdapter(
       // Spaltenwerte der Spalte 1 werden sortiert der Größe nach aufsteigend
       L"SELECT [Zahl] FROM Tabelle ORDER BY 1 ASC;",
       connection);

      auto table = gcnew DataTable(L"Tabelle");
      adapter->Fill(table);


      Int32 wert;
      Int32 columnIndex = 0;
      Int32 rowIndex;
      for (rowIndex = 0; rowIndex < table->Rows->Count; rowIndex++){
       Object^ value = table->Rows[rowIndex][columnIndex];
       wert = safe_cast<Int32>(value);
       Console::Write("{0}; ", wert);
      }
      Console::WriteLine();

     }
     catch (OleDbException^ ex)
     {
      Console::WriteLine(L"InsertData: {0}", ex->Message);
     }
     finally
     {
      delete connection;
     }
    }

    // Methode
    void SampleTable::expandTableDB()
    {
     auto connection = _accessDb->GetOleDbConnection();
     try
     {
      // Lies alle Datensätze aus der DB in table
      auto adapter = gcnew OleDbDataAdapter(
       L"SELECT [Zahl] FROM Tabelle;",
       connection);

      auto table = gcnew DataTable(L"Tabelle");
      adapter->Fill(table);

      Int32 wert1;
      Int32 wert2;
      Int32 integerSum=0;
      Int32 rowIndex1;
      Int32 rowIndex2;
      Int32 columnIndex = 0;
      Int32 anzahlZeilen=table->Rows->Count;
      for (rowIndex1 = 0; rowIndex1 < anzahlZeilen-1; rowIndex1++){
       for (rowIndex2 = rowIndex1+1; rowIndex2 < anzahlZeilen; rowIndex2++){
        Object^ value1 = table->Rows[rowIndex1][columnIndex];
        Object^ value2 = table->Rows[rowIndex2][columnIndex];
        wert1= safe_cast<Int32>(value1);
        wert2= safe_cast<Int32>(value2);
        integerSum = wert1+wert2;
        InsertData(integerSum);
        }
      }
     }
     catch (OleDbException^ ex)
     {
      Console::WriteLine(L"InsertData: {0}", ex->Message);
     }
     finally
     {
      delete connection;
     }
    }


    /***************************************************************************/
    /**                                                                       **/
    /**  H A U P T P R O G R A M M                                            **/
    /**                                                                       **/
    /***************************************************************************/
    int main(array<System::String ^> ^args)
    {
     //String^ accessFileName = System::IO::Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::MyDocuments), "odbctest.mdb");
     String^ accessFileName = System::IO::Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::MyDocuments), "dbWundersam.mdb");
     Console::WriteLine(L"Creating Access Database: '{0}'", accessFileName);

     auto accessDb = gcnew AccessDatabase(accessFileName);

     // Delete existing file (may throw exception)
     accessDb->DeleteIfExists();

     // Create via ODBC
     if (!accessDb->CreateIfNotExists())
      throw gcnew InvalidOperationException("Database was not created via ODBC.");
     
     // Extract vom embedded resource
     //if (!accessDb->CreateFromResourceIfNotExists())
     // throw gcnew InvalidOperationException("Database was not created from ressource.");

     //Console::WriteLine("Press <Enter> to Create Table.");
     //Console::ReadLine();

     auto sampleTable = gcnew SampleTable(accessDb);
     //sampleTable->ListData(); 
     sampleTable->CreateTable();
     sampleTable->InsertData(3);
     sampleTable->InsertData(3);
     sampleTable->InsertData(5);
     sampleTable->InsertData(8);
     sampleTable->InsertData(11);
     sampleTable->InsertData(13);
     //sampleTable->InsertData(8);
     //sampleTable->InsertData(123);
     sampleTable->ListData();
     sampleTable->expandTableDB();
     sampleTable->ListData();
     sampleTable->expandTableDB();
     sampleTable->ListData();
     sampleTable->expandTableDB();
     sampleTable->ListData();

     Console::WriteLine("Press <Enter> to exit program.");
     Console::ReadLine();
        return 0;
    }

    Donnerstag, 24. November 2016 13:49