我有一个SSIS包,我必须从excel表中选择一些值并将它们插入到SQL Server数据库表中,我通过执行sql任务来完成它。
这些是步骤:
例:
Foreach
迭代Select * from [GenDet$F3:F3]
例:
这是有效的 - 但问题是它正在采取的时间。对于3000个字段,整个过程需要50分钟来处理一个Excel文件。我必须在不到一分钟的时间内做到这一点。
请让我知道实现这一目标的最佳方法。
谢谢!
正如我在评论中提到的,我认为编写一个从excel单元读取数据的c#脚本并将它们分组到一个列表或DataTable然后执行一次Bulk插入将更具性能
首先,您必须导入Excel Interop程序集:
using Microsoft.Office.Interop.Excel;
using System.Data.SqlClient;
现在,您应该定义以下将excel列字母表转换为索引的函数:
private int ParseColHeaderToIndex(string colAdress)
{
int[] digits = new int[colAdress.Length];
for (int i = 0; i < colAdress.Length; i++)
{
digits[i] = Convert.ToInt32(colAdress[i]) - 64;
}
int mul = 1;
int res = 0;
for (int pos = digits.Length - 1; pos >= 0; pos--)
{
res += digits[pos] * mul;
mul *= 26;
}
return res;
}
以下函数用于对SQL执行批量插入操作
public void InsertToSQLUsingSQLBulk(System.Data.DataTable dt, string connectionstring, string Tablename)
{
try
{
using (var bulkCopy = new SqlBulkCopy(connectionstring, SqlBulkCopyOptions.KeepIdentity))
{
foreach (DataColumn col in dt.Columns)
{
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
}
bulkCopy.BulkCopyTimeout = 600;
bulkCopy.DestinationTableName = Tablename;
bulkCopy.WriteToServer(dt);
}
}
catch (Exception ex)
{
throw ex;
}
}
以下函数将excel路径和范围DataTable作为参数,并返回具有目标结构的DataTable(Id,AttributeKey,AttributeValue)
public System.Data.DataTable ReadFromExcel(System.Data.DataTable dtRanges,string strPath)
{
string num = "0123456789";
//Declare result datatable
System.Data.DataTable destination = new System.Data.DataTable();
destination.Columns.Add("Id");
destination.Columns.Add("AttributeKey");
destination.Columns.Add("AttributeValue");
//Decalre Interop Objects
Microsoft.Office.Interop.Excel.Application m_XlApp;
m_XlApp = new Microsoft.Office.Interop.Excel.Application();
m_XlApp.Visible = false;
m_XlApp.DisplayAlerts = false;
Workbook xlWbs = null;
xlWbs = m_XlApp.Workbooks.Open(strPath, Type.Missing, Type.Missing,
Type.Missing, "'", Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing);
xlWbs.DoNotPromptForConvert = true;
xlWbs.CheckCompatibility = false;
xlWbs.Application.DisplayAlerts = false;
//Loop over worksheets
foreach (Worksheet xlWks in xlWbs.Worksheets) {
string Name = xlWks.Name;
//Assing rows relevant to the current sheet
foreach (DataRow drRow in dtRanges.AsEnumerable().Where(x => x["Sheet_Name"].ToString() == Name))
{
string sheet = drRow["Sheet_Name"].ToString();
string range = drRow["Location_Value"].ToString();
string field = drRow["Field_Name"].ToString();
string id = drRow["Id"].ToString();
string rangeAlpha = range.Split(':')[0];
int rowidx = 0;
int colidx = 0;
foreach (char chr in num) {
rangeAlpha = rangeAlpha.Replace(chr, '\0');
}
rowidx = Int32.Parse(range.Split(':')[0].Replace(rangeAlpha, ""));
colidx = ParseColHeaderToIndex(rangeAlpha);
DataRow dr = destination.NewRow();
if (xlWks.Cells[rowidx, colidx] != null && (xlWks.Cells[rowidx, colidx] as Range).Value2 != null)
{
dr["AttributeValue"] = (string)(xlWks.Cells[rowidx, colidx] as Range).Value2;
}
else
{
dr["AttributeValue"] = "";
}
dr["AttributeKey"] = drRow["Field_Name"].ToString();
dr["Id"] = drRow["Id"].ToString();
destination.Rows.Add(dr);
}
}
xlWbs.Close(false, Type.Missing, Type.Missing);
m_XlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWbs);
System.Runtime.InteropServices.Marshal.ReleaseComObject(m_XlApp);
return destination;
}
public void Main(){
//Initialize ranges table
System.Data.DataTable ranges = new System.Data.DataTable();
ranges.Columns.Add("Id");
ranges.Columns.Add("Field_Name");
ranges.Columns.Add("Location_Value");
ranges.Columns.Add("Sheet_Name");
//Add rows or read them from database using SQLDataAdapter
//note that the destination table must exists in the database with identical columns of datatable
System.Data.DataTable destination = ReadFromExcel(ranges, "C:\\1.xlsx", "dbo.destination");
InsertToSQLUsingSQLBulk(destination, "Pass SQL Server destination connection string here");
}
您可以通过将所有工作表内容放在二维数组中来提高方法性能,然后循环遍历数组而不是在Excel工作表中循环。
Excel.Range targetCells = xlWks.UsedRange;
object[,] allValues = (object[,])targetCells.Cells.Value;
...
if (targetCells.Cells[rowidx, colidx] != null)
{
dr["AttributeValue"] = (string)(targetCells.Cells[rowidx, colidx] as Range).Value2;
}
else
{
dr["AttributeValue"] = "";
}
参考
考虑构建一个运行的select语句,一次获取所有记录。
根据您的图像,这样的事情:
select
(Select [Field1] from [GenDet$I3:I3]) as Field1
,(Select [Field2] from [GenDet$I4:I4]) as Field2
...
这是基于水平和列的。
或者你可以垂直
(Select [FieldName],[Field1] as Value from [GenDet$I3:I3]) as Field1
union all
(Select [Field2],* from [GenDet$I4:I4]) as Field2
...
我知道有3000左右,但你可以用字符串连接查询而不是简单地构建它。
只是一个想法。
这将减少执行时间,因为电子表格不会在每次迭代时打开和关闭。