Datensatz in Datenbank am schnellsten Kopieren

  • VB.NET

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von Superuse.

    Datensatz in Datenbank am schnellsten Kopieren

    Hallo Kollegen

    wie kann ich wohl am schnellsten über VB einen Datensatz in einer Mysql-Datenbank am schnellsten kopieren. Folgendes funktioniert zwar in meinem MySQL-Abfrage Tool, aber nicht über VB:

    SQL-Abfrage

    1. CREATE TEMPORARY TABLE tmp SELECT * FROM Journal WHERE rec_id = 12345;
    2. UPDATE tmp SET rec_id = (SELECT MAX(Rec_id)+1 FROM journal);
    3. INSERT INTO Journal SELECT * FROM tmp;"


    Ich vermute das VB die temporäre Tabelle nicht mehr kenn, wenn ich das als 3 einzelne Befehle an die Datenbank schicke. Aber auch wenn ich das zusammen als eine Abfrage laufen lasse, ist kein neuer Datensatz erzeugt. Fehlermeldungen gibt es seitens VB aber auch keine.

    Hat jemand einen anderen Ansatz?

    Code-Tags eingefügt ~EaranMaleasi

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

    Wenn du das Statement in VB abschickst tut es genau so wie direkt in deinem MySQL Tool. Nur muss es eben am Stück bleiben. Du solltest mal den relevanten VB Code posten damit man sich das anschauen kann.
    "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
    Wow. Hätte am Sonntag dazu keine Antworten erwartet.
    Ich habe eine allgemeine Funktion, die in Datenbanken schreibt. Die sieht aktuell so aus:

    VB.NET-Quellcode

    1. Public Function WritetoTable(ByVal strSQL As String) As String
    2. Dim strResult As String
    3. Dim Conn As New MySqlConnection(Form1.Verbindungsstring)
    4. Dim myCommand As New MySqlCommand
    5. Conn.Open()
    6. myCommand.CommandText = strSQL
    7. myCommand.Connection = Conn
    8. Try
    9. myCommand.ExecuteNonQuery()
    10. strResult = 0
    11. Catch myerror As MySqlException
    12. MsgBox("There was an error updating the database: " & myerror.Message)
    13. strResult = 1
    14. End Try
    15. If Not Conn Is Nothing Then Conn.Dispose()
    16. If Not myCommand Is Nothing Then myCommand.Dispose()
    17. Return strResult
    18. End Function


    Die Funktion ruf ich dann so auf

    VB.NET-Quellcode

    1. Module1.WritetoTable("CREATE TEMPORARY TABLE tmp SELECT * FROM Journal WHERE rec_id = (SELECT MAX(Rec_id)+1 FROM journal);UPDATE tmp SET rec_id = (SELECT MAX(Rec_id)+1 FROM journal);INSERT INTO Journal SELECT * FROM tmp;")
    Wie sieht das SQL Statement aus, wenn du es über dein SQL Tool laufen lässt?
    "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

    Superuse schrieb:

    Hallo Kollegen

    wie kann ich wohl am schnellsten über VB einen Datensatz in einer Mysql-Datenbank am schnellsten kopieren. Folgendes funktioniert zwar in meinem MySQL-Abfrage Tool, aber nicht über VB:

    CREATE TEMPORARY TABLE tmp SELECT * FROM Journal WHERE rec_id = 12345;
    UPDATE tmp SET rec_id = (SELECT MAX(Rec_id)+1 FROM journal);
    INSERT INTO Journal SELECT * FROM tmp;"



    so richtig sinn macht das nicht.

    du willst die nummer 12345 aufrufen um 12346 daraus zumachen ?
    ist 12345 die letzte nummer in der Tabelle?
    Ich erstelle damit eine Kopie des Datensatzes in eine temporäre Tabelle. Dann wird die ID des neuen Datensatzes auf die nächste freie ID gesetzt und dann wieder zurück in die ursprüngliche Tabelle kopiert.
    Das erschien mir der einfachste Weg, einen Datensatz zu kopieren.
    frage nicht beantwortet aus Post#7 ..ist das die letzte/höchste ID in der Tabelle?

    also das liefert mir zunächst die letzte/höchste ID aus einer Access Tabelle

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    2. Dim sDB As String = "E:\Adressen.mdb"
    3. Dim cmd As OleDbCommand
    4. Dim Dr As OleDbDataReader
    5. Dim sCon As String = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
    6. "Data Source=" & sDB & ";"
    7. Dim Cn As OleDb.OleDbConnection = New OleDb.OleDbConnection(sCon)
    8. Cn.Open()
    9. Try
    10. cmd = Cn.CreateCommand()
    11. cmd.CommandText = "SELECT * FROM tbl_someTable WHERE myID = (SELECT MAX(myID) FROM tbl_SomeTable)"
    12. 'cmd.CommandText = "SELECT * FROM Journal WHERE rec_id = (SELECT MAX(rec_id) FROM Journal)"
    13. 'CREATE TEMPORARY TABLE tmp SELECT * FROM Journal WHERE rec_id = 12345;
    14. 'UPDATE tmp SET rec_id = (SELECT MAX(Rec_id)+1 FROM journal);
    15. 'INSERT INTO Journal SELECT * FROM tmp;"
    16. Dr = cmd.ExecuteReader()
    17. Dr.Read()
    18. TextBox1.Text = CStr(Dr.Item(1))
    19. Catch ex As Exception
    20. MsgBox(ex.Message())
    21. Finally
    22. Cn.Close()
    23. End Try
    24. End Sub


    jetzte Increment mit + 1 für deine neue ID.

    aber warum nicht einen Autowert verwenden ?
    Der zu kopierende Datensatz hat IRGEND eine ID. Der neu erzeugte muß natürlich die nächste, freie ID bekommen. Das passiert ja eigentlich hier.

    UPDATE tmp SET rec_id = (SELECT MAX(Rec_id)+1 FROM journal);

    Das war auch nicht mein Problem. Die Ausführung dieser 3 SQL-Befehle führt ja im SQL-Tool auch zum korrekten Ergebnis.

    'CREATE TEMPORARY TABLE tmp SELECT * FROM Journal WHERE rec_id = 12345;
    'UPDATE tmp SET rec_id = (SELECT MAX(Rec_id)+1 FROM journal);
    'INSERT INTO Journal SELECT * FROM tmp;"


    Nur beim Abschicken über VB passiert gar nichts.
    versuche es so, deine Connection natürlich anpassen
    dies verwendet OleDb.OleDbTransaction um mehrere Transaktionen auszuführen

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    2. Dim sSql As String
    3. Dim con As OleDbConnection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;data source=D:\Db2010.accdb")
    4. 'öffnen
    5. con.Open()
    6. 'Transaktionen ausführen
    7. sSql = "CREATE TEMPORARY TABLE tmp SELECT * FROM Journal WHERE rec_id = 12345;"
    8. ExecuteSQL(con, sSql)
    9. sSql = "UPDATE tmp SET rec_id = (SELECT MAX(Rec_id)+1 FROM journal);"
    10. ExecuteSQL(con, sSql)
    11. sSql = "INSERT INTO Journal SELECT * FROM tmp;"
    12. ExecuteSQL(con, sSql)
    13. 'schliessen
    14. con.Close()
    15. con = Nothing
    16. End Sub
    17. Public Function ExecuteSQL(ByVal Con As OleDb.OleDbConnection, _
    18. ByVal sSQL As String, _
    19. Optional ByRef ErrMessage As String = Nothing, _
    20. Optional ByVal TransAction As _
    21. OleDb.OleDbTransaction = Nothing) As Integer
    22. ErrMessage = Nothing
    23. Try
    24. Dim Result As Integer = 0
    25. Using Cmd As New OleDb.OleDbCommand(sSQL, Con, TransAction)
    26. Result = Cmd.ExecuteNonQuery
    27. End Using
    28. Return Result
    29. Catch ex As Exception
    30. ErrMessage = ex.Message
    31. Return 0
    32. End Try
    33. End Function


    wobei der Sinn ergibt sich immer noch nicht.
    die nächste ID finden in dem zusammenhang ist nicht logisch, wenn du IRGEND eine ID kopieren willst

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

    Wenn man einen neuen Datensatz zu einer Datenbank hinzufügt, die auf der ID-Spalte automatisch eine fortlaufende ID erzeugt und jeden Wert nur 1x erlauft, mußt du das wohl machen.
    In oben genannten Script wird ja der Datensatz erst in eine temporäre Tabelle kopiert. Da hätte die Spalte ID ja noch den alten Wert. Dann wird aus der Quelltabelle die aktuell höchste verwendete ID ermittelt und in der temporären Tabelle mit dem höchsten Wert +1 ersetzt, damit der kopierte Datensatz wieder in die Quelltabelle zurück kopiert werden kann, ohne das die Datenbank sagt, das die Id schon vorhanden ist. Eventuell würde es auch funktionieren die ID auf NULL zu setzen und die Datenbank vergibt automatisch eine. Das habe ich bislang nicht getestet, da obiges ja in der Datenbank auch funktioniert.

    Haben das nun auf 3 hintereinander ausgeführte Befehle aufgetrennt und dann scheint es tatsächlich zu funktionieren, wobei ich momentan noch nicht weiß, wie lange die temporäre Tabelle in Mqsql existiert und ob man diese löschen muß.

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

    Kasi schrieb:

    dies verwendet OleDb.OleDbTransaction um mehrere Transaktionen auszuführen
    Ich glaub die Transaktion hast du vergessen.
    Der Satz ist auch unlogisch - imo müsste es heissen:
    dies verwendet OleDb.OleDbTransaction um mehrere Aktionen auszuführen
    Aber wie gesagt: Im Code tritt keine Transaction-Instanz auf.
    nochmal darüber nachgedacht, wenn du deine ID als Autowert verwendest kannst
    du es so machen. Die neue ID wird auch angezeigt

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    2. Dim con As OleDbConnection = New OleDbConnection("Provider=Microsoft.jet.oledb.4.0;data source=E:\Adressen.mdb")
    3. Dim sSql As String = "INSERT INTO [Personal] "
    4. sSql &= "SELECT Nachname,Vorname,Position "
    5. sSql &= "FROM Personal "
    6. sSql &= "WHERE [Personal-Nr]=5;"
    7. con.Open()
    8. ExecuteSQL(con, sSql)
    9. 'zeige Neue ID
    10. txtID.Text = NewID(con)
    11. con.Close()
    12. con = Nothing
    13. End Sub
    14. Public ReadOnly Property NewID(ByVal Cn As OleDb.OleDbConnection, _
    15. Optional ByVal ErrMessage As String = Nothing) As Integer
    16. Get
    17. Try
    18. Dim ID As Integer
    19. Dim sSQL As String = "Select @@Identity As [ID]"
    20. Using Cmd As New OleDb.OleDbCommand(sSQL, Cn)
    21. Using DR As OleDb.OleDbDataReader = Cmd.ExecuteReader
    22. Do While DR.Read
    23. ID = DR("ID")
    24. Loop
    25. DR.Close()
    26. Return ID
    27. End Using
    28. End Using
    29. Catch ex As Exception
    30. ErrMessage = ex.Message
    31. Return 0
    32. End Try
    33. End Get
    34. End Property
    35. Public Function ExecuteSQL(ByVal Cn As OleDb.OleDbConnection, _
    36. ByVal sSQL As String, _
    37. Optional ByRef ErrMessage As String = Nothing, _
    38. Optional ByVal TransAction As _
    39. OleDb.OleDbTransaction = Nothing) As Integer
    40. ErrMessage = Nothing
    41. Try
    42. Dim Result As Integer = 0
    43. Using Cmd As New OleDb.OleDbCommand(sSQL, Cn, TransAction)
    44. Result = Cmd.ExecuteNonQuery
    45. End Using
    46. Return Result
    47. Catch ex As Exception
    48. ErrMessage = ex.Message
    49. Return 0
    50. End Try
    51. End Function


    hier noch ein Image, du siehst Mitarbeiter 'Buchanan' ist kopiert mit der neuen ID 11


    @Superuse
    du bist dir bewusst das du so aber auch doppelte Datenbestände hast, lediglich mit einer neuen ID

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Kasi“ ()

    Der Hintergrund ist nicht ein doppelter Datensatz. Nach dem kopieren werden noch ein paar Felder abgeändert. Ich mache hier aus einer Rechnung eine Gutschrift. Dabei ändern sich nur ein paar wenige Werte. Ich halte das auf diesem Weg als schneller umgesetzt als den ganzen Datensatz auszulesen und die Felder alle einzeln wieder zurückzuschreiben. Die Tabelle hat ca. 250 Felder.
    Dieser Eintrag ist dann auch nur der "Kopf"-Datensatz der Rechnung. Es gibt dann auch nochmal die Positionen, die auch durchlaufen werden müssen. Die müssen dann auch wiederum auf die neue ID angepasst werden. Das läuft zwischenzeitlich nun auch zu 95%. Muß nur noch ein paar Kleinigkeiten anpassen.
    Ich habe zum Schreiben in die DB übrigens eine Funktion, die ich verwende. Das macht es übersichtlicher.

    VB.NET-Quellcode

    1. Public Function WritetoTable(ByVal strSQL As String) As String
    2. Dim strResult As String
    3. Dim Conn As New MySqlConnection(Form1.Verbindungsstring)
    4. Dim myCommand As New MySqlCommand
    5. Conn.Open()
    6. myCommand.CommandText = strSQL
    7. myCommand.Connection = Conn
    8. Try
    9. myCommand.ExecuteNonQuery()
    10. strResult = 0
    11. Catch myerror As MySqlException
    12. MsgBox("There was an error updating the database: " & myerror.Message)
    13. strResult = 1
    14. End Try
    15. If Not Conn Is Nothing Then Conn.Dispose()
    16. If Not myCommand Is Nothing Then myCommand.Dispose()
    17. Return strResult
    18. End Function