Löschen per SQL in Access-DB funktioniert nicht richtig

  • VB.NET

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.

    Löschen per SQL in Access-DB funktioniert nicht richtig

    Hallo zusammen,

    ich habe mir in VB ein kleines Corona Kontakttagebuch gebaut.
    Die ermittelten Kontakte werden in einer ACCDB gesichert.

    Beim Verlassen der Anwendung möchte ich nun die Kontakthistorie der letzten 14-Tage löschen automatisch löschen lassen.

    Irgendwas mach ich beim Löschen aber falsch und ich komm grad nicht drauf, woran es liegt - vielleicht könnt ihr mir weiterhelfen.

    Wenn ich in der Accessspalte "DATUM" die Werte 12.11.2020
    11.11.2020
    10.11.2020
    09.11.2020
    08.11.2020
    07.11.2020
    06.11.2020
    05.11.2020
    04.11.2020
    03.11.2020
    02.11.2020
    01.11.2020
    31.10.2020
    30.10.2020
    29.10.2020

    28.10.2020
    27.10.2020
    26.10.2020
    25.10.2020
    24.10.2020
    23.10.2020

    eintrage, werden nur die roten Werte gelöscht.
    Ich hätte aber vorausgesetzt, dass alles seit dem 28.10.2020 (grün) gelöscht wird, da älter als 14 Tage.

    VB.NET-Quellcode

    1. Function GetSQLDate(dtDate As Date) As String
    2. 'GetSQLDate = Format(dtDate, "\#dd\.MM\.yyyy\#")
    3. GetSQLDate = Format(dtDate, "\#yyyy-MM-dd\#")
    4. 'GetSQLDate = Format(dtDate, "\#dd-MM-yyyy\#")
    5. End Function
    6. Sub KontakteLoeschen()
    7. 'Erstellen des SQL-Befehls mit Parameter
    8. Dim strSQLString As String = "DELETE FROM " & strTabellenName &
    9. " WHERE DATUM >= " & GetSQLDate((DateAdd(DateInterval.Day, -14, Date.Now.Date)))
    10. Debug.Print(strSQLString)
    11. 'Aufbau der benötigten Variablen für die Connection
    12. Dim con As New OleDb.OleDbConnection(strConnectionsString)
    13. Dim cmd As New OleDb.OleDbCommand(strSQLString, con)
    14. 'Öffnen der Verbindung
    15. con.Open()
    16. Try
    17. 'Ausführen des SQL-Befehls
    18. cmd.ExecuteNonQuery()
    19. Catch ex As Exception
    20. MessageBox.Show(text:=ex.Message,
    21. caption:="Fehler 216: Fehler bei der Übermittlung der Daten",
    22. buttons:=MessageBoxButtons.OK,
    23. icon:=MessageBoxIcon.Warning)
    24. End Try
    25. 'schließen der Verbindung
    26. con.Close()
    27. End Sub


    Habt ihr vielleicht eine Idee, woran das liegen kann?
    Vielen Dank im Voraus.
    Moin,


    arbeite bitte mit DbParametern. Außerdem schmeiß den Microsoft.VisualBasic Verweis raus.

    Ohne DbParameter ist deine Anwendung offen für SqlInjections und eben solche Formatierungsfehler, gerade beim Datum.
    Sobald ein Wert mit Parametern an den SqlCommand übergeben wird, formatiert der SqlCommand sich die Werte so wie er sie braucht.

    Ist DATUM wirklich ein reines Datum oder ein DateTime Feld?

    Hier mal ein Beispiel, wie ich das lösen würde.

    VB.NET-Quellcode

    1. Private Shared ReadOnly Property DeleteCommand As String
    2. Get
    3. Return "DELETE FROM " & "TABELLE" & " WHERE " & "DATUM" & "<=" & "@" & "DATUM"
    4. End Get
    5. End Property
    6. Public Shared Function Delete(MaxAge As Integer) As Boolean
    7. Try
    8. Using Cmd As New OleDbCommand(DeleteCommand, New OleDbConnection("CONNECTIONSTRING"))
    9. With Cmd
    10. With .Connection
    11. If Not .State = ConnectionState.Open Then .Open()
    12. End With
    13. With .Parameters
    14. .AddWithValue("@" & "DATUM", Date.Now.AddDays(-14))
    15. End With
    16. .ExecuteNonQuery()
    17. With .Connection
    18. If .State = ConnectionState.Open Then .Close()
    19. End With
    20. End With
    21. End Using
    22. Return True
    23. Catch ex As Exception
    24. MessageBox.Show(ex.Message, String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Error)
    25. Return False
    26. End Try
    27. End Function
    Hallo BlueLagoonX,

    vielen Dank für deine schnelle Rückmeldung.

    Den DB Parameter habe ich bisher beim Insert verwendet - das merk ich mir für künftig auch für andere SQL-Statements.

    Die Spalte in der ACCDB habe ich als Datum/Uhrzeit angelegt und im Format "Datum, kurz" ausgewählt.
    Übergeben tu ich die Werte aus meiner Anwendung mit

    VB.NET-Quellcode

    1. cmd.Parameters.Add("@DATUM", OleDbType.Date).Value = frm_Kontakttagebuch.dtp_Datum.Value.ToShortDateString


    Ich habe deine Lösung eingebaut.
    Beim Löschen der Daten bleibt er nun im ExecuteNonQuery hängen und wirft einen "Datentypenkonflikt in Kriterienausdruck" raus. :-/

    Hättest du mir hier bitte auch nochmal deine Hilfe?

    Sorry, und was meintest du mit
    ​Außerdem schmeiß den Microsoft.VisualBasic Verweis raus.

    EveretEichhörnchen schrieb:

    Sorry, und was meintest du mit
    Außerdem schmeiß den Microsoft.VisualBasic Verweis raus.
    Dabei geht es um diese Anfänger-Probleme: Visual Studio - Empfohlene Einstellungen
    Also es sind üblicherweise die dort behandelten zwei üblen Grundeinstellungen, die zu korrigieren sind:
    1. Option Strict Off
    2. Microsoft.VisualBasic


    Zum Type-Mismatch kann ich nur vermuten:
    nee - ich empfehle erstmal: Mach doch einfach mal wie BlueLagon gesagt hat. Nämlich nicht:

    VB.NET-Quellcode

    1. cmd.Parameters.Add("@DATUM", OleDbType.Date).Value = frm_Kontakttagebuch.dtp_Datum.Value.ToShortDateString

    sondern (schau nochmal hin):

    VB.NET-Quellcode

    1. With cmd.Parameters
    2. .AddWithValue("@" & "DATUM", Date.Now.AddDays(-14))
    3. End With

    Ich vermute nämlich, dass es an dieser Stelle die Datentypen sind die den Unterschied ausmachen.
    Deins: frm_Kontakttagebuch.dtp_Datum.Value.ToShortDateString ist ein String - steht da ja: .ToString()
    Seins: Date.Now.AddDays(-14) ist ein DateTime.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Wenn es nur ein Datumsfeld ist, versuch mal

    VB.NET-Quellcode

    1. .AddWithValue("@" & "DATUM", Date.Now.AddDays(-14).Date)


    Dadurch wird nur der Date-Wert des Date(Time) Objekts übergeben, ohne die Uhrzeit.

    VB.NET-Quellcode

    1. cmd.Parameters.Add("@DATUM", OleDbType.Date).Value = frm_Kontakttagebuch.dtp_Datum.Value.ToShortDateString


    Verwende ich gar nicht, da man hierbei durch den OleDbType den Typ des Feldes explizit angeben muss. Bei meinem Beispiel sucht sich der OledbCommand die passenden Datentypen selber. Wenn es dann knallt, liegt es am falschen Datentyp welcher in die Datenbank geschrieben wird.
    Hallo ihr beiden,

    vielen Dank für eure Hilfe und Geduld!

    kurz vorweg:

    Microsoft.VisualBasic habe ich bisher noch nie importiert, daher konnte ich damit auch erstmal nichts anfangen.

    Bei meinen Projecten habe ich immer Option Strict On und Option Explicit On im Code integriert.
    Das habe ich mir gleich von Anfang an so "angezwungen", hierauf zu achten.



    Die Übertragung in meine ACCDB habe ich jetzt angepasst:

    VB.NET-Quellcode

    1. Sub KontaktSpeichern()
    2. 'Erstellen des SQL-Befehls mit Parameter
    3. Dim strSQLString As String = "INSERT INTO " & strTabellenName &
    4. "(DATUM, ORT, ZEIT, KONTAKTPERSON, DAUER, KONTAKTART, SCHUTZMAßNAHMEN, KONTAKTDATEN)
    5. VALUES
    6. (@DATUM, @ORT, @ZEIT, @KONTAKTPERSON, @DAUER, @KONTAKTART, @SCHUTZMAßNAHMEN, @KONTAKTDATEN)"
    7. 'Aufbau der benötigten Variablen für die Connection
    8. Dim con As New OleDb.OleDbConnection(strConnectionsString)
    9. Dim cmd As New OleDb.OleDbCommand(strSQLString, con)
    10. 'Öffnen der Verbindung
    11. con.Open()
    12. Try
    13. 'Befüllen der SQL-Parameter
    14. With cmd
    15. With .Parameters
    16. '.Add("@DATUM", OleDbType.Date).Value = frm_Kontakttagebuch.dtp_Datum.Value
    17. '.Add("@ORT", OleDbType.VarChar).Value = frm_Kontakttagebuch.cbo_Ort.Text
    18. '.Add("@ZEIT", OleDbType.VarChar).Value = frm_Kontakttagebuch.dtp_Zeit.Value.ToShortTimeString
    19. '.Add("@KONTAKTPERSON", OleDbType.VarChar).Value = frm_Kontakttagebuch.cbo_Kontaktperson.Text
    20. '.Add("@DAUER", OleDbType.VarChar).Value = frm_Kontakttagebuch.dtp_Dauer.Value.ToShortTimeString
    21. '.Add("@KONTAKTART", OleDbType.VarChar).Value = frm_Kontakttagebuch.txt_ArtDesKontakts.Text
    22. '.Add("@SCHUTZMAßNAHMEN", OleDbType.VarChar).Value = frm_Kontakttagebuch.txt_Schutzmaßnahmen.Text
    23. '.Add("@KONTAKTDATEN", OleDbType.VarChar).Value = frm_Kontakttagebuch.txt_Kontaktdaten.Text
    24. .AddWithValue("@" & "DATUM", frm_Kontakttagebuch.dtp_Datum.Value)
    25. .AddWithValue("@" & "ORT", frm_Kontakttagebuch.cbo_Ort.Text)
    26. .AddWithValue("@" & "ZEIT", frm_Kontakttagebuch.dtp_Zeit.Value)
    27. .AddWithValue("@" & "KONTAKTPERSON", frm_Kontakttagebuch.cbo_Kontaktperson.Text)
    28. .AddWithValue("@" & "DAUER", frm_Kontakttagebuch.dtp_Dauer.Value)
    29. .AddWithValue("@" & "KONTAKTART", frm_Kontakttagebuch.txt_ArtDesKontakts.Text)
    30. .AddWithValue("@" & "SCHUTZMAßNAHMEN", frm_Kontakttagebuch.txt_Schutzmaßnahmen.Text)
    31. .AddWithValue("@" & "KONTAKTDATEN", frm_Kontakttagebuch.txt_Kontaktdaten.Text)
    32. End With
    33. End With
    34. 'Ausführen des SQL-Befehls
    35. cmd.ExecuteNonQuery()
    36. Catch ex As Exception
    37. MessageBox.Show(text:=ex.Message,
    38. caption:="Fehler 134: Fehler bei der Übermittlung der Daten",
    39. buttons:=MessageBoxButtons.OK,
    40. icon:=MessageBoxIcon.Warning)
    41. End Try
    42. 'schließen der Verbindung
    43. con.Close()
    44. End Sub


    Da ich in der ACCDB die Spalte DATUM als Datum/Uhrzeit deklariert hatte, hat er beim Eintragen den gleichen Fehler (Datentypenkonflikt in Kriterienausdruck) gebracht.

    Wenn ich die Spalte auf Text ändere kommt der Fehler nicht mehr, allerdings überträgt er dann die DateTime.
    Vom Prinzip hätte ich hier aber gesagt, dass das nicht passt.

    Den DateTimePicker "dtp_Datum" initiiere ich beim Laden der Maske mit

    VB.NET-Quellcode

    1. 'DatePicker Kontaktdatum
    2. With dtp_Datum
    3. .Format = DateTimePickerFormat.Custom
    4. .CustomFormat = "dd.MM.yyyy"
    5. End With

    EveretEichhörnchen schrieb:

    Microsoft.VisualBasic habe ich bisher noch nie importiert
    Genau das ist das Problem damit.
    Dieser Namespace wird standardmässig general-importiert.
    Also du musst aktiv werden, um ihn loszuwerden - siehe Tutorial.
    Dass du ihn am Hacken hast sieht man zb daran, dass du die Format-Funktion verwendest. Im "richtigen" VB.Net gibts die nicht - da verwendet man System.String.Format(), und das ist was anderes.



    Zum TypeMismatch-Problem: Wie du das dtp_Datum-Format einstellst ist egal - der Datentyp der Datetimepicker-Property .Value ist und bleibt DateTime.
    Allerdings sehen wir jetzt mehrere Verwendungen von DatetimePickern.



    Huch - das ist ja eine ganz andere methode, von der du auf einmal sprichst!

    Ist denn das in Post#1 geschilderte Problem nun gelöst? Das bitte erst eindeutig beantworten, bevor wir uns auf iwas anneres stürzen.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Guten Morgen,

    ErfinderDesRades schrieb:

    Genau das ist das Problem damit.


    Ok, jetzt hab ich es verstanden - ich kümmere mich drum.
    Ich hab den Teil mit dem Format es im Netz gefunden und für meine Zwecke angepasst.
    Von diesem Namespace hatte bisher nichts gewusst - jetzt weiß ich es.




    Ist denn das in Post#1 geschilderte Problem nun gelöst? Das bitte erst eindeutig beantworten, bevor wir uns auf iwas anneres stürzen.


    Ja, das Thema ist behoben, es werden in der ACCDB nur noch die gewünschten 14-Tage beibehalten, der Rest wird sauber gelöscht.
    @BlueLagoonX: Vielen Dank!

    Huch - das ist ja eine ganz andere methode, von der du auf einmal sprichst!

    Sorry, ich hatte eure Hinweise zum "AddWithValue" gleich auch auf den Einleseprozess angepasst.
    Aber irgendwo dort knallt es dann wieder.

    Ich hab mal die Entwurfsansicht der ACCDB beigefügt.
    Den Felddatentyp habe ich jetzt mal bei den drei DatePickern auf Datum/Uhrzeit eingestellt, weil es bei "kurzer Text" mir die DateTime mitgibt.

    EveretEichhörnchen schrieb:

    den gleichen Fehler (Datentypenkonflikt in Kriterienausdruck)
    ist das wirklich die Fehlermeldung?
    weil in dem InsertCommand ist doch überhaupt kein Kriterium.

    Was ich dir ebenfalls dringend empfehle: Mach den TryCatch weg.
    Es bringt nix, sich Fehlermeldungen wegzufangen - die fehler müssen ja doch identifiziert und behoben werden.
    Das Proggi kann eh nicht weiter laufen, bzw. das könnte wenns echt dumm läuft sogar zu Datenverlusten führen, wenn man ihm erlauben würde, weiterzulaufen.
    Daher ist in 99% der Fälle besser, keinen TryCatch hinzumachen - und in diesem Falle auch.
    Siehe TryCatch ist ein heißes Eisen
    Ja, das war die Fehlermeldung.

    Den TryCatch hatte ich während dem Debuggen auskommentiert, da wurde mir dann auch dieser Fehler ausgegeben - nicht nur in der hinterlegten Messagebox.

    Ich hab jetzt mal die DatePicker im Insert nicht mit ".value" sondern mit ".Text" übergeben.
    Das hat geholfen, ich kann die Daten jetzt übertragen.

    Vielen Dank bis hier her für eure Hilfe und Geduld!

    EveretEichhörnchen schrieb:

    Ich übergebe den Text aus dem DatePicker, weil er den Value nicht erkennt, wenn ich die Access Spalte als DateTime definiere.

    naja, wenn du Text aus dem DatePicker erhälst, dann musst du den umwandeln in Date, dann sollte das hinhauen:
    Dim d = Date.Parse(datepicker.text) oder sowas. d wird dann zum Datentyp Date und das passt mit einer Spalte Datum/Uhrzeit in Access zusammen.
    Ich arbeite mit Access als Datenbank hinter meinem Projekt (sogar mit der alten mdb-Version) und das kommt wunderbar mit DateTime-Sachen klar, wenn ich die auch richtig übergebe ;)
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    EveretEichhörnchen schrieb:



    Da ich in der ACCDB die Spalte DATUM als Datum/Uhrzeit deklariert hatte, hat er beim Eintragen den gleichen Fehler (Datentypenkonflikt in Kriterienausdruck) gebracht.

    [/vbnet]


    es kann sein das 'Datum' ist ein resevriertes WORT in Access ist, ändere die Feldbezeichnung in der Accesstabelle zu 'nDatum' und schau mal ob es funktioniert

    Kasi schrieb:

    ändere die Feldbezeichnung in der Accesstabelle zu 'nDatum' und schau mal ob es funktioniert

    ist nicht nötig. Mit "Datum" muss es auch funzen - geht bei mir auch
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Kann man hier mal eben das „echte“ SQL-Statement posten um zu sehen was denn nun tatsächlich an die DB gesendet wird? Zudem ein Auszug der Werte die in der DB stehen?

    Bei der WERE Klausel mit Datum zu arbeiten ist tricky, da meist noch ne Uhrzeit mit drin steht.

    SQL-Abfrage

    1. DELETE FROM MyTable WHERE Convert(date, DatumBarFoo) = Convert(date, DatumFooBar)

    *date muss hier gegen einen Datum Datentypen ausgetauscht werden der nur ein Datum ohne Uhrzeit enthält.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    mrMo schrieb:

    *date muss hier gegen einen Datum Datentypen ausgetauscht werden der nur ein Datum ohne Uhrzeit enthält.


    das geht doch eigentlich mit date.date - dann bekommt man das Datum ohne Uhrzeit
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup: