我经常遇到以下错误
Error: 0xC020901E at Build Test Data, Lookup ID String[120]: Row yielded no match during lookup.
Run Code Online (Sandbox Code Playgroud)
为了解决这些问题,我将回到源头并进行明智的猜测,但如果我能看到失败的行,那就容易多了。
在 SSIS 中执行此操作的最佳方法是什么(使用 MSSQL2012)?
谢谢。
我遇到过的任何东西都没有为此提供开箱即用的功能,如果有人证明我错了,我会很高兴。
因此,我所做的是一个可控的失败。

我对 DimEmployee 的查找应该总是匹配。在执行此依赖包之前,数据已加载到该表中。源数据没有机会在加载之间改变,但我仍然遇到查找结果不匹配的情况。不,这不是一个迟到的维度,只是他们对需求的理解很差。
无论如何,我所做的是将不匹配设置为“将行重定向到无匹配输出”。对于 2005 年的那些人,您将不得不使用“将行重定向到错误输出”

然后我计算有多少行从失败的查找中流出,因为如果有一个失败,可能会有更多。即使查找可以捕获该行失败,这也是一个缺点 - 它只会向您显示第一行,我通常想知道所有失败。
我为此使用了一个脚本任务,当我输入它时,我可以看到如何将它变成一个可重用的组件......我的脚本任务充当转换,但我可以很容易地指定一个目标。我在查找中使用的列中进行了映射,但没有产生匹配项。对于这个例子,我有一个EmployeeID和他们的EffectiveDT
我将在这个组件中做的是为每一个通过的行触发一个警告事件。SSISDB 中运行的 2012 项目的默认设置将捕获警告事件。一旦所有行都通过,在我的PostExecute方法中,我将引发Error事件,这将导致整个 DataFlow 失败。
using System;
using System.Collections.Generic;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
/// <summary>
/// Variable identifying whether we had any rows
/// </summary>
bool Found;
/// <summary>
/// Initialize our variable
/// </summary>
public override void PreExecute()
{
base.PreExecute();
this.Found = false;
}
/// <summary>
/// Error out the entire task if we found any rows
/// </summary>
public override void PostExecute()
{
base.PostExecute();
if (this.Found)
{
bool cancel = true;
ComponentMetaData.FireError(0, "SCR Lookup Employee", "Unmatched Employees found. See warning for more context", string.Empty, 0, out cancel);
}
}
/// <summary>
/// Emit warnings for all the bad rows and then flag the entire operation as having bad rows
/// </summary>
/// <param name="Row">The row that is currently passing through the component</param>
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
this.Found = true;
string msg = string.Format("Research->{0}:{1}", Row.EmployeeID, string.Format("{0:yyyy-MM-dd}", Row.EffectiveDT));
ComponentMetaData.FireWarning(0, "Unmatched Employees", msg, string.Empty, 0);
}
}
Run Code Online (Sandbox Code Playgroud)
然后我在服务器上运行我的包并观察执行/操作 ID。如果您进入 SSMS 中的“所有执行”报告,则这是第一列 ID 中的值。在这种情况下,我看到 938 所以我然后在 SSISDB 中运行以下查询
USE SSISDB;
SET NOCOUNT ON;
DECLARE
@operation_id bigint = 938;
WITH SRC AS
(
SELECT
OM.message
, CHARINDEX('->', OM.message) AS arrow
, CHARINDEX(':', OM.message, CHARINDEX('->', OM.message)) AS colon
, LEN(OM.message) AS length
, RIGHT(OM.message, LEN(OM.message) - CHARINDEX('->', OM.message) -1) AS elements
FROM
catalog.operation_messages AS OM
WHERE
OM.message_type= 110
AND OM.message_source_type = 60
AND OM.message LIKE '%research%'
AND OM.operation_id = @operation_id
)
, PARSED AS
(
SELECT
SRC.message
, CHARINDEX(':', SRC.elements) AS colon
, LEN(SRC.elements) AS length
, SRC.elements AS RelevantText
, LEFT(SRC.elements, CHARINDEX(':', SRC.elements) -1) AS EmployeeID
, RIGHT(SRC.elements, LEN(SRC.elements) - CHARINDEX(':', SRC.elements)) AS EventDate
FROM
SRC
)
SELECT
P.message
, P.RelevantText
, P.EmployeeID
, P.EventDate
FROM
PARSED AS P;
Run Code Online (Sandbox Code Playgroud)
这将为我提供我在“所有消息”报告中看到的所有相关部分,但优点是我可以单击并选择内容,而且我已经解析出我需要的内容。
message RelevantText EmployeeID EventDate
DFT Load FactPayroll:Warning: Research->90132693:2011-05-25 90132693:2011-05-25 90132693 2011-05-25
DFT Load FactPayroll:Warning: Research->900432371:2011-05-25 900432371:2011-05-25 100432371 2011-05-25
DFT Load FactPayroll:Warning: Research->900443209:2011-05-25 900443209:2011-05-25 100443209 2011-05-25
DFT Load FactPayroll:Warning: Research->900443418:2011-05-25 900443418:2011-05-25 100443418 2011-05-25
Run Code Online (Sandbox Code Playgroud)
如果您是从 Visual Studio/SSDT/BIDS 的上下文中运行它,我什至不会担心脚本的输出,只需添加一个数据查看器,然后您就不必担心爬取日志。
2012 年发布的 SSIS 为我们提供了一种用于对已部署的包进行故障排除的新工具:Data Taps。这些是每次执行的机制,允许您在数据流中的特定点生成 CSV(仅)提取。这在高度监管的环境 (SOX/SAS 70/HIPPA/PCI) 中非常有用,在这些环境中,您不能在没有地球上每个人的签字的情况下部署更新的包。只需运行带有特殊位集的包,它就会在一个众所周知的位置生成一个 CSV。
对于上面引用的屏幕截图,如果我想查看将要命中“LKP DimEmployee”的所有源数据,我会标识我的 PackagePath:\Package\DFT Load FactJobAction和我的 IdentificationString:Paths[ALL DateSK.Union All Output 1]然后使用 Josh 文章中的脚本
USE SSISDB;
DECLARE @ExecutionID BIGINT
/*****************************************************************************
-- First create an execution instance. Data taps are valid for the specified
-- execution instance only
*****************************************************************************/
EXEC catalog.create_execution
N'DW Folder', --Folder name in SSISDB
N'DW Project', --Project name in SSISDB
N'FactJobAction', --Package name in SSISDB
NULL, --optional parameter to hold reference ID for later use
0, --optional parameter set to 1 if 32-bit runtime required
@ExecutionID OUTPUT;
DECLARE @DataTapID BIGINT;
/******************************************************************************
-- Next create the actual data tap. The parameters specified below deterimine
-- at which point in a specific package the data tap will be added.
******************************************************************************/
EXEC catalog.add_data_tap
@ExecutionID, --output from catalog.create_execution
N'\Package\DFT Load FactJobAction', --PackagePath property value from data flow task in SSDT
N'Paths[ALL DateSK.Union All Output 1]', --IdentificationString property value from data flow task in SSDT
N'File.csv', --Desired Output file name
NULL, --optional paramter to specify number of rows to log. NULL for all rows
@DataTapID OUTPUT; --output ID
/******************************************************************************
-- This final block of code executes the package. The data tap file output
-- will be found in the %SSISRoot%\DataTaps directory upon completion
******************************************************************************/
EXEC catalog.start_execution
@ExecutionID; --output from catalog.create_execution
Run Code Online (Sandbox Code Playgroud)