6

在插入目标表期间,发生的任何错误都会重定向到 Errors 表,我们可以在其中看到ErrorCodeand ErrorColumn。问题是我们得到了一个在ErrorColumn包中任何地方都不存在的值。也就是说,没有一个列LineageID等于ErrorColumn

后来,在每一列中启用 NULL 条目时,我发现是哪一列导致了问题。当我分析数据流任务中的列时,它没有LineageIDErrorColumn. 例如,ErrorColumn报告的是 413,但LineageID在第一次合并时是 84,并且在各种排序过程中会发生变化。不管怎样,它永远不会变成 413。这个ErrorColumnID (413) 根本不存在,但它在错误重定向插入目标源(错误表)期间报告。

我检查了很多网站,但他们都建议通过ComponenteMetaData.InputCollectionComponentMetaData.OutputCollection在脚本任务中枚举,然后通过列枚举以查找LineageID,但没有任何成功。

正如我所说,我已经解决了这个问题,但是由于我们处于 ETL 流程的早期阶段,这可能会在其他一些情况下发生。如何解决这个问题?

4

3 回答 3

7

我正在复制我的答案,以便我们可以在网站上获得权威的问答

从SSIS中的Lineageid中查找列名的简单方法是什么

我记得说过这不会那么难,我可以在错误重定向中编写一些脚本来从输入集合中查找列名。

string badColumn = this.ComponentMetaData.InputCollection[Row.ErrorColumn].Name;

我了解到的是失败的列不在该集合中。好吧,但是报告的 ErrorColumn 并不是我所需要的。我找不到那个包,但这里有一个例子说明为什么我不能得到我需要的东西。希望你会有更好的运气。

这是一个简单的数据流,一旦由于被零除而命中派生列,就会产生错误。Derived 列生成一个新的输出列 (LookAtMe) 作为除法的结果。错误输出上的数据查看器告诉我失败的列是 73。使用上面的脚本逻辑,如果我尝试访问输入集合中的第 73 列,它将失败,因为它不在集合中。LineageID 73 是 LookAtMe 并且 LookAtMe 不在我的错误分支中,它仅在非错误分支中。

基本数据流

这是我的 XML 的副本,您可以看到,是的,outputColumn id 73 是 LookAtme。

<outputColumn id="73" name="LookAtMe" description="" lineageId="73" precision="0" scale="0" length="0" dataType="i4" codePage="0" sortKeyPosition="0" comparisonFlags="0" specialFlags="0" errorOrTruncationOperation="Computation" errorRowDisposition="RedirectRow" truncationRowDisposition="RedirectRow" externalMetadataColumnId="0" mappedColumnId="0"><properties>

不过,我真的很想要这些数据,而且我很聪明,所以我可以将所有结果重新组合在一起,然后有条件地将其拆分出来以得到它。问题是,Union All 是一个异步转换。异步转换导致数据从一组黄油复制到另一组黄油,从而导致...分配新的沿袭 ID,因此即使使用联合将两个流重新组合在一起,您也无法调用数据流链来查找原始沿袭 id,因为它位于不同的缓冲区中。

在这一点上,我承认失败并决定我可以在我的包中没有智能/有用的错误报告。

2012

SSIS 的 2012 版本改变了他们使用 LineageID 保持列同步的方式。它们不是将数字从源映射到接收器的组件,而是使用元素的文本表示。上面引用的 XML 现在看起来像

 <outputColumn
 refId="Package\DFT Generate Errors\DER Divide by SomeNumber.Outputs[Derived Column Output].Columns[LookAtMe]"
 dataType="i4"
 errorOrTruncationOperation="Computation"
 errorRowDisposition="RedirectRow"
 lineageId="Package\DFT Generate Errors\DER Divide by SomeNumber.Outputs[Derived Column Output].Columns[LookAtMe]"
 name="LookAtMe"
 truncationRowDisposition="FailComponent">

如果您现在查看 ErrorColumn,它们甚至没有引用文本 lineageid。相反,它们引用了第 6 列。如果我搜索源 XML,我不会在任何地方找到对第 6 列的引用。这一定是一些运行时的魔法。

在此处输入图像描述

不幸的是,最终结果是相同的 - 您无法访问错误列,因为它是在此组件中创建的,因为它仅存在于输出列集合中。它在错误列集合中不可用。

于 2013-12-03T13:51:29.827 回答
2

我意识到这是一个迟到的答案,但我是 SSIS 游戏的新手。我创建了一个解决方案

  1. 在包运行时工作(不预填充)
  2. 通过脚本任务和组件自动化
  3. 不涉及安装新程序集或自定义组件
  4. 很好地兼容 BIML

在此处查看完整的解决方案。

编辑

这是简短的版本。

  1. 创建 2 个对象变量,execsObj以及lineageIds
  2. 在控制流中创建脚本任务,为其提供对两个变量的读写访问权限
  3. 将以下代码插入您的脚本任务
Dictionary<int, string> lineageIds = null;

public void Main()
{
    // Grab the executables so we have to something to iterate over, and initialize our lineageIDs list
    // Why the executables?  Well, SSIS won't let us store a reference to the Package itself...
    Dts.Variables["User::execsObj"].Value = ((Package)Dts.Variables["User::execsObj"].Parent).Executables;
    Dts.Variables["User::lineageIds"].Value = new Dictionary<int, string>();
    lineageIds = (Dictionary<int, string>)Dts.Variables["User::lineageIds"].Value;
    Executables execs = (Executables)Dts.Variables["User::execsObj"].Value;

    ReadExecutables(execs);

    Dts.TaskResult = (int)ScriptResults.Success;
}

private void ReadExecutables(Executables executables)
{
    foreach (Executable pkgExecutable in executables)
    {
        if (object.ReferenceEquals(pkgExecutable.GetType(), typeof(Microsoft.SqlServer.Dts.Runtime.TaskHost)))
        {
            TaskHost pkgExecTaskHost = (TaskHost)pkgExecutable;
            if (pkgExecTaskHost.CreationName.StartsWith("SSIS.Pipeline"))
            {
                ProcessDataFlowTask(pkgExecTaskHost);
            }
        }
        else if (object.ReferenceEquals(pkgExecutable.GetType(), typeof(Microsoft.SqlServer.Dts.Runtime.ForEachLoop)))
        {
            // Recurse into FELCs
            ReadExecutables(((ForEachLoop)pkgExecutable).Executables);
        }
    }
}

private void ProcessDataFlowTask(TaskHost currentDataFlowTask)
{
    MainPipe currentDataFlow = (MainPipe)currentDataFlowTask.InnerObject;
    foreach (IDTSComponentMetaData100 currentComponent in currentDataFlow.ComponentMetaDataCollection)
    {
        // Get the inputs in the component.
        foreach (IDTSInput100 currentInput in currentComponent.InputCollection)
            foreach (IDTSInputColumn100 currentInputColumn in currentInput.InputColumnCollection)
                lineageIds.Add(currentInputColumn.ID, currentInputColumn.Name);

        // Get the outputs in the component.
        foreach (IDTSOutput100 currentOutput in currentComponent.OutputCollection)
            foreach (IDTSOutputColumn100 currentoutputColumn in currentOutput.OutputColumnCollection)
                lineageIds.Add(currentoutputColumn.ID, currentoutputColumn.Name);
    }
}

4. 在 Dataflow 中创建具有只读访问权限lineageIds和以下代码的脚本组件。

public override void Input0_ProcessInputRow(Input0Buffer Row)
  {
      Dictionary<int, string> lineageIds = (Dictionary<int, string>)Variables.lineageIds;

      int? colNum = Row.ErrorColumn;
      if (colNum.HasValue && (lineageIds != null))
      {
          if (lineageIds.ContainsKey(colNum.Value))
              Row.ErrorColumnName = lineageIds[colNum.Value];

          else
              Row.ErrorColumnName = "Row error";
      }
      Row.ErrorDescription = this.ComponentMetaData.GetErrorDescription(Row.ErrorCode);
  }
于 2015-09-15T01:43:04.340 回答
1

右键单击 CSV 组件(和许多其他组件)并选择“显示高级编辑器”。转到最后一个选项卡“输入和输出属性”

在此屏幕上,在树形菜单中查看您的输出列(不是(!)外部列)。这些在“公共属性”中具有沿袭 ID

有很多 jabber 很难找到,如果不重新编写 Visual Studio 本身的代码就不可能找到,但我只是在 2010 年和 2012 年的不同系统上检查了这个,它并不比我更难刚刚描述的。

于 2014-03-05T09:05:12.997 回答