如果源文件中不存在,ssis 添加具有默认值的列
Posted
技术标签:
【中文标题】如果源文件中不存在,ssis 添加具有默认值的列【英文标题】:ssis add column with default value if not present in source file 【发布时间】:2014-04-02 18:11:06 【问题描述】:我正在制作一个 SSIS 包,其中我将多个 Excel 文件传输到一个唯一的 Excel 文件中。
问题在于输入文件可能具有不同的结构(某些列可能不存在)。
我的 SSIS 结构是这样的:
-
一个 foreach 容器,一个接一个地获取每个文件
一个显示窗口窗体的脚本,允许我在变量中输入我的列的默认值
我的数据流任务
在我的数据流任务中,我想从 Excel 文件中获取值并将它们放入目标文件。 如果该列不存在,我希望数据流使用默认值创建一个新列。
我设法做到了,但我对“如果该列不存在”的事情有疑问。我添加了带有派生列的列,但是他如何首先检查源文件中是否不存在该列。我不想每次都输入默认值。如果该列存在,我想使用它而不是默认值。
感谢您的回答,
【问题讨论】:
您的意思是“某些列可能不存在”吗?而不是“某些行可能不存在”。请注意,如果您针对具有 X 列的 Excel 文件定义连接,并且随后需要读取 Y 列,则您的包将不起作用。你能确认源文件肯定是 XLSX/XLS 而不是 CSV 吗? 谢谢,那是列而不是行。我确认该文件是 xls 文件。我可以设置最小数据并收集 4 列并收集剩余的列(如果它们的名称合适)而不是等待 10 列广告管理丢失的列? 问题出在包中的 excel 源代码中。如果您针对 4 列 Excel 文件定义它并且您的循环尝试加载 10 列文件,它将失败 - 试试看。我这样做的方法是尝试事先计算出文件中有多少列并分支到适当的数据流。你知道你有多少种组合吗?是否只有两种类型的文件? 没有精确的文件类型。有些人会多一些,有些人会少一些。他们拥有的越多越好,但他们只能填写 3 个必填列,其他列需要按默认值填写。在其他情况下,我会有一些我不关心的列,但这不是问题。我读到也许脚本组件可以处理它,但我不熟悉使用脚本访问文件 您可以尝试按照以下方式选择所需的列:sqlserversolutions.blogspot.com.au/2009/02/…。这可以保证您的 Excel 源返回一致的列。您可能必须采用 try/catch 方法来获取所需的列,即数据流具有包含所有列的选择。如果失败,请尝试使用较少列的下一个选择。是的,您可以使用脚本,但您也可以在 SSIS 外部执行。 【参考方案1】:我通过使用脚本组件作为我的数据流源得到了答案。
这是我使用的结构
-
windowsForm 输入默认值和要读取的文件
数据流
脚本组件作为源
手动读取文件(通过 OleDB 连接器)并将其放入数据表中
如果该列存在于文件中,则检查 if 条件
如果该列不存在,则将其添加到数据表中
获取列号以便稍后写入
为可能不存在的每一列执行此操作
为数据表的每一行创建一个输出缓冲区行的for循环
在每一行中,写入相应的值:如果该列是手动创建的,则为默认值,否则为使用 datatable.Rows[row][column] 过程的原始值
最后,我的结构完全填充了默认值的原始列。
我首先在数据流任务之前在脚本任务中使用 windowsform 在这种形式中,我让用户通过 openfiledialog 选择文件,然后在 windowsform 上输入最终所需的默认值。
这是我在脚本组件中编写的代码的摘录。 我在变量中有默认值 我需要填写 uniqueRef、EAN 和名称:必填 但有时我可能在文件中填充了 value1 和/或 value2 和/或颜色。如果他们是我想得到他们的好价值。如果不是,我想为所有列设置一个默认值。
它可能没有经过优化,但可以完成工作(8 年没有开发并且第一次使用 C# 对我来说是一件相当困难的事情,但我别无选择,因为 SSIS 不想用 UI 来做)。
using System;
using System.Data;
using System.Windows.Forms;
using System.Data.OleDb;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
DataTable dt;
public override void PreExecute()
base.PreExecute();
/*
get the xls file based on the inputPath and put its data in a datatable
*/
String connString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Variables.InputPath + ";Extended Properties=\"Excel 8.0;IMEX=1\"";
OleDbConnection connection = new OleDbConnection(connString);
var DataAdapter = new OleDbDataAdapter("SELECT * FROM [ToImport$]", connection);
dt = new DataTable();
DataAdapter.Fill(dt);
base.CreateNewOutputRows();
public override void PostExecute()
base.PostExecute();
public override void CreateNewOutputRows()
// initialize booleans which will tell if a column was present in the orignial file or has been created
// data that don't have bool are considered as mandatory, program will fail if missing
bool value1bool = false;
bool value2bool = false;
bool colorbool = false;
// check if the column is in the original file. if not, set boolean to true and add the missing column to the datatable
if ((dt.Columns.Contains("Value1")) == false)
dt.Columns.Add(new DataColumn("Value1", typeof(string)));
value1bool= true;
if ((dt.Columns.Contains("Value2")) == false)
dt.Columns.Add(new DataColumn("Value2", typeof(string)));
value2bool = true;
if ((dt.Columns.Contains("Color")) == false)
dt.Columns.Add(new DataColumn("Color", typeof(string)));
colorbool = true;
//get the column number of each matching column name to be able to get values later
int colRef = dt.Columns.IndexOf("UniqueRef");
int colEan = dt.Columns.IndexOf("EAN");
int colName = dt.Columns.IndexOf("Article Name");
int colValue1 = dt.Columns.IndexOf("Value1");
int colValue2 = dt.Columns.IndexOf("Value2");
int colColor = dt.Columns.IndexOf("Color");
//for each row of the datatable
for (int i = 0; i < dt.Rows.Count; i++)
// adds values of each line to the output buffer corresponding to LOTS output columns
//generate a new row in the buffer
LotsOutputBuffer.AddRow();
//fill rows datas taking datas from the good column with a name matching
LotsOutputBuffer.RefUnique = dt.Rows[i][colRef].ToString();
LotsOutputBuffer.EAN= dt.Rows[i][colEan].ToString();
// if Value1 column is not in the input file, default value from windowsform is taken
if (Value1bool)
LotsOutputBuffer.Value1 = Variables.Value1Var;
else LotsOutputBuffer.Value1 = dt.Rows[i][colValue1].ToString();
// if Value2 column is not in the input file, default value from windowsform is taken
if (Value2bool)
LotsOutputBuffer.Value2 = Variables.Value2Var;
else LotsOutputBuffer.Value2=dt.Rows[i][colValue2].ToString();
ArticlesBuffer.Name = dt.Rows[i][colName].ToString();
// if Color column is not in the input file, default value from windowsform is taken
if (colorbool)
ArticlesBuffer.Color = Variables.colorVar;
else ArticlesBuffer.Color = dt.Rows[i][colColor].ToString();
【讨论】:
【参考方案2】:对于您的问题:如果您想做 foreach 容器,则 foreach 循环将不起作用。相反,我有另一个想法可以帮助您实现目标。
1) 源将是数据流任务中的 Excel 源,将导出列拖到 Excel 源之后 > 目标将是临时表中的物理表
注意:此临时表将在您的流程完成后被删除。
2) 第二个数据流将从您的临时表中读取文件,您可以编写 case 语句或定义完整的列名 ( SELECT COL1, COL12 from table)
而不是 (SELECT * FROM TABLE)
3) 拖动目标源将是您在原始任务中所做的。
【讨论】:
以上是关于如果源文件中不存在,ssis 添加具有默认值的列的主要内容,如果未能解决你的问题,请参考以下文章