Laden...

daten in acess db schreiben

Erstellt von zerberos vor 16 Jahren Letzter Beitrag vor 16 Jahren 3.204 Views
Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren
daten in acess db schreiben

Hallo,

Ich rufe Daten aus einer Oracle Datenbank ab (oracledataadapter) und speicher diese in einer DataTable zwischen.

Jetzt möchte ich den Inhalt dieser DataTable in eine Access Datenbank schreiben. Die Tabelle zum reinschreiben muss allerding jedesmal neu erstellt werden aus den Angaben der DataTabel. Da hab ich ja spaltennamen und Anzahl der Spalten drinnen.

Nur habe ich leider keine Idea wie ich diese Informationen abrufe bzw wie ich damit die Tabelle in der Access Datenbank erstelle

476 Beiträge seit 2004
vor 16 Jahren

hallo zerberos,

eine Tabelle in Access mit C# erstellen? Benutz' doch bitte die Forensuche, dann wärst du schon lange fündig geworden, so zum Beispiel hier:

Access-Tabelle von C# aus erstellen

Eine Beschreibung zum DataTable-Objekt findest du hier: DataTable-Objekte

-yellow

Selbst ein Weg von tausend Meilen beginnt mit einem Schritt (chinesisches Sprichwort).

Mein Blog: Yellow's Blog auf sqlgut.de

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

hab mich vielleicht etwas falsch ausgedrückt. die tabelle erstellen weiß ich wie 's geht und die connection geht uach.

nur ich weiß noch nicht wie ich die daten aus meiner datatable in meine access tabelle bekomme?

N
4.644 Beiträge seit 2004
vor 16 Jahren

Stichworte: OleDbCommand, OleDbDataAdapter

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

so bin jetzt mal was weiter gekommen

so sieht mein quelltext aus:


// Connections
 OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\db.mdb");
OracleConnection con2 = new OracleConnection("User ID=test;password=test; Data Source=test");

//Tabelle in Access erstellen
string tabellenname = "test";
string tabelle = "CREATE TABLE "+ tabellenname;

OleDbCommand cmd = new OleDbCommand(tabelle, con);
con.Open();
OleDbDataReader dr = cmd.ExecuteReader();

//Oracle auslesen
string commandString = Txt_SQL.Text;
OracleDataAdapter DataAdapter = new OracleDataAdapter(commandString, con2);
DataTable dt = new DataTable();
DataAdapter.Fill(dt);
DataSet ds = new DataSet();
DataAdapter.Fill(ds);

//Access db füllen
string sql2 = "SELECT * from " + tabellenname;
OleDbDataAdapter dadapter = new OleDbDataAdapter(sql2,con);
dadapter.Update(ds, tabellenname); 

dr.Close();
con.Close();

beim update fliegt der mit folgender Meldung raus:

Aktualisieren: TableMapping['test'] oder DataTable 'test' kann nicht gefunden werden.

was ist falsch?

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

keiner?

ich denke das der update befehl falsch ist den ich verwende. Ich will ja mit der abgefragten Tabellenstruktur die im OracleDataAdapter steht eine neue Tabelle in der Access Datenbank erstellen.

Weiß keiner hier wie das geht? ich bin echt am verzweifeln gerade

J
3.331 Beiträge seit 2006
vor 16 Jahren

Original von zerberos
Ich will ja mit der abgefragten Tabellenstruktur die im OracleDataAdapter steht eine neue Tabelle in der Access Datenbank erstellen.

Dann ist zwangsläufig cmd.ExecuteReader() falsch, wie die einfache Übersetzung "Ausführen zum Lesen" zeigt und auch die :rtfm: erläutert.

Du musst dafür die Variante cmd.ExecuteNonQuery() verwenden. Jürgen

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

Original von juetho

Original von zerberos
Ich will ja mit der abgefragten Tabellenstruktur die im OracleDataAdapter steht eine neue Tabelle in der Access Datenbank erstellen.
Dann ist zwangsläufig cmd.ExecuteReader() falsch, wie die einfache Übersetzung "Ausführen zum Lesen" zeigt und auch die :rtfm: erläutert.

Du musst dafür die Variante cmd.ExecuteNonQuery() verwenden. Jürgen

ok hab ich gemacht. das ändert trotzdem nichts an meinen problem. der erstellt mir in der datenbank eine leere tabelle ohne feldnamen

möchte aber das der mir eine tabelle erstellt mit den feldnamen die ich aus der oracle datenbank abfrage. also die ich dataset (oder datatable?) stehen

J
3.331 Beiträge seit 2006
vor 16 Jahren

Original von zerberos
der erstellt mir in der datenbank eine leere tabelle ohne feldnamen

möchte aber das der mir eine tabelle erstellt mit den feldnamen ...

So hast Du Deinen DbCommand festgelegt:

string tabelle = "CREATE TABLE "+ tabellenname;

Das sagt für mich eindeutig: Du willst eine Tabelle ohne Felder haben. Also wird der Befehl korrekt ausgeführt.

Woher sollen zunächst der DbCommand und anschließend Access wissen, welche Felder hinzugefügt werden sollen? Du musst an dieser Stelle wirklich einen kompletten CREATE-Befehl erstellen (teilweise in Pseudocode):

StringBuilder sb = new StringBuilder();
sb.Append(tabelle);
sb.Append("(");
foreach(DataColumn field in dt.Columns) {
    sb.AppendFormat("  {0} {1},", DatenTyp.ToString(), field.ColumnName);
}
sb.Append(")");
OleDbCommand cmd = new OleDbCommand(sb.ToString(), con);

Gruß Jürgen

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

ok. bin soweit durchgestiegen glaub ich.

nur mit DatenTyp.ToString() komme ich nicht klar. Was muss ich für Datentyp schreiben. das kennt der ja nicht. oder muss ich einfach nur ne variable datentyp definieren? das ist aber nicht so denke ich

danke!

J
3.331 Beiträge seit 2006
vor 16 Jahren

Original von zerberos
nur mit DatenTyp.ToString() komme ich nicht klar. Was muss ich für Datentyp schreiben. das kennt der ja nicht. oder muss ich einfach nur ne variable datentyp definieren? das ist aber nicht so denke ich

Ich hatte ja von "Pseudocode" gesprochen.

An dieser Stelle musst Du dafür sorgen, dass der Wert von field.DataType korrekt in einen string umgesetzt wird, sodass Dein DBMS (d.h. das Access-SQL) ihn beim CREATE TABLE versteht.

Aber das musst Du schon selbst erledigen anhand der "Quellstruktur", die Du von Oracle bekommst. Jürgen

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

also funktioniert noch nicht ganz.

wenn ich mir ankucke was in dem comman cmd steht. da steht folgendes drinnen:
CREATE TABLE test_tbl( System.String tbl_wert_1, System.String tbl_wert_2, System.String tbl_wert_3, System.Decimal tbl_wert_4, System.Decimal tbl_wert_4,)

bei

cmd.ExecuteNonQuery();

fliegt der dann mit folgender Meldung raus:

Syntaxfehler in Felddefinition.

mein ganzer code sieht so aus:


OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\db.mdb");

            string tabellenname = "testtabelle";

            OracleConnection con2 = new OracleConnection("User ID=test;password=test; Data Source=test");
            string commandString = Txt_SQL.Text;
            OracleDataAdapter DataAdapter = new OracleDataAdapter(commandString, con2);
            DataTable dt = new DataTable();
            DataAdapter.Fill(dt);

            StringBuilder sb = new StringBuilder();
            sb.Append("CREATE TABLE ");
            sb.Append(tabellenname);
            sb.Append("(");
            foreach (DataColumn field in dt.Columns)
            {
                sb.AppendFormat("  {0} {1},", field.DataType.ToString(), field.ColumnName);
            }
            sb.Append(")");
            OleDbCommand cmd = new OleDbCommand(sb.ToString(), con);
            con.Open();
            cmd.ExecuteNonQuery();
                        
          
            con.Close();
J
3.331 Beiträge seit 2006
vor 16 Jahren

Original von zerberos
wenn ich mir ankucke was in dem comman cmd steht. da steht folgendes drinnen:
CREATE TABLE test_tbl( System.String tbl_wert_1, System.String tbl_wert_2, System.String tbl_wert_3, System.Decimal tbl_wert_4, System.Decimal tbl_wert_4,)

bei

cmd.ExecuteNonQuery();  

fliegt der dann mit folgender Meldung raus:

Syntaxfehler in Felddefinition.

Ich hatte oben genau beschrieben, worauf Du achten musst:

... field.DataType korrekt in einen string umgesetzt wird, sodass Dein DBMS (d.h. das Access-SQL) ihn beim CREATE TABLE versteht.

Schau doch selbst genau hin: *Hinter dem letzten Feld steht noch ein Komma; das ist für SQL der Hinweis, dass noch weitere Angaben folgen; diese fehlen, also knallt es. *Unter SQL gibt es die Datentypen "System.String" oder "System.Decimal" mit 100% Sicherheit nicht (und ich kann mir nicht vorstellen, dass der OleDbProvider dies innerhalb des CommandText anpasst). Du musst dafür sorgen, dass dort etwas wie varchar(50) oder decimal(10,2) steht (oder wie auch immer es für Deine Tabelle und Access konkret und korrekt heißen muss).

Jürgen

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

string createbefehl = sb.Replace(",)", ")").ToString();

so hab ich jetzt das Problem mit dem letzten komma gelöst.

Aber wie ich das System.String umsetze hab ich noch keine ahnung. Ich könnte das auch alles mit replace ersetzen. Nur dann muss ich ja für jeden möglichen typ ein replace schreiben.

Gibt es da ne besser lösung?

J
3.331 Beiträge seit 2006
vor 16 Jahren

Aber wie ich das System.String umsetze hab ich noch keine ahnung. ... für jeden möglichen typ ... Gibt es da ne besser lösung?

Aber sicher doch:

private string DataTypeToString(Type fieldType) {
    string Result = String.Empty;
    if (fieldType == typeof(int))
        Result = "integer";
    else if (fieldType == typeof(DateTime))
        Result = "DATE";          //  nur mal so als Vermutung
    else if (fieldType == typeof(string)) {
        //  jetzt wird's komplizierter, weil SQL die Feldlänge benötigt
    } else if ... usw.
    return Result;
}

Wie gesagt: Jedem NET-Datentyp muss der Access-Datentyp in der korrekten Schreibweise zugewiesen werden.

In manchen Fällen könnte es kürzer gehen, wenn die SQL-Schreibweise mit fieldType.ToString() übereinstimmt; aber das dürfte der Ausnahmefall sein.

Ärgerlich: DbType (also auch OleDbType usw.) sind Enumerationen, die grundlegenden NET-Datentypen dagegen nicht. Mir ist noch kein Verfahren über den Weg gelaufen, von einem Type direkt zu einem DbType oder der exakten Schreibweise zu kommen.

Jürgen

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

ok hab es erstmal geschafft mir eine tabelle mit der struktur zu erstellen

kann mir einer sagen wie ich meine Daten da jetzt reinbekomme. Hab das mit Update versucht. Das klappt aber irgendwie nicht...

mein momentaner code:


            OracleConnection con2 = new OracleConnection("User ID=test;password=test; Data Source=test");
            string commandString = Txt_SQL.Text;
            OracleDataAdapter DataAdapter = new OracleDataAdapter(commandString, con2);
            DataTable dt = new DataTable();
            DataAdapter.Fill(dt);
            DataSet ds = new DataSet();
            DataAdapter.Fill(ds);

        
            OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\db.mdb");
            string tabellenname = "test_table";
            OleDbDataAdapter dadapter = new OleDbDataAdapter("Insert into "+tabellenname,con);

            StringBuilder sb = new StringBuilder();
            sb.Append("CREATE TABLE ");
            sb.Append(tabellenname);
            sb.Append("(");
            foreach (DataColumn field in dt.Columns)
            {
                sb.AppendFormat("  {0} {1},", field.ColumnName, field.DataType.ToString());
            }
            sb.Append(")");
            sb.Replace(",)", ")");
            sb.Replace("System.", "");
         
            OleDbCommand cmd = new OleDbCommand(sb.ToString(), con);                     
            con.Open();
            cmd.ExecuteNonQuery();

            dadapter.Update(ds, tabellenname);
                      
            con.Close();
J
3.331 Beiträge seit 2006
vor 16 Jahren

Original von zerberos

string tabellenname = "test_table";  
OleDbDataAdapter dadapter = new OleDbDataAdapter("Insert into "+tabellenname,con);  
  
dadapter.Update(ds, tabellenname);  

Hier gilt im Prinzip das Gleiche wie beim Erstellen der Tabelle: Es wird ein vollständiger SQL-Befehl benötigt; aber "Insert into test_table" ist das doch nicht!

Du benötigst:*ein **Commit **nach dem Erzeugen der Tabelle; andernfalls ist nicht sicher, dass die Access-DB die Tabelle schon vollständig erzeugt hat und kennt *einen vollständigen DbCommand, der als InsertCommand beim DataAdapter registriert wird *alle Datensätze der DataTable müssen als RowState.Added markiert werden (andernfalls erkennt der Update-Befehl nicht, welche Datensätze in die Datenbank übertragen werden sollen)

Es ginge auch über einen einfachen DbCommand (ohne DataAdapter), der dann per Schleife mit ExecuteNonQuery alle Datensätze aus Table.Rows speichert. (Ich vermute, das ginge schneller, aber wenn die Daten sowieso schon im DataSet stehen...)

Bitte beachte, dass Du bei jedem DbCommand unbedingt **DbParameter **verwendest.

Jürgen

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

wie setze ich den alle datensätze in der datatabel auf rowstate.added ??

hab mal versucht den Insert befehl zu erstellen

OleDbCommandBuilder incmd = new OleDbCommandBuilder();
incmd.Append("Insert into");
incmd.Append(tabellenname);
foreach (DataRow row in dt)
{
??????
}

aber komme da nicht weiter

J
3.331 Beiträge seit 2006
vor 16 Jahren

Also ich verzweifle langsam an Deinem Willen, konsequent und mit Überlegung vorzugehen. Du hast ja schon ganz am Anfang den Hinweis auf das OpenBook mit Kap. 26 bekommen...

Original von zerberos
wie setze ich den alle datensätze in der datatabel auf rowstate.added??

Genz einfach:

// row ist ein Element von dt.Rows, nicht von dt!!!
            foreach (DataRow row in dt.Rows)
            {
            //  wie ich geschrieben habe: es muss RowState.Added eingetragen werden
            //  kannst Du das wirklich nicht übertragen???
            }

hab mal versucht den Insert befehl zu erstellen

OleDbCommandBuilder incmd = new OleDbCommandBuilder();  
            incmd.Append("Insert into");  
            incmd.Append(tabellenname);  

aber komme da nicht weiter

Was soll der Blödsinn incmd.Append? Hast Du jemals die :rtfm: Doku benutzt? Was hat der OleDbCommandBuilder mit Append zu tun? Wenn Du den DbCommandBuilder benutzen willst, dann richtig, wie es in der Doku beschrieben wird:

Zum Generieren von INSERT-Anweisungen, UPDATE-Anweisungen und DELETE-Anweisungen verwendet der OleDbCommandBuilder die SelectCommand-Eigenschaft...

Ich hatte schon vorgeschlagen:

einen vollständigen DbCommand, der als InsertCommand beim DataAdapter registriert wird

In der :rtfm: gibt es unter **DbDataAdapter.InsertCommand-Eigenschaft **genau das passende Beispiel!

Jürgen

PS. Ich bin sauer, wenn immer wieder ähnliche Fehler auftreten und Hinweise nicht oder falsch zur "Lösung" verwendet werden. Ich habe keine Lust mehr zu weiteren Antworten.

Z
zerberos Themenstarter:in
520 Beiträge seit 2007
vor 16 Jahren

ok danke dir. bin jetzt etwas weiter.

habe versucht mir den insert befehl dynaamisch erstellen zu lassen (statisch geht ja nicht da die felder ja immer andere sein können)

bekomme jetzt aber folgende Meldung:

Dynamische SQL-Generierung für den UpdateCommand wird nicht für einen SelectCommand unterstützt, der keine Schlüsselspalteninformationen zurückgibt.

ich denke das problem liegt darin da die von mir erstellte tabelle in der access datenbank keinen primärschlüssel enthält

was kann ich machen?


OracleConnection con2 = new OracleConnection("User ID=test;password=test; Data Source=testdata");
            string commandString = Txt_SQL.Text;
            OracleDataAdapter DataAdapter = new OracleDataAdapter(commandString, con2);
            DataTable dt = new DataTable();
            DataAdapter.Fill(dt);
            DataSet ds = new DataSet();
            DataAdapter.Fill(ds);

        
            OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\db.mdb");
            string tabellenname = "testtabelle";
            
            StringBuilder sb = new StringBuilder();
            sb.Append("CREATE TABLE ");
            sb.Append(tabellenname);
            sb.Append("(");
            foreach (DataColumn field in dt.Columns)
            {
                sb.AppendFormat("  {0} {1},", field.ColumnName, field.DataType.ToString());
            }
            sb.Append(")");
            sb.Replace(",)", ")");
            sb.Replace("System.", "");
         
            OleDbCommand cmd = new OleDbCommand(sb.ToString(), con);                     
            con.Open();
            cmd.ExecuteNonQuery();
           
            foreach(DataRow row in ds.Tables[0].Rows)
            {
                row.SetModified();
            }

            OleDbDataAdapter dadapter = new OleDbDataAdapter();
            dadapter.SelectCommand = new OleDbCommand("Select * from " + tabellenname, con);
            OleDbCommandBuilder custCB = new OleDbCommandBuilder(dadapter);
            dadapter.Update(ds);
            
                      
            con.Close();

die vorgeschlagene Funktion DbDataAdapter.InsertCommand-Eigenschaft hab ich mir angesehen. Aber wenn ich das richtig verstanden habe muss ich den update bzw insert befehl statisch festlegen. Und ich brauch ja was, was komplett dynamisch ist

1.274 Beiträge seit 2005
vor 16 Jahren

Verwende doch DAO oder ADOX für die Erstellung von Datenbanken.

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein