在 SQL/Vb.net 中的多个表之间填充主键/外键

Posted

技术标签:

【中文标题】在 SQL/Vb.net 中的多个表之间填充主键/外键【英文标题】:Populating Primary/foreign keys between multiple tables in SQL/Vb.net 【发布时间】:2019-01-29 10:09:15 【问题描述】:

我正在创建一个程序,用户可以在其中上传歌曲,并且这些歌曲的元数据(例如其专辑或艺术家)记录在关系 sql 数据库中。我当前的表设置包含 3 个表 - Song_DB、Album_DB、Artist_DB。

SONG_DB:

CREATE TABLE [dbo].[SONGS_DB] (
[SONG_ID]          INT         IDENTITY (1, 1) NOT NULL,
[SONG_NAME]        NCHAR (100) NOT NULL,
[ARTIST_ID]        INT         NULL,
[ALBUM_ID]         INT         NULL,
[SONG_LENGTH]      TIME (0)    NOT NULL,
[SONG_PLAYLIST_ID] INT         NULL,
PRIMARY KEY CLUSTERED ([SONG_ID] ASC),
CONSTRAINT [FK_SONGS_DB_ToARTIST] FOREIGN KEY ([ARTIST_ID]) REFERENCES [dbo].[ARTIST_DB] ([ARTIST_ID]),
CONSTRAINT [FK_SONGS_DB_ToALBUM] FOREIGN KEY ([ALBUM_ID]) REFERENCES [dbo].[ALBUM_DB] ([ALBUM_ID]),
CONSTRAINT [FK_SONGS_DB_ToSONG_PLAYLIST] FOREIGN KEY ([SONG_PLAYLIST_ID]) REFERENCES [dbo].[SONG_PLAYLIST] ([SONG_PLAYLIST_ID])

Artist_DB

CREATE TABLE [dbo].[ARTIST_DB] (
    [ARTIST_ID] INT  IDENTITY (1, 1) NOT NULL,
    [SONG_ID]   INT  NULL,
    [NAME]      TEXT NULL,
    PRIMARY KEY CLUSTERED ([ARTIST_ID] ASC),
    CONSTRAINT [FK_ARTIST_DB_ToSONGS_DB] FOREIGN KEY ([SONG_ID]) REFERENCES [dbo].[SONGS_DB] ([SONG_ID])
);

专辑数据库

CREATE TABLE [dbo].[ALBUM_DB] (
[ALBUM_ID] INT         IDENTITY (1, 1) NOT NULL,
[SONG_ID]  INT         NULL,
[NAME]     NCHAR (100) NULL,
PRIMARY KEY CLUSTERED ([ALBUM_ID] ASC),
CONSTRAINT [FK_ALBUM_DB_SONGS] FOREIGN KEY ([SONG_ID]) REFERENCES [dbo].[SONGS_DB] ([SONG_ID])

);

一旦上传歌曲并将元数据收集到变量中,我会尝试写入表格。我已经写下了实际的写作,但我正在努力弄清楚如何填充外键表。例如,使用以下代码,在 Artist/album_DB 中既不会填充 song_ID,在 Song_DB 中也不会填充 Album/artist_ID-

   Dim SQLcon As New SqlConnection With .ConnectionString = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\coolj\OneDrive\Documents\Loop\Loop\Songs_SQL.mdf;Integrated Security=True"

                Dim SQLCmd As SqlCommand
                Dim SQLCmd2 As SqlCommand
                Dim SQLCmd3 As SqlCommand
                Dim SQLCmd4 As SqlCommand
                Dim SQLCmd5 As SqlCommand
                Dim SQLCmd_SID As SqlCommand
                Dim SQLCmd_ARID As SqlCommand
                Dim SQLCmd_ALID As SqlCommand
                Dim SQLCmd_ARID2 As SqlCommand
                Dim SQLCmd_ALID2 As SqlCommand
                Dim SID
                Dim ARID
                Dim ALID
                SQLcon.Open()
                SQLCmd = New SqlCommand("INSERT INTO SONGS_DB (SONG_NAME, SONG_LENGTH) VALUES (@SONG_NAME, @SONG_LENGTH)", SQLcon)
                SQLCmd.Parameters.AddWithValue("@SONG_NAME", Title)
                SQLCmd.Parameters.AddWithValue("@SONG_LENGTH", Duration)
                SQLCmd_SID = New SqlCommand("SELECT max(SONG_ID) FROM SONGS_DB", SQLcon)


                If SID = "" Then
                    SID += 1

                Else
                    SID = SQLCmd_SID.ExecuteScalar()
                    SID = Convert.ToInt32(SID)
                End If



                If Album IsNot "" Then
                    SQLCmd2 = New SqlCommand("INSERT INTO ALBUM_DB (NAME) VALUES (@NAME)", SQLcon)
                    SQLCmd2.Parameters.AddWithValue("@NAME", Album)
                    'SQLCmd2.Parameters.AddWithValue("@SONG_ID", SID)
                End If

                If Artist IsNot "" Then
                    SQLCmd3 = New SqlCommand("INSERT INTO ARTIST_DB (NAME) VALUES (@NAME)", SQLcon)
                    SQLCmd3.Parameters.AddWithValue("@NAME", Artist)
                    'SQLCmd3.Parameters.AddWithValue("@SONG_ID", SID)

                End If



                SQLCmd.ExecuteNonQuery()
                If Album IsNot "" Then
                    SQLCmd2.ExecuteNonQuery()
                End If
                If Artist IsNot "" Then
                    SQLCmd3.ExecuteNonQuery()
                End If

                If Artist IsNot "" Then
                    SQLCmd_ARID = New SqlCommand("SELECT max(ARTIST_ID) FROM ARTIST_DB", SQLcon)
                    If ARID = "" Then
                        ARID += 1

                    Else
                        ARID = SQLCmd_ARID.ExecuteScalar()
                        ARID = Convert.ToInt32(ARID)
                    End If
                    SQLCmd_ARID2 = New SqlCommand("UPDATE SONG_DB SET ARTIST_ID = (@ARTIST_ID) WHERE SONG_ID = (@SONG_ID)", SQLcon)
                    SQLCmd_ARID2.Parameters.AddWithValue("@ARTIST_ID", ARID)
                    SQLCmd_ARID2.Parameters.AddWithValue("@SONG_ID", SID)


                End If

                If Album IsNot "" Then
                    SQLCmd_ALID = New SqlCommand("SELECT max(ALBUM_ID) FROM ALBUM_DB", SQLcon)
                    If ALID = "" Then
                        ALID += 1

                    Else
                        ALID = SQLCmd_ARID.ExecuteScalar()
                        ALID = Convert.ToInt32(ARID)
                    End If
                    SQLCmd_ALID2 = New SqlCommand("UPDATE SONG_DB SET ARTIST_ID = (@ARTIST_ID) WHERE SONG_ID = (@SONG_ID)", SQLcon)
                    SQLCmd_ALID2.Parameters.AddWithValue("@ARTIST_ID", ARID)
                    SQLCmd_ALID2.Parameters.AddWithValue("@SONG_ID", SID)


                End If

                If Artist IsNot "" Then
                    SQLCmd_ARID2.ExecuteNonQuery()
                End If

                If Album IsNot "" Then
                    SQLCmd_ALID2.ExecuteNonQuery()
                End If
                SQLcon.Close()
            End If

任何想法我哪里出错了?提前致谢!

【问题讨论】:

您的数据库设计有缺陷。 SONG_ID 列不属于Artist_DBAlbum_DB。事实上,在现实世界中,同一首歌可能由多个艺术家演唱并出现在多张专辑中,而每个艺术家可能会演奏多首歌曲并制作多张专辑。我建议使用艺术家表、专辑表、歌曲表、艺术家和专辑之间的多对多桥接表,以及新表和歌曲表之间的多对多桥接表。 (继续)这将使您能够描述真实世界的情况,即同一首歌出现在两个不同艺术家的两张专辑中,或者两个艺术家一起创建专辑。 请开启 Option Strict。您可以在工具菜单 -> 选项 -> 项目和解决方案 -> VB 默认设置中找到此设置。这将使您避免在运行时出现错误。 If SID = "" Then SID += 1 什么是 SID?一个字符串?一个号码? Option Strict 会强制你将其声明为一种类型。 If Album IsNot "" Then 早在此之前就应该进行验证。 【参考方案1】:
            If Album IsNot "" Then
                SQLCmd2 = New SqlCommand("INSERT INTO ALBUM_DB (NAME) VALUES (@NAME)", SQLcon)
                SQLCmd2.Parameters.AddWithValue("@NAME", Album)
                'SQLCmd2.Parameters.AddWithValue("@SONG_ID", SID)
            End If

            If Artist IsNot "" Then
                SQLCmd3 = New SqlCommand("INSERT INTO ARTIST_DB (NAME) VALUES (@NAME)", SQLcon)
                SQLCmd3.Parameters.AddWithValue("@NAME", Artist)
                'SQLCmd3.Parameters.AddWithValue("@SONG_ID", SID)

            End If

您将这段代码的一半放在引号内。 替换为:

        If Album IsNot "" Then
            SQLCmd2 = New SqlCommand("INSERT INTO ALBUM_DB (NAME) VALUES (@NAME)", SQLcon)
            SQLCmd2.Parameters.AddWithValue("@NAME", Album)
            SQLCmd2.Parameters.AddWithValue("@SONG_ID", SID)
        End If

        If Artist IsNot "" Then
            SQLCmd3 = New SqlCommand("INSERT INTO ARTIST_DB (NAME) VALUES (@NAME)", SQLcon)
            SQLCmd3.Parameters.AddWithValue("@NAME", Artist)
            SQLCmd3.Parameters.AddWithValue("@SONG_ID", SID)

        End If

如 cmets 中所述,以下行没有向插入语句添加任何内容,因为语句中没有 @SONG_ID 参数。这也可能导致问题。

SQLCmd3.Parameters.AddWithValue("@SONG_ID", SID) SQLCmd2.Parameters.AddWithValue("@SONG_ID", SID)

【讨论】:

但是您正在添加不属于 Insert 语句的参数。

以上是关于在 SQL/Vb.net 中的多个表之间填充主键/外键的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate的表之间的关系

外键未填充主键值

主键和外键的区别:

今日刷题总结10

MySQL存储过程---涉及多个表之间的关联关系,且各表中具有相同的字段,以主键id 为例,一定要使用 xx.id加以区分

主键约束