| |
ADO.NET / DatenbankenDataTable.Merge führt zu falschem Ergebnis | | | Autor: Achim 49 | Datum: 06.02.18 18:46 |
| Vorgabe: Access Datenbank mit einer Tabelle 'Pegel' mit 3 Feldern 'Datum' [DateTime], 'Ort' [String 50] und 'Hoehe' [Integer]; Primärschlüssel auf 'Datum' und 'Ort'.
Ziel: Mit Daten aus verarbeiteten .CSV-Dateien vereinen (nur hinzufügen; geänderte Daten nicht übernehmen).
Realisierung: Tabelle 'Pegel' clonen; .CSV-Daten zu Clone-Tabelle hinzufügen; beide Tabellen 'Mergen'.
Mit 'table.GetChanges(DataRowState.Added)' sollten die neu hinzugefügten Datensätze zurückgegeben werden. Statt dessen erhalte ich diese Datensätze + die bereits vorher vorhandenen Datensätze über 'DT.GetChanges(DataRowState.Unchanged)' gelistet.
Dadurch werden auch keine Daten mit der Update-Funktion zurückgeschrieben.
Wer kann mir helfen?
Private Dateiname As String = _
"c:\users\achim\desktop\rheinpegel\Test#1_W-N.csv"
Private DbName As String = "c:\users\achim\desktop\rheinpegel\db1.mdb"
Private Conn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data" _
& _
"Source=" & DbName)
Private DA As New OleDbDataAdapter("SELECT * FROM Pegel;", Conn)
Private CB As New OleDbCommandBuilder(DA)
Private DT As New DataTable
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
Conn.Open()
DA.Fill(DT)
Conn.Close()
DT.PrimaryKey = New DataColumn() {DT.Columns("Datum"), DT.Columns( _
"Ort")}
Grid1.DataSource = DT
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles _
btnStart.Click
Dim dt2 As DataTable = CSV2Table(DT.Clone)
DT.Merge(dt2, True)
'Nur zur Überprüfung des Ergebnisses:
Dim s As String = ""
Dim DTt As DataTable
DTt = DT.GetChanges(DataRowState.Unchanged) : If Not IsNothing(DTt) _
Then s += " Unv.: " & DTt.Rows.Count.ToString
DTt = DT.GetChanges(DataRowState.Added) : If Not IsNothing(DTt) Then s _
+= " Add.: " & DTt.Rows.Count.ToString
DTt = DT.GetChanges(DataRowState.Modified) : If Not IsNothing(DTt) Then _
s += " Mod.: " & DTt.Rows.Count.ToString
DTt = DT.GetChanges(DataRowState.Deleted) : If Not IsNothing(DTt) Then _
s += " Del.: " & DTt.Rows.Count.ToString
MsgBox(s,, "Merged")
Conn.Open()
Dim i As Integer = DA.Update(DT)
'Nur zur Überprüfung des Ergebnisses:
MsgBox(i,, "Zurückgeschrieben")
Conn.Close()
End Sub
Private Function CSV2Table(ByVal DT2 As DataTable) As DataTable
:
'In einer Schleife Datensätze (Anzahl > 3.000) einlesen
DT2.Rows.Add({dDateTime, sOrt, iPegel})
DT2.AcceptChanges()
CSV2Table = DT2
End Function | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Manfred X | Datum: 07.02.18 23:19 |
| Hallo!
Die Ausführung der Methode "AcceptChanges" setzt die RowState-
Eigenschaft aller Datensätze der Table auf "unchanged". | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Franki | Datum: 09.02.18 04:13 |
| Hallo,
du arbeitest ja mit einer Datenbank (mdb) Soweit so gut, aber dann verwendest du ein Select * im SQL Statement. Warum? Der Vorteil von SQL ist ja grade, dass man in er Lage ist schon dort festzulegen was für Daten man haben möchte. Stichwort: SQL = ... Where ... usw. Da kannst du doch schon auf nur die neuen Daten zugreifen...
Ich verstehe das seit Jahrzehnten nicht warum immer wieder Leute eine komplette Tabelle aus einer DB einlesen und dann erst im Grid ausfiltern wollen. SQL ist da viel mächtiger von den Möglichkeiten her und auch für die Anwendung ist es performanter nicht erst alles einzulesen und dann zu filtern. (Besonders dann wenn der Zugriff auf die DB über (langsames) Netzwerk erfolgt bzw. erfolten muss (DB im Internet z.B.)
Aber gut, ich muss nicht alles verstehen...
Gruß
Frank | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Achim 49 | Datum: 09.02.18 14:25 |
| Hallo Franki,
der Hintergrund der Vorgehensweise ist folgender: Ich will in unregelmäßigen Abständen größere Datenmengen übernehmen, die im .CSV-Format vorliegen und einen Zeitraum von einem Monat abdecken. Dabei ist der Aufbau der Datenzeilen leider unterschiedlich, weswegen jede Zeile individuell ausgewertet und die relevanten Daten entnommen werden müssen. Da die Übernahme nicht immer im exakt gleichen zeitlichen Abstand erfolgt kommt es regelmäßig vor, dass sich Datensätze zeitlich mit bereits früher erfassten überlappen. Daher die Vorgehensweise: Einlesen der (neuen) Daten, anschließend 'mergen' mit den vorhandenen und abspeichern. Die Ergebnismenge (also alte UND neue Daten) wird dann in der Anwendung weiter ausgewertet (hier nur symbolisch als DGV).
Ich hoffe, ich konnte mich einigermaßen verständlich ausdrücken.
Gruß
Achim | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Achim 49 | Datum: 09.02.18 14:41 |
| Hallo Manfred,
ich habe deine Info befolgt und das AcceptChanges entfernt. Und siehe da: es funktioniert!
Aber: Mir fehlt der Zusammenhang. Ich ist bekannt, dass die Methode die State-Eigenschaft auf Unchanged zurücksetzt. Aber ich habe AcceptChanges auf die 2. Tabelle (DT2) angewendet, in die ich die neuen Datensätze eingelesen habe. Erst danach Merge ich diese Tabelle in die erste Tabelle (DT) und erwarte als Ergebnis des Mergens, dass in der Tabelle (DT) für jeden Datensatz die RowStat-Eigenschaft auf einen adäquaten Wert gesetzt ist.
Wo also ist mein Denkfehler?
Gruß
Achim | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Manfred X | Datum: 09.02.18 15:29 |
| Es ist zu beachten, was sich die VB-Entwickler konzeptionell
für die Art der Verwendung der Merge-Methode überlegt haben - siehe z.B.
https://msdn.microsoft.com/de-de/library/wkk7s5zk(v=vs.110).aspx
So weit ich verstanden habe, wird das "Mergen" insbesondere zur Aktualisierung
von zuvor abgefragten und danach geänderten Zeilen eingesetzt - anhand des
Primärschlüssels unter Einbezug der RowState-Eigenschaft.
Die zusammengefasste Tabelle soll danach ein korrektes Datenbank-Update
ermöglichen. Dementsprechend wird die RowState-Eigenschaft der Sätze verarbeitet.
Das Zusammenfassen der Datenzeilen aus Tabellen unterschiedlicher Quellen
ist wohl eher als ein "nebensächlicher" Anwendungsfall einzuordnen.
Beitrag wurde zuletzt am 09.02.18 um 15:36:59 editiert. | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Manfred X | Datum: 09.02.18 15:48 |
| Hallo!
Datenbanken dienen dem geordneten Verwahren (relationaler,
normalisierter) Daten; Tabellenkalkulation der Aufbereitung
(aggregierter) Daten (Formeln, Diagramme, Sichten, ergänzende Texte usw.).
Kalkulations-Tabellen umfassen gewöhnlich nur wenige hundert
(aufbereitete) Datenzeilen. Es spricht nichts dagegen, solche
Quellen durch eine Anwendung komplett in den Hauptspeicher zu laden
und sie in-memory weiter zu bearbeiten.
Um Datensätze aus CSV-Dateien in einer Datenbank an eine Tabelle
anzuhängen, wird nur das Tabellenschema benötigt.
Es ist vor dem DB-Update sicher zu stellen, daß eindeutige Primärschlüssel
bei den CSV-Zeilen eingetragen sind. | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Franki | Datum: 10.02.18 03:48 |
| Hallo Achim,
grade dann wenn es sich um einen relativ seltenen Vorgang (monatlich) handelt und die Datenmenge groß ist, solltest du die entsprechenden Anpassungen einmalig beim Einlesen der neuen CSV Datei machen damit die bereinigten Daten in der DB stehen.
Du kannst dafür ja eine Wartung.exe erstellen, ein Unterprogramm oder was auch immer. Deiner Phantasie sind da keine Grenzen gesetzt.
Aber wie ManfredX ja schon schrieb ist es auch von Bedeutung um welche Datenmenge bzw. Anzahl Datensätze es sich handelt. Gib doch mal eine etwas genauere Angabe wie groß die jeweilige CSV Datei ist und wie viele Datensätze die DB enthält.
Es macht keinen Sinn alte und neu Daten erst in der Anwendung auszuwerten wenn diese nur monatlich verändert werden oder die Datenmenge sehr groß ist, bzw. die neuen Daten sehr gering im Verhältnis zur vorhandenen Datenmenge in der DB sind. Wenn eine einmalige Anpassung notwendig ist für neue Datensätze, dann solltest du sie auch nur genau einmalig durchführen und nicht bei jedem Start der Anwendung.
Gruß
Frank | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Franki | Datum: 10.02.18 03:58 |
| Hallo,
du hast zu 100% recht, aber das ist halt "gefährliches Halbwissen" warum gewisse Leute so etwas machen.
Und du hast noch ein Argument vergessen:
Excel ist in allen preiswerten / kostenlosen Office Versionen enthalten, Access kostet zurätzliches Geld, also nehmen wir Excel.
Was die Leute halt nicht wissen, ist die Tatsache, dass sie wie in diesem Beispiel gar kein Acces brauchen um auf eine *.mdb zugreifen zu können. Die konnte man schon mit VB-Classic per Code erstellen und auch bis heute kann man daraus per ADO drauf zugreifen. Sowohl unter VBClassic, heutigem VBA als auch .NET ist das problemlos möglich.
Aber gut Excel ist bunter, schöner usw. Es bietet erweiterte Möglichkeiten wie z.B. Charts optisch ansprechend anzeigen zu können usw.
Aber den Aufwand bei einer eigenen Anwendung das auch machen zu könne scheuen viel, auch die Tatsache, dass es aus eigenen Programmen durchaus schon immer möglich war per Automation auch auf andere Programme wie Excel zugreifen zu können ist denen zu viel Aufwand gewesen.
Aber gut, jeder wie er mag, für eine private Anwendung ist das akzeptabel...
Gruß
Frank | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: effeff | Datum: 10.02.18 15:20 |
| Woran erkennst Du, dass ein Datensatz neuer ist als der Rest? Anhand des Feldes "Datum", welches Du als PrimaryKey definiert hast? Ist das nur ein Datumsfeld oder ein Date_/Time-Feld?
Ich würde schlicht die CSV durchgehen, sofern eine Zeile ein zu übernehmender Datensatz ist, gucken, ob in der Datenbank bereits ein Eintrag vorhanden ist und wenn nicht, diesen hinzufügen.
Danach würde ich die Datenbank zur Auswertung abfragen.
EALA FREYA FRESENA | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Achim 49 | Datum: 10.02.18 17:23 |
| Hallo zusammen,
zur Datenherkunft: Ich habe keinen Einfluss auf das Datenformat. Es wird im .CSV-Format geliefert. Es enthält die Daten für die letzten 30 Tage (~15.000 Zeilen). Die Struktur der Zeilen variiert. Deshalb muss Zeile für Zeile individuell ausgewertet werden und in ein Clone (DT2) der Muttertabelle (DT) geladen werden (angedeutet in Private Function CSV2Table | DT2.Rows.Add). Dieser Clone wird dann mit der Muttertabelle gemergt. Diese Vorgehensweise ist von der Ausführung schneller als beim dem von Effeff vorgeschlagenen Weg.
Das Datumsfeld ist immer vom Typ DateTime und wird auch so bedient.
Damit möchte ich gerne dieses Kapitel abschließen und noch mal auf den Kern meiner Frage zurück kommen: Ich ging davon aus, dass beim Mergen die RowState-Eigenschaften gesetzt werden. Wieso hat das AcceptChanges auf den Clone (DT2) VOR dem Mergen Einfluss auf die RowState-Eigenschaften in der Muttertabelle (DT)?
Gruß
Achim
Beitrag wurde zuletzt am 10.02.18 um 17:25:37 editiert. | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Manfred X | Datum: 10.02.18 18:04 |
| Hallo!
Der aktuelle Wert der Rowstate-Eigenschaft eines Datensatzes
entscheidet darüber, was beim Update der Datenbank geschehen soll.
Die aus der CSV geladenen Sätze werden als "Added" markiert.
Wenn Du "AcceptChanges" ausführst, wird die RowState-Eigenschaft zu
"unchanged", d.h. die Sätze werden beim Update nicht in die Datenbank
geschrieben.
Wenn Du diese Zeilen zuvor mit noch nicht vorhandenen Schlüsselwerten
versiehst, werden sie beim Mergen angehängt. Sie bleiben dabei "unchanged".
Ist eigentlich logisch - sie sind nicht geändert worden, sondern nur angehängt.
Dein Denkfehler liegt vermutlich darin, daß die Tabelle beim Mergen
verlängert wird durch neue Sätze. Das hat aber mit dem update-relevanten
Zustand dieser Sätze nichts zu tun.
Ein anderes Verhalten ergibt sich, wenn die geladenen Sätze anhand
des Primärschlüsselwertes bereits vorhandene Sätze in der Zieltabelle ersetzen.
In dem Fall wird die "RowState"-Eigenschaft der überschriebenen Sätze zu "modified".
Auch das ist logisch korrekt. Der Inhalt der Sätze ist durch das Mergen
geändert worden. | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Manfred X | Datum: 10.02.18 18:23 |
| Hallo!
Selbstverständlich ist mir klar, daß Du das alles weißt.
Ich war mir nicht sicher, ob das auch auf alle Mitlesenden zutrifft.
Wenn man eine überschaubare Datenmenge (normalisiert) verwalten möchte,
kann man - als Flatfile-Enthusiast oder wegen der Einfachheit -
auf eine Datenbank verzichten und statt dessen die XMLRead/Write-Methoden
des Dataset benutzen (mehrere Tabellen mit Spaltenschema und Relationen
werden dabei in einer XML-Datei zusammengefasst).
Selbstverständlich ist mir klar, daß Du das weißt.
Ich war mir wieder nicht sicher, ob das auch auf alle Mitlesenden zutrifft. | |
Re: DataTable.Merge führt zu falschem Ergebnis | | | Autor: Achim 49 | Datum: 11.02.18 09:30 |
| Hallo Manfred,
Dank deiner Erklärungen habe ich meinen Denkfehler gefunden und kann jetzt das Verhalten der Merge-Methode genauer nachvollziehen.
Vielen Dank euch Alle für eure Unterstützung!
Viele Grüße und noch ein paar närrische Tage
Achim | |
| Sie sind nicht angemeldet! Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.
Einloggen | Neu registrieren |
|
|
Neu! sevCoolbar 3.0
Professionelle Toolbars im modernen Design!
Mit sevCoolbar erstellen Sie in wenigen Minuten ansprechende und moderne Toolbars und passen diese optimal an das Layout Ihrer Anwendung an (inkl. große Symbolbibliothek) - für VB und MS-Access Weitere InfosTipp des Monats Access-Tools Vol.1
Über 400 MByte Inhalt
Mehr als 250 Access-Beispiele, 25 Add-Ins und ActiveX-Komponenten, 16 VB-Projekt inkl. Source, mehr als 320 Tipps & Tricks für Access und VB
Nur 24,95 EURWeitere Infos
|