我正在尝试创建一个对象变量,该变量将保存来自 执行SQL任务 的集合。此集合将在整个ETL包中用于多个 脚本任务 。
问题是,在第一个 脚本任务 的第一个Fill
之后,对象变量变为空。这是关于我如何将变量用于DataTable的代码:
try
{
DataTable dt = new DataTable();
OleDbDataAdapter da = new OleDbDataAdapter();
da.Fill(dt, Dts.Variables["reportMetrics"].Value);
Dts.TaskResult = (int)ScriptResults.Success;
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
Dts.TaskResult = (int)ScriptResults.Failure;
}
在整个ETL包中, 脚本任务 组件将拥有这段代码。由于变量在第一个Fill
之后变空,我无法重用对象变量。
我猜测Fill方法与此有关。
谢谢!
答案 0 :(得分:1)
您的Dts.Variables["reportMetrics"].Value
对象看起来像DataReader
个对象。此对象允许对数据进行只进,只读访问。您无法使用DataReader填充DataTable两次。要完成您的任务,您需要创建另一个执行此处描述的脚本任务:它将Reader读取到DataTable
对象,并将此DataTable
对象存储在另一个类型为Object的Dts.Variable
中。
Dts.Variables["reportMetricsTable"].Value = dt
之后,如果修改数据,所有子结果脚本任务都应创建此表的副本,如果不修改数据,则直接使用它。
DataTable dtCopy = (Dts.Variables["reportMetricsTable"].Value as DataTable).Copy()
答案 1 :(得分:0)
我有类似的情况。虽然我认为您可以使用SELECT COUNT(*)查询执行SQL任务并将结果分配给SSIS变量,但我所做的是创建一个名为totalCount的int SSIS变量,其原始值为0.我希望总计数为是> 0(否则,我没有任何东西可以迭代)所以我在我的脚本任务中创建了一个if语句。如果值为零,我假设totalCount尚未初始化,因此我使用您使用的相同代码(使用Fill方法)。否则(即,在进一步的迭代中),我跳过该部分并继续使用totalCount变量。这是代码块。希望它有所帮助:
if ((int)Dts.Variables["User::totalCount"].Value == 0) // if the total count variable has not been initialized...
{
System.Data.OleDb.OleDbDataAdapter da = new System.Data.OleDb.OleDbDataAdapter();
DataTable stagingTablesQryResult = new DataTable();
da.Fill(stagingTablesQryResult, Dts.Variables["User::stagingTablesQryResultSet"].Value); // to be used for logging how many files are we iterating. It may be more efficient to do a count(*) outside this script and save the total number of rows for the query but I made this as proof of concept for future developments.
Dts.Variables["User::totalCount"].Value = stagingTablesQryResult.Rows.Count;
}
Console.WriteLine("{0}. Looking for data file {0} of {1} using search string '{2}'.", counter, Dts.Variables["User::totalCount"].Value, fileNameSearchString);
答案 2 :(得分:0)
优秀
这帮助我解决了构建myt ETL平台的问题。
本质上,我执行SQL任务以构建任务数据集,其中存在一些内联转换和规则,这些规则和规则将相关任务放在了首位,出于明显的原因,我只希望每次执行一次。
然后我需要从数据集中获取唯一的ProcessID(以在For Each循环中使用)
在FEL中,我想从原始数据集中获取相关记录,然后进行进一步的FEL流程。
对于数据集的第二次执行,我面临着相同的“空数据集”。
我认为我会尝试分享自己的解决方案以帮助他人
您需要添加命名空间
使用System.Data.OleDb;
进入脚本
获取数据集
执行SQL-获取数据并传递给变量对象
拉动Ds Declare the Variable Objects
public void Main()
{
DataTable dt = new DataTable();
OleDbDataAdapter da = new OleDbDataAdapter();
//Read the original table
da.Fill(dt, Dts.Variables["Tbl"].Value);
//Push to a replica
Dts.Variables["TblClone"].Value = dt;
Dts.TaskResult = (int)ScriptResults.Success;
}
构建过程列表 通过过滤数据集中的Rank字段来获取ProcessID(和名称)的列表
public void Main()
{ //Take a copy of the Cloned Dataset
DataTable dtRead = (Dts.Variables["TblClone"].Value as DataTable).Copy();
//Lock the output object variable
Dts.VariableDispenser.LockForWrite("User::ProcTbl");
//Create a data table to place the results into which we can write to the output object once finished
DataTable dtWrite = new DataTable();
//Create elements to the Datatable programtically
//dtWrite.Clear();
dtWrite.Columns.Add("ID", typeof(Int64));
dtWrite.Columns.Add("Nm");
//Start reading input rows
foreach (DataRow dr in dtRead.Rows)
{
//If 1st col from Read object = ID var
if (Int64.Parse(dr[9].ToString()) == 1) //P_Rnk = 1
{
DataRow newDR = dtWrite.NewRow();
newDR[0] = Int64.Parse(dr[0].ToString());
newDR[1] = dr[4].ToString();
//Write the row
dtWrite.Rows.Add(newDR);
}
}
//Write the dataset back to the object variable
Dts.Variables["User::ProcTbl"].Value = dtWrite;
Dts.Variables.Unlock();
Dts.TaskResult = (int)ScriptResults.Success;
}
从ProcList构建任务列表
在For Each循环中循环处理ProcessID
..并映射Vars
构建TL脚本 这将为您动态生成输出(请注意,尽管还没有对其进行广泛的测试,但是这对我来说仍然有效,因此,如果它不起作用...。 您会看到我已经注释掉了一些Debug内容
public void Main()
{
//Clone the copied table
DataTable dtRead = (Dts.Variables["TblClone"].Value as DataTable).Copy();
//Read the var to filter the records by
var ID = Int64.Parse(Dts.Variables["User::ProcID"].Value.ToString());
//Lock the output object variable
Dts.VariableDispenser.LockForWrite("User::SubTbl");
//Debug Test the ProcID being passed
//MessageBox.Show(@"Start ProcID = " + ID.ToString());
//MessageBox.Show(@"TblCols = " + dtRead.Columns.Count);
//Create a data table to place the results into which we can write to the output object once finished
DataTable dtWrite = new DataTable();
//Create elements to the Datatable programtically
//dtWrite.Clear();
foreach (DataColumn dc in dtRead.Columns)
{
dtWrite.Columns.Add(dc.ColumnName, dc.DataType);
}
MessageBox.Show(@"TblRows = " + dtRead.Rows.Count);
//Start reading input rows
foreach (DataRow dr in dtRead.Rows)
{
//If 1st col from Read object = ID var
if (ID == Int64.Parse(dr[0].ToString()))
{
DataRow newDR = dtWrite.NewRow();
//Dynamically create data for each column
foreach (DataColumn dc in dtRead.Columns)
{
newDR[dc.ColumnName] = dr[dc.ColumnName];
}
//Write the row
dtWrite.Rows.Add(newDR);
//Debug
//MessageBox.Show(@"ProcID = " + newDR[0].ToString() + @"TaskID = " + newDR[1].ToString() + @"Name = " + newDR[4].ToString());
}
}
//Write the dataset back to the object variable
Dts.Variables["User::SubTbl"].Value = dtWrite;
Dts.Variables.Unlock();
Dts.TaskResult = (int)ScriptResults.Success;
}
对于每个循环容器
FEL Cont Collection N.B.不要忘记在变量映射中映射项目
现在您可以使用记录并对该数据进行处理 我将Msg Loop脚本包含为一个简单的数据检查...实际上,它会关闭并触发其他进程,但是尽管Id包含了它,但只是为了帮助您进行数据检查
消息循环
消息循环脚本
public void Main()
{
// TODO: Add your code here
MessageBox.Show("ID = " + Dts.Variables["User::ProcID"].Value + ", and val = " + Dts.Variables["User::TaskID"].Value, "Name = Result");
Dts.TaskResult = (int)ScriptResults.Success;
}
希望可以帮助某人解决问题(希望在一个工作日左右解决这个问题:/