Primärschlüssel ermitteln

  • VB.NET

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

    Primärschlüssel ermitteln

    Hallo

    Meine Kenntnisse reichen noch nicht aus, um folgendes Problem zu lösen. Ich habe zwei Tabellen, eine mit Statistikdaten pro Mitarbeiter (TabStatistik) und eine für die Mitarbeiter (TabMitarbeiter) selbst. Ich möchte nun einen neuen Statistik-Datensatz speichern für einen Mitarbeiter, den ich aus einer Combobox auswähle. Diese habe ich vorher mit den Mitarbeitern aus der Tabelle TabMitarbeiter gefüllt.

    Mein Code, der grundsätzlich funktioniert:

    VB.NET-Quellcode

    1. Dim con As New OleDb.OleDbConnection
    2. Dim cmd As New OleDb.OleDbCommand
    3. con = New OleDb.OleDbConnection
    4. con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Application.StartupPath & "\Datenbank.mdb"
    5. cmd.Connection = con
    6. cmd.CommandText = "INSERT INTO TabStatistik " &
    7. "([Mitarbeiter], [Datum], [Daten_1], [Daten_2], [Daten_3], [Daten_4], [Daten_5], [Daten_6], Daten_7]) " &
    8. "VALUES(@Mitarbeiter, @Datum, @Daten_1, @Daten_2, @Daten_3, @Daten_4, @Daten_5, @Daten_6, @Daten_7)"
    9. cmd.Parameters.AddWithValue("@Mitarbeiter", ?????????????????????)
    10. cmd.Parameters.AddWithValue("@Datum", Datum)
    11. cmd.Parameters.AddWithValue("@Daten_1", Daten_1)
    12. cmd.Parameters.AddWithValue("@Daten_2", Daten_2)
    13. cmd.Parameters.AddWithValue("@Daten_3", Daten_3)
    14. cmd.Parameters.AddWithValue("@Daten_4", Daten_4)
    15. cmd.Parameters.AddWithValue("@Daten_5", Daten_5)
    16. cmd.Parameters.AddWithValue("@Daten_6", Daten_6)
    17. cmd.Parameters.AddWithValue("@Daten_7", Daten_7)
    18. Try
    19. con.Open()
    20. Dim anzahl = cmd.ExecuteNonQuery()
    21. MessageBox.Show($"Es wurde {anzahl} Datensatz erfolgreich gespeichert.")
    22. con.Close()
    23. Catch ex As Exception
    24. MessageBox.Show(ex.Message)
    25. End Try


    Ich will ja nicht den Namen des Mitarbeiters als String speichern, sondern die ID des Mitarbeiters aus der Tabelle TabMitarbeiter. In meiner ComboBox habe ich natürlich nur Text. Ich müsste also anhand des Namens die ID ermitteln und das möglichst auf elegante und direkte Art, finde aber in meinen Lehrbüchern nichts, was mir weiterhilft. Für Tipps wäre ich sehr dankbar.

    Viele Grüsse

    P.
    Ohne die Details deiner Tabellenstruktur fällt es mir schwer, dir eine richtig gute Antwort zu schreiben, also muss ich ein paar Behauptungen anstellen.

    Nehmen wir an, deine Mitarbeiter-Tabelle ist wie folgt aufgebaut:
    ID (int, not null, pkey)Name (varchar)Vorname (varchar)
    0MustermannMax
    1MustermannErika



    und dass deine Statistiktabelle so aufgebaut ist:

    ID (int, not null, pkey)Mitarbeiter (int references Mitarbeiter.ID)Daten 1Daten 2
    00Super gute Arbeit oder so
    11Ebenfalls super Arbeit


    Dann hast du ja alle Daten, die du brauchst. Falls deine Daten nicht so atomar aufgebaut sind, solltest du dich nochmal mit Datenbanknorminalisierung befassen.

    In dem Fall kannst du ja mit einem Sub-Query den Namen des Mitarbeiters herausfinden.

    SQL-Abfrage

    1. select
    2. ID,
    3. Daten1,
    4. Daten2,
    5. (select Nachname from Mitarbeiter where Mitarbeiter.ID = Statistik.Mitarbeiter) as MitarbeitName,
    6. (select Vorname from Mitarbeiter where Mitarbeiter.ID = Statistik.Mitarbeiter) As MitarbeiterVorname
    7. from Statistik
    8. where [bedingung];


    Ich habe leider die genaue Syntax gerade nicht im Kopf, aber so oder so änhnlich müsste es gehen. Das variiert je nachdem, welchen DBMS du verwendest. Ich meine mich dunkel daran erinnern zu können, dass MS SQL auch noch seine Eigenheiten hat.

    Im Zweifel nochmal für deinen genauen DBMS/Deiner Datenbank nach "Subquery" suchen.
    Alternativ würde allerdings auch ein inner oder left join gehen.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)
    Fast-Vollzitat des direkten Vorposts an dieser Stelle entfernt ~VaporiZed

    Ich nutze eine Access *.mdb, das habe ich leider nicht erwähnt. Den Namen des Mitarbeiters kenne ich ja, aber nicht die ID des entsprechenden Datensatzes in der TabMitarbeiter. Die brauche ich ja zum Speichern.

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

    Aber wenn du den Namen des Mitarbeiters kennst, kannst du doch darüber auch die ID finden. Allerdings hört sich das für mich arg nach einem systemischen an.
    Deine Daten sind suboptimal abgelegt - eigentlich müsstest du die komplette Datenstruktur refactoren und da nochmal von vorne an. Da kann ich dir - wo oben bereits geschrieben - nur empfehlen, dir Datenbanknorminalisierung anzuschauen und dich dort einzulesen.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)

    Pe..CH schrieb:


    für einen Mitarbeiter, den ich aus einer Combobox auswähle


    Du kannst an eine ComboBox Daten binden. So könntest du dann Problemlos an die ID des Mitarbeiters kommen.
    Beispiel

    C#-Quellcode

    1. comboBox1.DisplayMember= "Name";
    2. comboBox1.DataSource = new List<Employee>() {
    3. new Employee(1, "Max"),
    4. new Employee(2, "MusterMann")
    5. };
    6. comboBox1.SelectedIndexChanged += (s, ev) => {
    7. Employee employee = comboBox1.SelectedItem as Employee;
    8. System.Diagnostics.Debug.WriteLine($"{employee.Id}, {employee.Name}");
    9. };

    Vollzitat eines Vorposts an dieser Stelle entfernt ~VaporiZed
    @siycah
    Meine Tabellen sind so aufgebaut, wie du sie aufgezeigt hast. Kann ich die ID nicht innerhalb meiner INSERT ermitteln, oder muss ich vorher bereits eine Abfrage machen ? Kann ich mir den einen Zugriff nicht sparen ?

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

    Ach so, mein Fehler. Dann habe ich dich falsch verstanden.

    Ja, in deinem INSERT INTO kannst du theoretisch auch ein SELECT machen, klar.
    Sind deine Datenmengen so hoch, dass es dir wirklich um einen Zugriff mehr geht?

    Ich würde den SELECT vorher machen und in einer Variable schreiben. So kannst du es auch später besser debuggen, als wenn du alles in ein Statement kloppst.
    Viele versuchen möglichst viel möglichst kompakt zu machen, verstehen dann aber drei Wochen später schon nicht mehr, was genau sie fabriziert haben.

    Versuche nicht von vorn herein zu optimieren, sondern baue erstmal das funktionale Programm und schaue dann, ob sich die Optimierung überhaupt lohnt. Wenn dein Programm dadurch nur eine halbe Sekunde schneller wird, aber du den geschriebenen Quellcode selbst nicht mehr verstehst, dann hast du dir über kurz oder lang selbst ins Bein geschossen.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)

    VB.NET-Quellcode

    1. Dim con As New OleDb.OleDbConnection
    2. Dim cmd As New OleDb.OleDbCommand
    3. con = New OleDb.OleDbConnection
    4. con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Application.StartupPath & "\Datenbank.mdb"
    5. cmd.Connection = con
    6. cmd.CommandText = "INSERT INTO TabStatistik " &
    7. "([Mitarbeiter], [Datum], [Daten_1], [Daten_2], [Daten_3], [Daten_4], [Daten_5], [Daten_6], Daten_7]) " &
    8. "VALUES(@Mitarbeiter, @Datum, @Daten_1, @Daten_2, @Daten_3, @Daten_4, @Daten_5, @Daten_6, @Daten_7)"
    9. cmd.Parameters.AddWithValue("@Mitarbeiter", ?????????????????????)
    10. cmd.Parameters.AddWithValue("@Datum", Datum)
    11. cmd.Parameters.AddWithValue("@Daten_1", Daten_1)
    12. cmd.Parameters.AddWithValue("@Daten_2", Daten_2)
    13. cmd.Parameters.AddWithValue("@Daten_3", Daten_3)
    14. cmd.Parameters.AddWithValue("@Daten_4", Daten_4)
    15. cmd.Parameters.AddWithValue("@Daten_5", Daten_5)
    16. cmd.Parameters.AddWithValue("@Daten_6", Daten_6)
    17. cmd.Parameters.AddWithValue("@Daten_7", Daten_7)
    18. Try
    19. con.Open()
    20. Dim anzahl = cmd.ExecuteNonQuery()
    21. MessageBox.Show($"Es wurde {anzahl} Datensatz erfolgreich gespeichert.")
    22. con.Close()
    23. Catch ex As Exception
    24. MessageBox.Show(ex.Message)
    25. End Try
    Sowas solltest du ganz lassen. Für sowas gibts CommandBuilder, und einigen anderen Kram.
    Wenn du für jede Tabelle für jedes Command (Select, Update, Delete, Insert) so ein Brimborium selbst programmieren willst, dann biste nächstes Jahr fertig, hast 10000 Zeilen, und die Anwendung kann immer noch kaum mehr als ein Fliegen-furz.
    Am besten du lässt die DB erstmal weg und lernst, wie man das mit Comboboxen, DataGridView und Databinding etc. so programmiert, wie vorgesehen (man füllt nämlich nix in Comboboxen).
    Guggemol vier Views Videos
    Datenbank-Anschluss kannste später noch machen - wenn überhaupt nötig.
    Fast-Vollzitat des direkten Vorposts an dieser Stelle entfernt ~VaporiZed

    Danke für deinen Input. Es exisitiert bereits eie Datenbank mit 10.000 Einträgen. Ich programmiere den Fliegen-Furz drumherum, damit weitere Einträge erfasst/geändert werden können. Deine Videos sind mir bekannt, aber es geht mir nicht um eine Darstellung der Daten, sonder nur darum, welche zu erfassen. Meine Vorgehensweise ist wohl nicht im Sinne des Erfinders (des Rades), evtl. mache ich einen Neustart mit Databinding etc.

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

    Hallo @Pe..CH,

    aus der MS Online-Hilfe habe ich folgende Funktion gefunden,wie aus ein Access-DB nach dem Hinzufügen eines Datensatzes der Wert einer AutoID ermittelt werden kann:

    VB.NET-Quellcode

    1. ''' <summary>
    2. ''' Ermittelt den Autowert des zuletzt hinzugefügten Datensatzes
    3. ''' </summary>
    4. ''' <param name="Conn">OleDb-Connection Objekt</param>
    5. ''' <returns>Autowert</returns>
    6. Public Function GetAutoID(ByVal Conn As OleDb.OleDbConnection) As Integer
    7. Dim SQL As String = "SELECT @@IDENTITY"
    8. GetAutoID = 0
    9. Using cmd As OleDb.OleDbCommand = New OleDb.OleDbCommand(SQL, Conn)
    10. GetAutoID = CInt(cmd.ExecuteScalar)
    11. End Using
    12. End Function


    Und aufrufen tue ich das wie folgt:

    VB.NET-Quellcode

    1. [...]
    2. strSQL = "INSERT INTO tblMandanten (MandantNr, CryptoTyp) VALUES(" & iMdNr & ", " & iCrypto & ")"
    3. cmd.CommandText = strSQL
    4. cmd.ExecuteNonQuery()
    5. AutoID = GetAutoID(myOleDbConnection)
    6. [...]


    Gruß Achilleus
    Entweder Databinding oder die Mitarbeiter ID anhand des Mitarbeiternamens vorher auslesen.

    Da du die Mitarbeiter ja aber vorher ohnehin schon aus der Tabelle liest um sie in die Combobox zu schreiben, wäre es sinnvoll gleich die ID mit auszulesen und an die Combobox zu hängen.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. Dim connStr As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Application.StartupPath & "\Datenbank.mdb"
    4. Dim ds As DataSet = GetRecordset("select personal_id,mitarbeitername from mitarbeiter;", connStr)
    5. With ComboBox1
    6. .DataSource = ds.Tables(0)
    7. .DisplayMember = "mitarbeitername"
    8. .ValueMember = "personal_id"
    9. End With
    10. End Sub
    11. Private Sub ComboBox1_SelectedValueChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedValueChanged
    12. TextBox1.Clear()
    13. TextBox1.Text = String.Concat("Mitarbeiter ", ComboBox1.Text, " hat die ID: ", ComboBox1.SelectedValue.ToString)
    14. End Sub
    15. Private Function GetRecordset(command As String, connstr As String) As DataSet
    16. Dim ret As New DataSet
    17. Using conn As New OleDbConnection With {.ConnectionString = connstr}
    18. Try
    19. conn.Open()
    20. Using adapter As New OleDbDataAdapter
    21. Using cmd As New OleDbCommand With {.Connection = conn}
    22. cmd.CommandText = command
    23. adapter.SelectCommand = cmd
    24. adapter.Fill(ret)
    25. End Using
    26. End Using
    27. Catch ex As Exception
    28. Finally
    29. conn.Close()
    30. End Try
    31. End Using
    32. Return ret
    33. End Function
    34. End Class


    Pe..CH schrieb:

    Deine Videos sind mir bekannt


    Dann weißt du mehr über mich, als ich selbst ;)

    Ich glaube es kristalisiert sich langsam heraus, dass deine Frage noch etwas konkreter gestellt werden muss. Mit jeder Antwort kamen (zumindest für mein Empfinden) immer mehr und neue Details ans Licht, die deine Frage konkretisiert haben.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)

    siycah schrieb:


    Ich glaube es kristalisiert sich langsam heraus, dass deine Frage noch etwas konkreter gestellt werden muss. Mit jeder Antwort kamen (zumindest für mein Empfinden) immer mehr und neue Details ans Licht, die deine Frage konkretisiert haben.


    Nein, meine Frage wurde mehrfach befriedigend beantwortet. Danke an euch alle.