查询值和目标字段的数量不同 - C# 脚本任务 SSIS - 使用动态列将 SQL Proc 的结果导出到 Excel

Posted

技术标签:

【中文标题】查询值和目标字段的数量不同 - C# 脚本任务 SSIS - 使用动态列将 SQL Proc 的结果导出到 Excel【英文标题】:Number of query values and destination fields are not the same - C# Script Task SSIS - Export Results of SQL Proc to Excel Using Dynamic Columns 【发布时间】:2020-04-28 09:07:39 【问题描述】:

我正在尝试在 SSIS 中编写一个脚本任务,该任务基于变量运行 SQL 过程,从结果中确定名称和列数,然后将其导出到 Excel 工作表中。这是基于 TechBrothersIT 网站/视频:http://www.techbrothersit.com/2016/03/how-to-create-excel-file-dynamically_21.html

错误“System.Data.OleDb.OleDbException (0x80040E14):查询值和目标字段的数量不同。”在它运行过程之后发生,因为它试图插入到它构建的表中。我试图寻找答案,但我还没有看到有人使用这样的动态列,所以所有为 INSERT 和 VALUES 部分指定列的答案都不适用(据我所知)。

正在运行的程序返回六列:Branch、Client、Hours、Gross Pay、WC Premium、GP$。在它动态构建后使用 messagebox.show 命令来构建表确认它正在使用这些值,拼写正确,并用括号括起来。因此,我认为我的问题出在 VALUES 部分,但我无法弄清楚。

我在这里做错了什么?

using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.IO;
using System.Data.OleDb;
using System.Data.SqlClient;

namespace ST_0493a2bda5424767ac07ca96649a95e2

    [Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
    public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
    

        public void Main()
        
            string datetime = DateTime.Now.ToString("yyyyMMddHHmmss");
            try
            
                //Declare Variables
                string ExcelFileName = Dts.Variables["User::ExcelFileName"].Value.ToString();
                string FolderPath = Dts.Variables["User::FolderPath"].Value.ToString();
                string StoredProcedureName = Dts.Variables["User::StoredProcedureName"].Value.ToString();
                string SheetName = Dts.Variables["User::SheetName"].Value.ToString();
                string StartDate = Dts.Variables["User::StartDate"].Value.ToString();
                string EndDate = Dts.Variables["User::EndDate"].Value.ToString();
                string DBName = Dts.Variables["User::DBName"].Value.ToString();
                string ServerName = Dts.Variables["User::ServerName"].Value.ToString();
                ExcelFileName = ExcelFileName + "_" + datetime;

                OleDbConnection Excel_OLE_Con = new OleDbConnection();
                OleDbCommand Excel_OLE_Cmd = new OleDbCommand();

                //Construct ConnectionString for Excel
                string connstring = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + FolderPath + ExcelFileName
                    + ".xlsx;Extended Properties=\"Excel 12.0 Xml;HDR=YES\";";

                //Drop Excel file if exists
                File.Delete(FolderPath + "\\" + ExcelFileName + ".xlsx");

                //USE ADO.NET Connection from SSIS Package to get data from table
                SqlConnection myADONETConnection = new SqlConnection("Data Source="+ServerName+";Initial Catalog="+DBName+";Integrated Security=true");                


                //Load Data into DataTable from SQL ServerTable
                string queryString = "EXEC  " + StoredProcedureName + " '" + StartDate + "', '" + EndDate + "', @RunInSSIS=1";
                SqlDataAdapter adapter = new SqlDataAdapter(queryString, myADONETConnection);
                DataSet ds = new DataSet();
                adapter.Fill(ds);

                //MessageBox.Show(queryString);

                //Get Header Columns
                string TableColumns = "";

                // Get the Column List from Data Table so can create Excel Sheet with Header
                foreach (DataTable table in ds.Tables)
                
                    foreach (DataColumn column in table.Columns)
                    
                        TableColumns += column + "],[";
                    
                

                // Replace most right comma from Columnlist
                TableColumns = ("[" + TableColumns.Replace(",", " NVARCHAR(255),").TrimEnd(','));
                TableColumns = TableColumns.Remove(TableColumns.Length - 2);
                MessageBox.Show(TableColumns);


                //Use OLE DB Connection and Create Excel Sheet
                Excel_OLE_Con.ConnectionString = connstring;
                Excel_OLE_Con.Open();
                Excel_OLE_Cmd.Connection = Excel_OLE_Con;
                Excel_OLE_Cmd.CommandText = "Create table " + SheetName + " (" + TableColumns + ")";
                Excel_OLE_Cmd.ExecuteNonQuery();


                //Write Data to Excel Sheet from DataTable Dynamically
                foreach (DataTable table in ds.Tables)
                
                    String sqlCommandInsert = "";
                    String sqlCommandValue = "";
                    foreach (DataColumn dataColumn in table.Columns)
                    
                        sqlCommandValue += dataColumn + "],[";
                    

                    sqlCommandValue = "[" + sqlCommandValue.TrimEnd(',');
                    sqlCommandValue = sqlCommandValue.Remove(sqlCommandValue.Length - 2);
                    sqlCommandInsert = "INSERT into " + SheetName + "(" + sqlCommandValue + ") VALUES(";

                    int columnCount = table.Columns.Count;
                    foreach (DataRow row in table.Rows)
                    
                        string columnvalues = "";
                        for (int i = 0; i < columnCount; i++)
                        
                            int index = table.Rows.IndexOf(row);

                            columnvalues += table.Rows[index].ItemArray[i];
                            columnvalues = "'" + columnvalues.Replace("'", "''") + "',";
                        
                        columnvalues = columnvalues.TrimEnd(',');

                        var command = sqlCommandInsert + columnvalues + ")";
                        Excel_OLE_Cmd.CommandText = command;
                        Excel_OLE_Cmd.ExecuteNonQuery();
                    

                
                Excel_OLE_Con.Close();
                Dts.TaskResult = (int)ScriptResults.Success;
            
            catch (Exception exception)
            

                // Create Log File for Errors
                using (StreamWriter sw = File.CreateText(Dts.Variables["User::FolderPath"].Value.ToString() + "\\" +
                    Dts.Variables["User::ExcelFileName"].Value.ToString() + datetime + ".log"))
                
                    sw.WriteLine(exception.ToString());
                    Dts.TaskResult = (int)ScriptResults.Failure;

                
            
        

        enum ScriptResults
        
            Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
            Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
        ;

    

【问题讨论】:

【参考方案1】:

我想通了。我在 for 循环的内部使用了 messagebox.show 来准确查看正在构建的内容,并且每次看到新列时都会在语句的开头添加一个单引号,如下所示: '''''''''[column]',[column2], etc...'

修复涉及在开始时将 columnvalues 设置为 ' 而不是空白,然后在内部循环中修改 columnvalues 以将 ',' 添加到末尾,最后在完成的语句末尾修剪掉多余的部分。我猜这可以用更干净的方法完成,但它仍然解决了我的问题:

foreach (DataRow row in table.Rows)
                    
                        string columnvalues = "'";
                        for (int i = 0; i < columnCount; i++)
                        
                            int index = table.Rows.IndexOf(row);

                            columnvalues += table.Rows[index].ItemArray[i];
                            columnvalues += "','";
                            //MessageBox.Show(columnvalues);
                        
                        columnvalues = columnvalues.TrimEnd('\'');
                        columnvalues = columnvalues.TrimEnd(',');

                        var command = sqlCommandInsert + columnvalues + ")";
                        //MessageBox.Show(command);

                        Excel_OLE_Cmd.CommandText = command;
                        Excel_OLE_Cmd.ExecuteNonQuery();
                    

【讨论】:

以上是关于查询值和目标字段的数量不同 - C# 脚本任务 SSIS - 使用动态列将 SQL Proc 的结果导出到 Excel的主要内容,如果未能解决你的问题,请参考以下文章

错误:查询值和目标字段的数量不同

查询值和目标字段的数量不相同

如何使 SSIS 脚本任务失败(使用 C#,2008)

Java string.split 与 C# Regex.split - 限制为一定数量的字段

性能调优 powershell 文本处理

mysql如何查询一个表里,同一字段不同条件数据数量?