使用foreach循环时如何在SSIS中获取文件夹名称和文件名错误

How to Get folder name and file name error in SSIS when using foreach loop

我使用 SSIS 向数据库中插入数据。我使用 foreach 循环来循环文件夹和该文件夹中的文件。我想获取处理中有错误的文件夹名称和文件名称。我会将它们记录在 txt 文件中。大家帮帮我,谢谢!

下面对此进行了概述。有些事情可能会有所不同,具体取决于您的环境以及您希望如何记录有错误的文件夹和文件的名称,但这应该让您朝着正确的方向开始。

  • 创建一个int变量,你可以调用这个"ErrorCount"并确保它的值设置为0。这将在稍后的错误记录中使用。

  • 创建一个执行 SQL 任务,该任务将创建一个 table 用于保存文件夹和文件名。 "Filename" 是 T-SQL 中的关键字,因此使用标识符(方括号)。这些不是必需的,但可以使其更易于阅读。

  • 由于您已经在使用 Foreach 循环来加载文件,我假设已经映射了一个变量来保存每次迭代的文件名。如果您还没有这样做,请在 Foreach 循环的“变量映射”窗格中的索引 0 处添加一个字符串变量。
  • 在加载文件的数据流任务上添加一个带有 C# 脚本任务的 OnError 事件处理程序。在脚本任务编辑器上,在 ReadOnlyVariables 字段中添加保存文件名的字符串变量(Foreach 循环中的索引 0)。在 ReadWriteVariables 字段中添加您之前创建的 "ErrorCount" 变量和 System::Propagate 系统变量。稍后将使用它来允许在错误后处理后续文件。

  • 此脚本任务的代码在此 post 的后面。您需要添加对 System.IOSystem.Data.SqlClient 命名空间的引用。 每个错误 都会触发一次 OnError 事件,而不仅仅是在文件出错时。在此示例中,仅当 "ErrorCount" 用户变量的值为 0 时才记录文件名。记录文件和文件夹后,此变量将设置为 1 以避免多次记录同一文件。 Path.GetDirectoryNamePath.GetFileName 方法分别用于获取文件夹和文件名。虽然您正在加载的所有文件很可能具有相同的扩展名,但 Path.GetFileName 仍用于 return 带有文件名的文件扩展名。如果您不想看到文件扩展名,请改用 Path.GetFileNameWithoutExtension 方法。

  • SSPI 设置为集成安全性以指示将使用 Windows 身份验证。要使用 SQL 服务器身份验证,请将其设置为 false 并为 User IDPassword 属性添加适当的值。我建议使用参数,即下面的 SqlParameter 对象,而不是将 SQL 命令构造为连接字符串。输入是默认值 ParameterDirection,但为清楚起见仍定义了这些。此脚本获取已解析的文件夹和文件名,并将它们插入到 table 中,在此示例中名为 ErrorFiles,它将用于保存在写入之前包执行期间出错的文件到一个文件。虽然使用 Execute SQL Task 执行插入会更简单,但 System.IO 命名空间中的方法允许在文件路径更改时正确获取文件夹和文件名。如果您使用的文件夹永远不会更改,则执行 SQL 任务可以与插入中的 T-SQL SUBSTRING 函数一起使用,以从保存这些文件的变量中解析文件夹和文件名.

  • 在数据流任务之后,在 Foreach 循环中添加另一个脚本任务。将其连接到数据流任务并将 Precedence Constraint 上的计算操作更改为 Expression 并添加以下表达式。这将通过检查 "ErrorCount" 变量的值确保以下脚本任务仅 运行 如果在 Foreach 循环的迭代期间出现错误。

  • 在此脚本任务中,将 "ErrorCount" 添加到 ReadWriteVariables 字段中,类似于之前将其设置为 1,现在将其设置回 0 (Dts.Variables["User::ErrorCount"].Value = 0).这样做是为了允许在 Foreach 循环的后续迭代中导致错误的文件也被记录下来。

  • 在 Foreach 循环之后,添加一个带有 OLE DB 源的数据流任务。将数据访问模式设置为 SQL 命令和 select 来自 table 的 FolderName 和 FileName 列用于存储有错误的文件。如果您没有单独创建此 table,您可以将 ValidateExternalMetadata 设置为 false,并在高级编辑器的输入和输出属性选项卡中的外部和输出列文件夹中添加输出列。但是,如果您对此不熟悉,那么仅 运行 CREATE TABLE DDL 并以这种方式定义元数据可能会更容易。在此数据流任务中,添加一个连接到 OLE DB 源的平面文件目标。使用要用于保存包含错误的文件名的文件名创建一个新的平面文件管理器。您可能希望在文件名中使用表达式,使其在每次执行包时都是唯一的。 post 后面有一个示例表达式。这只使用当前日期。如果您计划在一天内多次 运行,您可能需要添加时间戳或以其他方式使每个文件名唯一。这可以通过在变量中添加此表达式并将其用作平面文件管理器的 ConnectionString 属性 来设置为输出文件的名称。

  • 接下来在此数据流任务之后添加一个执行 SQL 任务。对于 SQLStatement 添加 SQL 以删除 table 用于保存包含错误的文件名(如果存在)。虽然这不是必需的,因为创建此 table 的初始任务会删除它,但这可以避免在您的数据库中有一个额外的 table。

优先约束表达式:

@[User::ErrorCount] > 0

平面文件连接管理器连接字符串表达式:

"C:\Your Folder\" + (DT_STR, 4, 1252)DATEPART("Year", GETDATE()) + "_"
 + (DT_STR, 2, 1252)DATEPART("Month", GETDATE()) + "_" 
 + (DT_STR, 2, 1252)DATEPART("Day", GETDATE()) +"_"
+ "ErrorFiles.txt"

错误文件Table DDL:

IF(OBJECT_ID(N'YourDatabase.DBO.ERRORFILES') IS NOT NULL)
BEGIN
DROP TABLE YourDatabase.DBO.ERRORFILES
END

CREATE TABLE YourDatabase.DBO.ERRORFILES 
(
FOLDERNAME VARCHAR(100),
[FILENAME] VARCHAR(100)
)

OnError 事件处理程序脚本任务代码:

 if (Convert.ToInt32(Dts.Variables["User::ErrorCount"].Value.ToString()) == 0)
{
    string connString = @"Data Source=YourSQLServerInstance;Initial Catalog=YourDatabase;Integrated Security=SSPI";

    string cmd = @"Insert into dbo.ErrorFiles (FolderName,[FileName]) values (@folderName, @fileName)";

    //parse variable with file that caused error
    string errorFileFullName = Dts.Variables["User::NameForTable"].Value.ToString();

    //get folder
    string errorFolderName = Path.GetDirectoryName(errorFileFullName);
    //get only file name
    string errorFileName = Path.GetFileName(errorFileFullName);

    using (SqlConnection conn = new SqlConnection(connString))
    {
        SqlCommand sql = new SqlCommand(cmd, conn);

        SqlParameter pFolderName = new SqlParameter("@folderName", SqlDbType.VarChar);
        pFolderName.Direction = ParameterDirection.Input;
        pFolderName.Value = errorFolderName;
        pFolderName.Size = 100;

        SqlParameter pFileName = new SqlParameter("@fileName", SqlDbType.VarChar);
        pFileName.Direction = ParameterDirection.Input;
        pFileName.Value = errorFileName;
        pFileName.Size = 100;

        sql.Parameters.Add(pFolderName);
        sql.Parameters.Add(pFileName);

        conn.Open();

        sql.ExecuteNonQuery();

        //avoid failing Foreach Loop so other files are processed
        Dts.Variables["System::Propagate"].Value = false;

        //prevent event handler from firing multiple times. 
        Dts.Variables["User::ErrorCount"].Value = 1;

    }
}