如何将SSIS中的ErrorCode和ErrorColumn转换为错误消息和列名?

时间:2012-10-02 15:46:47

标签: ssis

我将行从平面文件源重定向到平面文件目标。重定向行中的默认元数据是:

  • 原始平面文件源行
  • ErrorCode
  • ErrorColumn

我在输出平面文件中得到的是源行(不错)和错误代码(不好,例如-1071628249)和错误列(不好,因为它是列的内部ID)。

如何转换行以输出错误消息(例如“数据被截断。”)和平面文件源中定义的列名?

换句话说,而不是...,-1071607675,10我希望看到:

...,The data was truncated,Firstname

或者(如果以前不可能);

...,DTS_E_FLATFILESOURCEADAPTERSTATIC_TRUNCATED,Firstname

10 个答案:

答案 0 :(得分:13)

可以使用脚本组件实现部分问题(添加错误描述)。这在Enhancing an Error Output with the Script Component

中有所描述

似乎Dougbert博客有一个添加列名的解决方案,但它远非简单。我很惊讶这在SSIS中很难做到;你认为知道源和列的名称是一个基本需要。

答案 1 :(得分:12)

错误消息列表位于以下位置: MSDN,Integration Services错误和消息参考 http://msdn.microsoft.com/en-us/library/ms345164%28v=sql.100%29.aspx

列ID号可以在SSIS的数据流任务中找到: 选择生成错误的任务组件,高级编辑器,“输入和输出属性”选项卡,“外部列属性”。

答案 2 :(得分:4)

Pragmatic Works似乎有一个Error Output Description Transform,它是他们称之为“任务工厂”的产品Community Edition (Free)的一部分。

错误输出描述转换为用户提供了一个用户界面,可以检索有价值的信息,例如ErrorCode,ErrorColumn,ErrorDescription,ComponentName(生成错误),ColumnName(如果已知),ColumnType和ColumnLength。

它还允许您将任何输入列传递给错误输出。说实话,它非常方便,并且节省了我的SSIS包故障排除时间。

答案 3 :(得分:4)

有一个更简单的答案。只需将错误输出重定向到新的目标文件(CSV或其他),然后在错误输出上启用DataViewer ....

Data Viewer in SSIS

答案 4 :(得分:4)

可以使用脚本组件作为转换,将错误输出重定向到脚本组件,并按照步骤实现您正在寻找的内容。

(1)打开脚本组件,

输入列选择

  1. ErrorColumn
  2. 错误代码
  3. 输入和输出添加输出列

    1. ErrorDescription(DT_STRING 500)
    2. ErrorColumnDescription(DT_STRING 100)
    3. (2)编辑脚本

      粘贴以下代码

          using System;
          using System.Data;
          using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
          using Microsoft.SqlServer.Dts.Runtime.Wrapper;
          #endregion
      
          /// <summary>
          /// This is the class to which to add your code.  Do not change the name, attributes, or parent
          /// of this class.
          /// </summary>
          [Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
          public class ScriptMain : UserComponent
          {
      
              public override void Input0_ProcessInputRow(Input0Buffer Row)
              {
                  var component130 = this.ComponentMetaData as IDTSComponentMetaData130;
                  if (component130 != null)
                  {
                      Row.ErrorDescription = component130.GetErrorDescription(Row.ErrorCode);
                      Row.ErrorColumnDescription = component130.GetIdentificationStringByID(Row.ErrorColumn);
                  }
              }
      

答案 5 :(得分:2)

    //column error description 
    Row.ErrorDescription = this.ComponentMetaData.GetErrorDescription(Row.ErrorCode);

    //we are getting column name with some extra information
    String rawColumnName = this.ComponentMetaData.GetIdentificationStringByLineageID(Row.ErrorColumn);

    //extracting positions of brackets 
    int bracketPos = rawColumnName.LastIndexOf('[')+1;
    int lastBracketPos = rawColumnName.LastIndexOf(']');

    //extracting column name from the raw column name
    Row.ErrorColName = rawColumnName.Substring(bracketPos, (lastBracketPos - bracketPos));

答案 6 :(得分:1)

这是

的解决方案
  1. 适用于包运行时(不预先填充)
  2. 通过脚本任务和组件自动化
  3. 不涉及安装新程序集或自定义组件
  4. 很好地兼容BIML
  5. Check out the full solution here.

    这是简短版本。

    1. 创建2个对象变量,execsObjlineageIds
    2. 在Control流程中创建脚本任务,为其赋予ReadWrite访问权限
    3. 将以下代码插入脚本任务
    4. 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。在数据流中创建脚本组件,只读访问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);
        }
      

答案 7 :(得分:1)

我使用“数据”选项卡上的“从Web获取数据”,使用excel连接到SSIS错误消息参考网页。将表格保存在excel中的工作表中,然后将其导入到SQL Server。然后将其加入十进制代码上的错误行表以获取描述,然后从中创建视图。认为这对那些不想弄乱脚本任务的人可能有用。

答案 8 :(得分:1)

使用SS2016及更高版本,很容易: https://www.mssqltips.com/sqlservertip/4066/retrieve-the-column-causing-an-error-in-sql-server-integration-services/

public override void Input0_ProcessInputRow(Input0Buffer Row)
{
    Row.ErrorDescription = this.ComponentMetaData.GetErrorDescription(Row.ErrorCode);
    IDTSComponentMetaData130 componentMetaData = this.ComponentMetaData as IDTSComponentMetaData130;
    Row.ErrorColumnName = componentMetaData.GetIdentificationStringByID(Row.ErrorColumn);
}

对于使用SS2016之前版本的SQL Server的任何人,这里有一些参考链接,用于获取列名称:

http://www.andrewleesmith.co.uk/2017/02/24/finding-the-column-name-of-an-ssis-error-output-error-column-id/

基于: http://toddmcdermid.blogspot.com/2016/04/finding-column-name-for-errorcolumn.html

我很欣赏我们不应该发布链接,但是这种解决方案非常复杂,我试图通过从Todd和Andrew的博客文章中提取信息并在此处重新创建来进行总结。 (如果您都读过这篇文章,谢谢你们!)

在Todd的页面上:

  
      
  1. 转到“输入和输出”页面,然后选择“输出0”节点。   将“ SynchronousInputID”属性更改为“无”。 (此更改   脚本从同步到异步。)      
        
    1. 在同一页面上,打开“输出0”节点,然后选择“输出”   列”文件夹。按“添加列”按钮。更改“名称”   该新列的“ LineageID”属性。
    2.   
    3. 再次按“添加列”按钮,然后更改“数据类型”   属性设置为“ Unicode字符串[DT_WSTR]”,然后更改“名称”   属性为“ ColumnName”。
    4.   
    5. 转到“脚本”页面,然后按“编辑脚本”按钮。复制   并将此代码粘贴到ScriptMain类中(您可以删除所有   其他方法存根):
    6.   
  2.   
public override void CreateNewOutputRows() {
    IDTSInput100 input = this.ComponentMetaData.InputCollection[0];
    if (input != null)
    {
        IDTSVirtualInput100 vInput = input.GetVirtualInput();
        if (vInput != null)
        {
            foreach (IDTSVirtualInputColumn100 vInputColumn in vInput.VirtualInputColumnCollection)
            {
                Output0Buffer.AddRow();
                Output0Buffer.LineageID = vInputColumn.LineageID;
                Output0Buffer.ColumnName = vInputColumn.Name;
            }
        }
    } }
  

可以使用数据查看器随意将虚拟输出附加到该脚本,   看看你得到什么。从这里开始,这就是您的“标准工程”   ETL专家。只需合并合并失败的错误输出   带有此元数据的组件,您将能够转换   将ErrorColumn号转换为有意义的列名。

     

但是对于那些想了解以上脚本内容的人   在做:

     
      
  1. 正在将“第一个(也是唯一)”输入附加到脚本   零件。      
        
    1. 正在获取与输入有关的虚拟输入。 “输入”是   该脚本实际上可以在输入中“看到”什么-并且由于我们   没有将任何列标记为“ ReadOnly”或“ ReadWrite” ...   表示输入没有NO列。但是,“虚拟输入”具有   无论是否存在,每个存在的列的完整列表   说我们正在“使用”它。
    2.   
    3. 然后,我们遍历此虚拟机上的所有“虚拟列”   输入,然后每一个...
    4.   
    5. 获取LineageID和列名,并将其作为新行推出   我们的异步脚本。
    6.   
  2.   

安德鲁(Andrew)页面上的图片和文字有助于对其进行更详细的说明:

enter image description here

  

然后将此地图与ErrorColumn世系ID合并合并。   沿着错误路径前进,以便可以将错误信息   附加了地图中的列名。我包括了一秒钟   从错误中查找错误描述的脚本组件   代码,因此我们在上面看到的错误表行同时包含两列   名称和错误说明。

     

需要说明的其余部分是条件拆分   –存在的目的只是向脚本组件提供元数据   创建地图。我创建了一个表达式(1 == 0)   对于“无行–仅元数据”路径,结果为false,因此没有行   往下走。

     

尽管此解决方案确实需要插入一些其他内容   深入数据流中,我们获得了非常有价值的信息   确实发生错误时记录。所以特别是当数据流是   在生产中无人值守时运行–当我们没有工具和   设计时可用的技术来找出问题所在–   记录的结果为我们提供了有关以下信息的更精确信息   出了什么问题以及为什么,与仅向我们提供失败的数据相比   并让我们弄清楚为什么它被拒绝了。

答案 9 :(得分:0)

最近几天我一直在拉头发。我做了所有提到的所有事情,但是package / c#抛出了错误。最终,当我决定放弃时,我发现我的ErrorColumn变为0(零),因为由于违反了PK / FK约束,该错误出现在整行中。

所以我如下修改了脚本:

public override void Input0_ProcessInputRow(Input0Buffer Row)
    {
        Row.ErrorDescription = this.ComponentMetaData.GetErrorDescription(Row.ErrorCode);

        var componentMetaData130 = this.ComponentMetaData as IDTSComponentMetaData130;
        if (componentMetaData130 != null)
        {
            if (Row.ErrorColumn == 0) //Checking if the Column is zero
            {
                Row.ColumnName = "Entire Row. Check PK FK constraints"; //Hardcoded error message
            }
            else
            {
                Row.ColumnName = componentMetaData130.GetIdentificationStringByID(Row.ErrorColumn);
            }
        }
    }

对于常规过程:https://docs.microsoft.com/en-us/sql/integration-services/extending-packages-scripting-data-flow-script-component-examples/enhancing-an-error-output-with-the-script-component?view=sql-server-2017

为什么ErrorColumn的值为零?:SSIS 2016 - ErrorColumn is 0 (zero)

希望有帮助!