none
Neuen User in zwei Tabellen anlegen RRS feed

  • Frage

  • Hallo zusammen,

    ich habe in einer MS-SQL-Datenbank zur Usererfassung zwei Tabellen angelegt.
    Die erste Tabelle heißt 'Student' und hat den Primärschlüssel Student_id.
    Die zweite Tabelle heißt 'Fachgebiet' und hat den Primärschlüssel Fach_id und den Fremdschlüssel Student_id.

    Das Anlegen von Datensätzen in die erste Tabelle(Student) funktioniert fehlerlos mit:
    INSERT INTO dbo.Student (Vorname, Email, Passwort, RegDatum, Gender, Birthda) Values (" & werte & ")

    'werte' ist eine Variable in VB.net, die die einzelnen Spaltenwerte enthält.

    Nun gibt es aber noch weitere Werte(LastVisit, Anzahl_der_Besuche, Note),  die in die Tabelle 'Fachgebiete'  eingetragen werden müssen.
    Die Verbindung der beiden Tabellen wird ja über die Fremdschlüsselbeziehung 'Student_id' hergestellt.

    Nur, wie muss der SQL-Code aussehen, damit in die Tabelle 'Fachgebiet' ebenfalls der Datensatz reingeschrieben wird?

    Vielen Dank für Eure Antworten!

    Rheinschiffer_70

    Mittwoch, 18. September 2019 16:21

Antworten

  • Hallo!

    Da Du explizit nach dem SQL-Code fragst, hier ein vereinfachtes Beispiel (weniger Spalten und ohne PK und FK):

    Create table #Student (Student_id int identity, Vorname varchar(20), Email varchar(20)) ;
    Create table #Fachgebiete (Fach_id int identity, Student_id int, LastVisit date, Anzahl_der_Besuche int , Note decimal(3,2)) ;
    
    Insert into #Student(Vorname, Email) values ('Rheinschiffer', 'r@test.de');
    Insert into #Fachgebiete(Student_id, LastVisit, Anzahl_der_Besuche, Note) 
    Select Student_id, GETDATE() as LastVisit, 1 as Anzahl_der_Besuche, 1.0 as Note
    from #Student
    where Vorname = 'Rheinschiffer';
    
    Select *
    from #Student;
    Select *
    from #Fachgebiete;
    
    go
    drop table #Student;
    drop table #Fachgebiete;
    HTH!


    Einen schönen Tag noch, Christoph - http://www.insidesql.org/blogs/cmu

    Donnerstag, 19. September 2019 06:01
  • Hi,
    anstelle der Verkettung mit "werte" sollten besser zur Verhinderung von Injection und weiteren Fehlern Parameter genutzt werden.

    Wenn es sich bei Student_id um einen Autowert handelt, kann dieser direkt nach dem Insert mit der gleichen SQL Anweisung zurück gelesen werden.

    Hier mal eine Konsolendemo:

    Imports System.Data.SqlClient
    
    Module Module1
      Sub Main()
        Try
          With (New Demo)
            .CreateDataTables()
            .SaveData()
            .Test()
          End With
        Catch ex As Exception
          Console.WriteLine(ex.ToString)
        End Try
        Console.WriteLine("Continue enter key")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
    
        ''' <summary>
        ''' Delete old Student and Fachgebiet
        ''' Create New Student and Fachgebiet
        ''' </summary>
        Friend Sub CreateDataTables()
          Using cn As New SqlConnection(My.Settings.cnSQL)
            cn.Open()
            Using cmd As New SqlCommand("", cn)
              ' Delete old Tables, ignore error if table not exists
              cmd.CommandText = "DROP Table [Student]"
              Try
                cmd.ExecuteNonQuery()
              Catch ex As Exception
              End Try
              cmd.CommandText = "DROP Table [Fachgebiet]"
              Try
                cmd.ExecuteNonQuery()
              Catch ex As Exception
              End Try
              ' create new tables
              cmd.CommandText = "CREATE Table [Student]([Student_id] int Identity, [Name] nvarchar(50), CONSTRAINT [PK_Student] PRIMARY KEY ([Student_id]))"
              cmd.ExecuteNonQuery()
              cmd.CommandText = "CREATE Table [Fachgebiet]([Fach_id] int Identity, [Student_id] int, [Note] int, CONSTRAINT [PK_Fach] PRIMARY KEY ([Fach_id]))"
              cmd.ExecuteNonQuery()
            End Using
          End Using
        End Sub
    
        ''' <summary>
        ''' Load jpg and save inti Table1
        ''' </summary>
        Friend Sub SaveData()
          Using cn As New SqlConnection(My.Settings.cnSQL)
            cn.Open()
            ' cmd1 für Master-Datensatz (Student)
            Using cmd1 As New SqlCommand("", cn)
              cmd1.CommandText = "INSERT INTO dbo.Student (Name) Values (@Name); SELECT Scope_Identity()"
              cmd1.Parameters.Add("@Name", SqlDbType.NVarChar)
              ' cmd2 für Child-Datensatz (Fachgebiet)
              Using cmd2 As New SqlCommand("INSERT INTO dbo.Fachgebiet (Student_id, Note) Values (@Student_id, @Note)", cn)
                cmd2.Parameters.Add("@Student_id", SqlDbType.Int)
                cmd2.Parameters.Add("@Note", SqlDbType.Int)
                ' Schleife für das Hinzufügen von mehreren Master-Datensätzen
                For i = 1 To 5
                  cmd1.Parameters("@Name").Value = $"Name {i}"
                  Dim id = cmd1.ExecuteScalar
                  ' dazu einen Child-Datensatz hinzufügen
                  cmd2.Parameters("@Student_id").Value = id
                  cmd2.Parameters("@Note").Value = i
                  cmd2.ExecuteNonQuery()
                Next
              End Using
            End Using
          End Using
        End Sub
    
        ''' <summary>
        ''' Test, display inserted records
        ''' </summary>
        Friend Sub Test()
          Using cn As New SqlConnection(My.Settings.cnSQL)
            cn.Open()
            Using cmd As New SqlCommand("SELECT Student.Name, Fachgebiet.Note FROM dbo.Student INNER JOIN dbo.Fachgebiet ON Student.Student_id = Fachgebiet.Student_id", cn)
              Dim rdr = cmd.ExecuteReader
              While rdr.Read
                Console.WriteLine($"Name: {rdr(0)}, Note: {rdr(1)}")
              End While
            End Using
          End Using
        End Sub
    
      End Class
    
    End Module


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks


    Donnerstag, 19. September 2019 03:36

Alle Antworten

  • In dem du dir die Student-ID per Select aus Student ausliest und dann beim Insert in Fachgebiet mit angibst.
    Die Fremdbeziehung dient nur dem einfacheren Verbinden der Tabellen mit Join.
    Die meisten Programmier-Frameworks benötigen ID-Fields als Primary Key.
    Mittwoch, 18. September 2019 16:39
  • Hi,
    anstelle der Verkettung mit "werte" sollten besser zur Verhinderung von Injection und weiteren Fehlern Parameter genutzt werden.

    Wenn es sich bei Student_id um einen Autowert handelt, kann dieser direkt nach dem Insert mit der gleichen SQL Anweisung zurück gelesen werden.

    Hier mal eine Konsolendemo:

    Imports System.Data.SqlClient
    
    Module Module1
      Sub Main()
        Try
          With (New Demo)
            .CreateDataTables()
            .SaveData()
            .Test()
          End With
        Catch ex As Exception
          Console.WriteLine(ex.ToString)
        End Try
        Console.WriteLine("Continue enter key")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
    
        ''' <summary>
        ''' Delete old Student and Fachgebiet
        ''' Create New Student and Fachgebiet
        ''' </summary>
        Friend Sub CreateDataTables()
          Using cn As New SqlConnection(My.Settings.cnSQL)
            cn.Open()
            Using cmd As New SqlCommand("", cn)
              ' Delete old Tables, ignore error if table not exists
              cmd.CommandText = "DROP Table [Student]"
              Try
                cmd.ExecuteNonQuery()
              Catch ex As Exception
              End Try
              cmd.CommandText = "DROP Table [Fachgebiet]"
              Try
                cmd.ExecuteNonQuery()
              Catch ex As Exception
              End Try
              ' create new tables
              cmd.CommandText = "CREATE Table [Student]([Student_id] int Identity, [Name] nvarchar(50), CONSTRAINT [PK_Student] PRIMARY KEY ([Student_id]))"
              cmd.ExecuteNonQuery()
              cmd.CommandText = "CREATE Table [Fachgebiet]([Fach_id] int Identity, [Student_id] int, [Note] int, CONSTRAINT [PK_Fach] PRIMARY KEY ([Fach_id]))"
              cmd.ExecuteNonQuery()
            End Using
          End Using
        End Sub
    
        ''' <summary>
        ''' Load jpg and save inti Table1
        ''' </summary>
        Friend Sub SaveData()
          Using cn As New SqlConnection(My.Settings.cnSQL)
            cn.Open()
            ' cmd1 für Master-Datensatz (Student)
            Using cmd1 As New SqlCommand("", cn)
              cmd1.CommandText = "INSERT INTO dbo.Student (Name) Values (@Name); SELECT Scope_Identity()"
              cmd1.Parameters.Add("@Name", SqlDbType.NVarChar)
              ' cmd2 für Child-Datensatz (Fachgebiet)
              Using cmd2 As New SqlCommand("INSERT INTO dbo.Fachgebiet (Student_id, Note) Values (@Student_id, @Note)", cn)
                cmd2.Parameters.Add("@Student_id", SqlDbType.Int)
                cmd2.Parameters.Add("@Note", SqlDbType.Int)
                ' Schleife für das Hinzufügen von mehreren Master-Datensätzen
                For i = 1 To 5
                  cmd1.Parameters("@Name").Value = $"Name {i}"
                  Dim id = cmd1.ExecuteScalar
                  ' dazu einen Child-Datensatz hinzufügen
                  cmd2.Parameters("@Student_id").Value = id
                  cmd2.Parameters("@Note").Value = i
                  cmd2.ExecuteNonQuery()
                Next
              End Using
            End Using
          End Using
        End Sub
    
        ''' <summary>
        ''' Test, display inserted records
        ''' </summary>
        Friend Sub Test()
          Using cn As New SqlConnection(My.Settings.cnSQL)
            cn.Open()
            Using cmd As New SqlCommand("SELECT Student.Name, Fachgebiet.Note FROM dbo.Student INNER JOIN dbo.Fachgebiet ON Student.Student_id = Fachgebiet.Student_id", cn)
              Dim rdr = cmd.ExecuteReader
              While rdr.Read
                Console.WriteLine($"Name: {rdr(0)}, Note: {rdr(1)}")
              End While
            End Using
          End Using
        End Sub
    
      End Class
    
    End Module


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks


    Donnerstag, 19. September 2019 03:36
  • Hallo!

    Da Du explizit nach dem SQL-Code fragst, hier ein vereinfachtes Beispiel (weniger Spalten und ohne PK und FK):

    Create table #Student (Student_id int identity, Vorname varchar(20), Email varchar(20)) ;
    Create table #Fachgebiete (Fach_id int identity, Student_id int, LastVisit date, Anzahl_der_Besuche int , Note decimal(3,2)) ;
    
    Insert into #Student(Vorname, Email) values ('Rheinschiffer', 'r@test.de');
    Insert into #Fachgebiete(Student_id, LastVisit, Anzahl_der_Besuche, Note) 
    Select Student_id, GETDATE() as LastVisit, 1 as Anzahl_der_Besuche, 1.0 as Note
    from #Student
    where Vorname = 'Rheinschiffer';
    
    Select *
    from #Student;
    Select *
    from #Fachgebiete;
    
    go
    drop table #Student;
    drop table #Fachgebiete;
    HTH!


    Einen schönen Tag noch, Christoph - http://www.insidesql.org/blogs/cmu

    Donnerstag, 19. September 2019 06:01
  • Vielleicht besser so:

    Insert into #Student(Vorname, Email) values ('Rheinschiffer', 'r@test.de');
    Insert into #Fachgebiete (@@IDENTITY, LastVisit, Anzahl_der_Besuche, Note)

    @@IDENTITY: liefert den letzten erzeugten Identity-Wert.

    Donnerstag, 19. September 2019 15:11
  • @@IDENTITY: liefert den letzten erzeugten Identity-Wert.

    Hi,
    @@Identity bringt nur den richtigen Wert, wenn keine Trigger eingesetzt werden, die ggf. auch ein Insert mit Autowert in einer anderen Tabelle ausführen. Besser ist da Scope_Indentity().

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Donnerstag, 19. September 2019 15:36
  • Ich hatte bewusst auf die Ermittlung des IDENTITY-Wertes über Funktionen verzichtet, da ja der Student nur einmal angelegt wird, aber im Laufe seines Lebens mehrfach Noten bekommt. 


    Einen schönen Tag noch, Christoph - http://www.insidesql.org/blogs/cmu

    Freitag, 20. September 2019 06:33
  • Ja, aber an deinem Beispiel hast du leider nicht erklärt, wo denn für den 2. Insert die Student_Id herkommen soll.
    Freitag, 20. September 2019 13:35
  • Ich dachte schon.

    Select Student_id
    from #Student
    where Vorname = 'Rheinschiffer';

    angereichert mit den anderen Werten für das Insert.


    Einen schönen Tag noch, Christoph - http://www.insidesql.org/blogs/cmu

    Freitag, 20. September 2019 13:52
  • Wäre ja mal schön, wenn der

    select * from final table (insert ....)

    im SQL-Server realisiert würde. Dann könnte ich mir auch viele andere Workarounds einfach sparen.

    Freitag, 20. September 2019 14:09