【问题标题】:Having issues importing Excel data into existing SQL Server table using SSIS script task (VB)使用 SSIS 脚本任务 (VB) 将 Excel 数据导入现有 SQL Server 表时遇到问题
【发布时间】:2019-07-06 15:15:24
【问题描述】:

我已经成功地从 Excel 文件中的表中加载了数据表对象。如何在 UPDATE 查询中使用此数据表对象来更新现有 SQL Server 表?

我遇到这个错误:

调用的目标已抛出异常。

在 System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) 在 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(对象 obj,对象 [] 参数,对象 [] 参数) 在 System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,Binder binder,Object[] 参数,CultureInfo 文化) 在 System.RuntimeType.InvokeMember(字符串名称、BindingFlags bindingFlags、Binder binder、Object 目标、Object[] providedArgs、ParameterModifier[] 修饰符、CultureInfo 文化、String[] namedParams) 在 Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine.ExecuteScript()

Public Sub Main()

    Dim fileToTest As String
    Dim SheetName As String
    Dim connectionString As String
    Dim excelConnection As OleDbConnection
    Dim excelCommand As OleDbCommand
    Dim ODA As OleDbDataAdapter
    Dim dtExcel As New DataTable()
    Dim SQLConn As SqlClient.SqlConnection
    Dim SQLCmd As SqlClient.SqlCommand
    Dim SQLPara As SqlClient.SqlParameter

    'open a connection to the excel file
    fileToTest = "C:\Users\testuser\Documents\test\mytestfile.xls"
    connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source=" &
    fileToTest & ";Extended Properties=""Excel 8.0;HDR=YES;IMEX=1"""
    excelConnection = New OleDbConnection(connectionString)
    excelConnection.Open()

    'open a SQL connection to the LRPSF_Source_DB SQL Server DB
    connectionString = "Data Source=mysqlserver.net\sqlentdb1d;Trusted_Connection=True;DATABASE=LRPSF_Source_DB;CONNECTION RESET=FALSE"
    SQLConn = New SqlClient.SqlConnection(connectionString)
    SQLConn.Open()

    'fetch the data from TEST table in Excel file using a command query and store in datatable object
    SheetName = "TEST$"
    excelCommand = excelConnection.CreateCommand()
    excelCommand.CommandText = "SELECT * FROM [" & SheetName & "]"
    excelCommand.CommandType = CommandType.Text
    ODA = New OleDbDataAdapter(excelCommand)
    ODA.Fill(dtExcel) '<- this datatable object is filled with the data successfully

    'using the dtExcel datatable as a table input, update the existing dbo.TEST_INPUT_SIMPLE SQL Server table
    SQLCmd = SQLConn.CreateCommand()
    SQLCmd.CommandText = "UPDATE TIS SET TIS.MY_COLUMN = TISX.MY_COLUMN " &
                         "FROM dbo.TEST_INPUT_SIMPLE TIS INNER JOIN @source AS TISX " &
                         "ON TIS.UPDATE_ID = TISX.UPDATE_ID"
    SQLCmd.CommandType = CommandType.Text
    SQLCmd.Parameters.AddWithValue("@source", dtExcel).SqlDbType = SqlDbType.Structured
    SQLCmd.ExecuteNonQuery() '<-- the program errors on this line

    Dts.TaskResult = ScriptResults.Success

End Sub

【问题讨论】:

    标签: sql-server excel vb.net ssis script-task


    【解决方案1】:

    更新 1

    我认为问题在于您没有在 SQL Server 中声明表结构。而不是您使用 SqlDbType.Structured 而不指定类型名称:

    SQLCmd.Parameters.AddWithValue("@source", dtExcel).SqlDbType = SqlDbType.Structured
    

    有关如何将数据表作为参数传递给 SQL Server 的更多信息,请查看以下 SO 问题:

    此外,在link you have mentioned in your comments 中,他们使用dbo.tStudent 作为类型名称:

    param.SqlDbType = SqlDbType.Structured;
    param.TypeName = "dbo.tStudent";
    

    初步回答

    如果您希望通过加入 Excel 文件来更新 SQL 表,那么这不是正确的方法。您以这种方式将表作为参数传递。将 Excel 表与 SQL 表连接的方法有很多:

    在 SQL Server 中

    在 SSIS 中

    在 VB/C# 中

    我没有在这个答案中提供太多细节,但我试图就比脚本任务更好地实现目标的方法提供一些见解。每个链接都包含您需要的信息以及更多信息

    【讨论】:

    • vb 的第三个链接中的代码看起来不适合批量复制。它正在尝试做一个 reader.Read 循环并传递阅读器。甚至不确定那会做什么,但没有什么好处。
    • @Mary 我根本不喜欢这种方法。我采用 SSIS 方法。但我试图给出一些见解并展示可能的解决方案
    • @Hadi - 非常感谢您的帮助。你知道在这种情况下我将如何使用 VB 代码声明 TypeName 吗?我认为这可能是缺失的部分。我还将尝试首先在 SQL Server 中设置用户定义的 TableType 对象,然后将其作为脚本任务中的参数传递,如上面的链接中所述。
    • @JustinCR 使用 SQLCommand 和 executeNonQuery 方法。按照我提供的链接中提到的创建类型,您应该在其中描述数据表结构。
    • @JustinCR 还请注意,您收到的错误消息是脚本任务中引发的一般异常。阅读真实信息。添加try... Catch 块并使用catch 块内的Dts.FireError 方法重新抛出异常。
    【解决方案2】:

    我通过执行以下步骤解决了这个问题:

    1)在数据库中创建一个用户自定义的TableType:

    CREATE TYPE [dbo].[MyTableType] AS TABLE(
        [UPDATE_ID] NVARCHAR(255),
        [MY_COLUMN] NVARCHAR(255)
    )
    

    2) 创建一个包含先前创建的表类型和更新查询的存储过程:

    CREATE procedure UpdateDB
        @myTableType MyTableType readonly
    AS
    BEGIN
        UPDATE TIS SET TIS.MY_COLUMN = TISX.MY_COLUMN 
        FROM dbo.TEST_INPUT_SIMPLE TIS INNER JOIN @myTableType AS TISX 
        ON TIS.UPDATE_ID = TISX.UPDATE_ID
    END
    

    3) 使用VB脚本任务,获取Excel数据并运行存储过程:

    Public Sub Main()
    
        Dim fileToTest As String
        Dim SheetName As String
        Dim connectionString As String
        Dim excelConnection As OleDbConnection
        Dim excelCommand As OleDbCommand
        Dim ODA As OleDbDataAdapter
        Dim dtExcel As New DataTable()
        Dim SQLConn As SqlClient.SqlConnection
        Dim SQLCmd As SqlClient.SqlCommand
    
        'open a connection to the excel file'
        fileToTest = "C:\Users\testuser\Documents\test\mytestfile.xls"
        connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source=" &
        fileToTest & ";Extended Properties=""Excel 8.0;HDR=YES;IMEX=1"""
        excelConnection = New OleDbConnection(connectionString)
        excelConnection.Open()
    
        'open a SQL connection to the LRPSF_Source_DB SQL Server DB'
        connectionString = "Data Source=mysqlserver.net\sqlentdb1d;Trusted_Connection=True;DATABASE=LRPSF_Source_DB;CONNECTION RESET=FALSE"
        SQLConn = New SqlClient.SqlConnection(connectionString)
        SQLConn.Open()
    
        'fetch the data from TEST table in Excel file using a command query and store in datatable object'
        SheetName = "TEST$"
        excelCommand = excelConnection.CreateCommand()
        excelCommand.CommandText = "SELECT * FROM [" & SheetName & "]"
        excelCommand.CommandType = CommandType.Text
        ODA = New OleDbDataAdapter(excelCommand)
        ODA.Fill(dtExcel) 'object is filled with Excel data'
    
        'load the dtExcel object into @myTableType object and run the stored procedure'
        SQLCmd = SQLConn.CreateCommand() 
        SQLCmd.CommandText = "[dbo].[UpdateDB]"
        SQLCmd.CommandType = CommandType.StoredProcedure
        SQLCmd.Parameters.AddWithValue("@myTableType", dtExcel) 
        SQLCmd.ExecuteNonQuery() 'run the stored procedure containing the update query'
    
        Dts.TaskResult = ScriptResults.Success
    
    End Sub
    

    感谢您的帮助!

    【讨论】:

    • 我认为您应该接受或投票赞成另一个答案,因为它解决了问题。您可以留下答案以提供更多详细信息。但似乎问题已根据 Hadi 回答中的 Update 部分解决
    • Hadi 的回答非常有帮助,因为它引导我利用存储的表类型和过程作为起点。但是,它缺少通过脚本任务执行它所需的额外 VB 代码,这是任务执行的原始方法。因此,我认为我的答案是在这种情况下的完整答案。
    • @JustinCR 您有权接受自己的答案。很高兴解决问题。如果有帮助并接受您自己的答案,您可以投票赞成。祝你好运
    • @JustinCR 出于这个原因,您应该接受您的回答并投票赞成另一个,以提及您拥有完整的版本,但另一个很有帮助。
    • 我对哈迪的回答投了赞成票,因为它非常有帮助,并接受了我的最终答案。如果还有什么我需要做的,请告诉我。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多