SQL Server SSIS:如何从数组创建数据集?文件更新校验需求
你提到的用两个单独数组存储文件名和修改时间确实不够优雅,我给你几个实用的方案,完美实现二维结构化数据的存储,后续校验修改时间也更方便:
方案1:用Script Task创建DataTable并存储到SSIS变量(最推荐)
DataTable天生就是二维结构化数据,正好符合你的需求,而且可以直接在SSIS变量中存储,后续用Foreach ADO枚举器遍历非常方便。
步骤:
- 在SSIS包中创建一个Object类型的变量,比如命名为
User::PreUpdateFileList。 - 添加一个Script Task,设置ReadWriteVariables为
User::PreUpdateFileList(ReadOnlyVariables留空)。 - 打开Script Task编辑器,选择C#作为脚本语言,写入以下代码(替换你的共享路径):
using System; using System.Data; using System.IO; using Microsoft.SqlServer.Dts.Runtime; public void Main() { // 初始化DataTable,定义需要的列 DataTable fileMetadataTable = new DataTable(); fileMetadataTable.Columns.Add("FileName", typeof(string)); fileMetadataTable.Columns.Add("LastModifiedTime", typeof(DateTime)); // 替换为你的Windows共享文件夹路径 string sharedFolderPath = @"\\YourFileServer\YourSharedFolder"; // 遍历共享文件夹中的所有文件,收集元数据 foreach (string fullFilePath in Directory.GetFiles(sharedFolderPath)) { FileInfo fileInfo = new FileInfo(fullFilePath); // 将文件名和修改时间添加到DataTable行中 fileMetadataTable.Rows.Add(fileInfo.Name, fileInfo.LastWriteTime); } // 将DataTable赋值给SSIS变量,供后续组件使用 Dts.Variables["User::PreUpdateFileList"].Value = fileMetadataTable; // 标记任务执行成功 Dts.TaskResult = (int)ScriptResults.Success; }
后续使用:
添加一个Foreach Loop Container,选择Foreach ADO Enumerator,数据源选择User::PreUpdateFileList,枚举模式选Rows in the first table。然后在「变量映射」中,把FileName列映射到一个字符串变量(比如User::CurrentFileName),LastModifiedTime映射到一个DateTime变量(比如User::PreUpdateModTime)。这样每次循环就能拿到执行前的文件信息,和BAT执行后的文件修改时间对比即可。
方案2:用Data Flow Task可视化生成Recordset(无大量代码)
如果你更喜欢用SSIS的图形化组件,不想写太多C#代码,可以用Data Flow来生成结构化数据集:
步骤:
- 创建Object类型变量
User::PreUpdateFileList,再创建一个字符串变量User::CurrentFilePath用于存储遍历到的文件路径。 - 添加Foreach Loop Container,选择
Foreach File Enumerator,设置共享文件夹路径,将遍历到的完整文件路径映射到User::CurrentFilePath。 - 在Foreach Loop中添加Data Flow Task。
- 在Data Flow里:
- 添加Script Component作为数据源,设置ReadOnlyVariables为
User::CurrentFilePath。 - 在Script Component的「输入和输出」中,添加两个输出列:
FileName(字符串类型)、LastModifiedTime(日期时间类型)。 - 编写Script Component的代码(仅需实现
CreateNewOutputRows方法):using System.IO; using Microsoft.SqlServer.Dts.Pipeline.Wrapper; using Microsoft.SqlServer.Dts.Runtime.Wrapper; [Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute] public class ScriptMain : UserComponent { public override void CreateNewOutputRows() { string filePath = Variables.CurrentFilePath; FileInfo fileInfo = new FileInfo(filePath); // 添加一行数据到输出 Output0Buffer.AddRow(); Output0Buffer.FileName = fileInfo.Name; Output0Buffer.LastModifiedTime = fileInfo.LastWriteTime; } } - 添加Recordset Destination,连接到Script Component的输出,将Recordset赋值给
User::PreUpdateFileList变量。
- 添加Script Component作为数据源,设置ReadOnlyVariables为
后续使用:
和方案1一样,用Foreach ADO Enumerator遍历这个Recordset变量即可。
关于用Execute SQL Task从数组生成数据集的问题
如果你已经有了两个单独的数组(文件名和修改时间),要通过Execute SQL Task生成数据集,可以按以下步骤操作:
- 在Script Task中,将两个数组合并成DataTable(参考方案1的代码逻辑)。
- 通过
SqlBulkCopy将DataTable的数据插入到SQL Server的临时表(比如#FileList)中:using System.Data.SqlClient; // 省略前面创建DataTable的代码... string connString = "Data Source=YourSQLServer;Initial Catalog=tempdb;Integrated Security=True;"; using (SqlConnection conn = new SqlConnection(connString)) { conn.Open(); // 创建临时表 using (SqlCommand cmd = new SqlCommand("CREATE TABLE #FileList (FileName NVARCHAR(255), LastModifiedTime DATETIME)", conn)) { cmd.ExecuteNonQuery(); } // 批量插入DataTable数据 using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn)) { bulkCopy.DestinationTableName = "#FileList"; bulkCopy.WriteToServer(fileMetadataTable); } } - 添加Execute SQL Task,使用同一个SQL Server连接,执行
SELECT FileName, LastModifiedTime FROM #FileList,设置「结果集」为完整结果集,将结果映射到Object类型变量,这样就得到了结构化数据集。
注意:临时表的生命周期和数据库连接绑定,要确保Script Task和Execute SQL Task使用同一个Connection Manager,或者改用全局临时表(
##FileList)避免找不到表的问题。
内容的提问来源于stack exchange,提问作者skittle

