【问题标题】:Inserting multiple values into a SQL database from EXCEL through VBA script通过 VBA 脚本从 EXCEL 将多个值插入 SQL 数据库
【发布时间】:2013-12-13 07:26:45
【问题描述】:

只是试图通过 VBA 脚本将 5 个单元格中的数据插入到 SQL server 08 数据库的列中。

所以基本上我有 1 个有 4 列的表,我想一次将多组数据插入到列中,这会将数据插入到 DB 中,结果如下..

Server Name     Middleware  Version License 
TEST6           Testing     1       1
TEST6           Testing1    1       1
TEST6           Testing2    1       1
TEST6           Testing3    1       1

我知道下面代码中的值不正确,但是在执行 VBA 脚本时我收到了错误消息(在 vba 代码下面)。

Dim val1 As String, val2 As String, val3 As String, val4 As String

val1 = Range("B126").Value
val2 = Range("C126").Value
val3 = Range("C127").Value
val4 = Range("D126").Value

conn.Open sConnString

Dim item As String
item4 = "INSERT INTO [IndustrialComp].[dbo].[Middleware]("
item4 = item4 & "  [server_name],[middleware],[middlware],[version]"

item4 = item4 & "  )Values("
item4 = item4 & "  '" & val1 & "', '" & val2 & "', '" & val3 & "','" & val4 & "')"

conn.Execute item4

End Sub

消息 264,第 16 级,状态 1,第 1 行 在 SET 子句中多次指定列名“中间件”。在同一个 SET 子句中,一个列不能被分配多个值。修改 SET 子句以确保一列只更新一次。如果 SET 子句更新视图的列,则列名“中间件”可能会在视图定义中出现两次。

【问题讨论】:

    标签: sql sql-server vba sql-server-2008 excel


    【解决方案1】:

    我相信您在 INSERT 语句中指定的列是重复的,因此不正确。 试试:

    item4 = item4 & "  [server_name],[middleware],[version],[license]"
    

    更新: 您的 SQL 语句应如下所示:

    INSERT INTO [IndustrialComp].[dbo].[Middleware]([server_name],[middleware],[version],[license])
    VALUES ('TEST6','Testing',1,1)
          ,('TEST6','Testing1',1,1)
          ,('TEST6','Testing2',1,1)
          ,('TEST6','Testing3',1,1)
    

    因此,您必须为要插入的每一行重复括号之间的块。

    但是,您现在只有 4 个变量在您的解决方案中包含 4 个不同的值,因此您将永远无法插入这 4 个不同的行,因为您只能在单元格 B126、C126、 C127 和 D126。那可能是您要插入的第一行?还是您想自己将 1,2,3 添加到 Testing 并重复其他值? 请相应地解释并更新您的答案。

    【讨论】:

    • 但这只会进入 TEST6 测试 1 1...我需要它从 excel 表中将多行数据输入到数据库中。我知道这很简单,但只是让它在我的脑海中变得更难,而不是它实际上是什么。
    【解决方案2】:

    我假设数据在 Excel 中。如果是这样,只需遍历行。此外,您的 val1、val2 等似乎与示例不匹配。也许您的意思是 val3 是 D126,而 val4 是 E126。我会假设。这是更正后的代码:

    Dim sSQL as string
    Dim i as long
    
    i=0
    while ActiveSheet.Range("B126").offset(i,0).value <> "" 'stop when there is a blank cell
        i=i+1
        conn.Open sConnString
        sSQL = "INSERT INTO [IndustrialComp].[dbo].[Middleware]("
        sSQL = sSQL & "  [server_name],[middleware],[version],[license]"
        sSQL = sSQL & "  )Values ("
        sSQL = sSQL & "  '" & ActiveSheet.Range("B126").offset(i,0).Value & "', "
        sSQL = sSQL & "  '" & ActiveSheet.Range("C126").offset(i,0).Value & "', "
        sSQL = sSQL & "  '" & ActiveSheet.Range("D126").offset(i,0).Value & "', "
        sSQL = sSQL & "  '" & ActiveSheet.Range("E126").offset(i,0).Value & "' "
        sSQL = sSQL & ")"
    
        conn.Execute sSQL
    wend
    

    代码未经测试,但可以编译。

    【讨论】:

    • 为响应干杯。刚刚尝试了那里的代码(更改为需要等)...仍然收到错误消息“在 SET 子句中多次指定列名'中间件'”
    • 查看我的更改。不能在 Update 语句中多次指定单个列。我错过了[许可证]。修复了代码。看看这是否有效。
    【解决方案3】:

    如果您有多行数据,在对存储过程的一次调用中一次性插入所有行会更有效。为此,您将数据序列化为 xml,然后调用将 xml 作为字符串参数的存储过程。

    AFAIK 你不能序列化一个字典,但是你可以序列化一个列表。

    所以我建议您遍历您的字典(字典列表),用适当的值填充一个列表。我倾向于为此使用结构,但简单的类也可以正常工作,例如:

    Public Class DBData
        Public pKey As Integer
        Public pValue As Double
        Public Sub New(key As Integer, val As Double)
            pKey = key
            pValue = val
        End Sub
        Public Sub New()
            pKey = 0
            pValue = 0.0
        End Sub
    End Class
    

    创建您的列表并填写它,例如:

    Dim myList As New List(Of DBData)
    For Each kvPair In dict
        myList.Add(New DBData(kvPair.Key, kvPair.Value))
    Next
    

    现在来序列化一点魔法:

    Dim sw As New StringWriter
    Dim serializer As New XmlSerializer(GetType(List(Of DBData)))
    Dim ns As New XmlSerializerNamespaces()
    serializer.Serialize(sw, myList)
    
    Dim xml As String
    xml = sw.ToString
    Dim pos As Integer
    
    pos = xml.IndexOf("<Array")
    xml = xml.Substring(pos)
    

    注意这里我剥离了刚刚创建的 xml 的标题。那是因为如果包含标头,我永远无法让 SQL Server 工作 - 你可能可以,我只是看起来不够努力。

    我们这样调用存储过程(显然将连接字符串更改为适合您的字符串):

    Using conn As New SqlConnection("Integrated Security=true; Initial Catalog=dbname; Data Source=servername")
        Using cmd As New SqlCommand("uspDBDataInsert", conn)
            cmd.CommandType = CommandType.StoredProcedure
            Dim param As SqlParameter
            param = cmd.CreateParameter
            param.ParameterName = "@dbdata"
            param.DbType = DbType.String
            param.Value = xml
            cmd.Parameters.Add(param)
            conn.Open()
            cmd.ExecuteNonQuery()
            conn.Close()
        End Using
    End Using
    

    对于 SQL Server,所需的过程如下所示:

    CREATE PROCEDURE [dbo].[uspDBDataInsert] 
        -- Add the parameters for the stored procedure here
        @dbdata varchar(MAX)
    
    AS
    
    BEGIN try
        -- SET NOCOUNT ON added to prevent extra result sets from
        -- interfering with SELECT statements.
        SET NOCOUNT ON;
    
        declare @idoc int
    
        --Create an internal representation of the XML document
        EXEC sp_xml_preparedocument @idoc OUTPUT, @dbdata
    
        insert into DBData
        (
            id, rowvalue    
        )
        select
            pKey,pValue
        FROM OPENXML (@idoc, '/ArrayOfDBData/DBData',2)
        WITH (
            pKey int,
            pValue float
        )
        select @@ROWCOUNT
    
    end try
    
    begin catch
        declare @msg nvarchar(200)
        SELECT @msg = ('Error during insert of DBData...')
    end catch
    

    显然,您需要将 ArrayOf 更改为您的班级名称,当然还要使用您自己的表格。

    虽然我在这里只展示了一个简单的键/值对,但您可以以完全相同的方式填充多列表。

    需要注意的一点:你的类/结构必须在公共模块中是公共的,否则序列化将不起作用。此外,如果你为一个类提供你自己的参数构造函数(就像我一样),你还必须提供一个无参数的构造函数,否则序列化器将再次反对。

    HTH

    附录

    我忘了说,为了让 VB 工作你需要:

    Imports System.IO
    Imports System.Xml.Serialization
    Imports System.Data.SqlClient
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多