查询值和目标字段的数量不同 - 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的主要内容,如果未能解决你的问题,请参考以下文章