SSIS - 将表数据分块导出到平面文件

Posted

技术标签:

【中文标题】SSIS - 将表数据分块导出到平面文件【英文标题】:SSIS - Export table data to flat file in chunks 【发布时间】:2016-06-29 00:49:38 【问题描述】:

我需要将表数据导出到一个平面文件(.csv 格式)中,每个文件每个只包含 5000 条记录。如果表有 10000 条记录,那么它必须创建 2 个文件,每个文件有 5000 条记录。表中的记录将每天增加。所以基本上我正在寻找一种动态解决方案,它将“n”个记录导出到“n”个文件,每个文件只有 5000 条记录。

*一个简单的可视化: 假设该表有 10230 条记录。我需要的是:

File_1.csv - 1 到 5000 条记录

File_2.csv - 5001 到 10000 条记录

File_3.csv - 10001 到 10230 条记录*

我已经为上述逻辑尝试了 BCP 命令。这可以使用数据流任务完成吗?

【问题讨论】:

看看这个答案Batch export data SSIS 【参考方案1】:

不,这不是 SSIS 本身就能很好地支持的东西。

脚本任务或充当目标的脚本组件可以完成此任务,但您需要重新发明***的重要部分来处理所需的所有文件。

第一步是以可重复的方式将行号添加到来自源的所有行。这可以像SELECT *, ROW_NUMBER() OVER (ORDER BY MyTablesKey) AS RN FROM dbo.MyTable 一样简单

现在您有一个与每一行关联的单调递增值,如果您采用 ForEach 方法,您可以使用 referenced 答案来提取给定范围内的数据。

如果您可以对您拥有的数据桶/数据文件的数量设定一个合理的上限,那么您可以使用一些分析函数来指定分组的大小。然后,所有数据都被输入数据流,并且您有一个条件拆分,其输出缓冲区的上限价值指向平面文件目标。

另一种方法是按原样导出文件,然后使用PowerShell 之类的东西将其拆分为更小的单元。 Unix 很好,因为他们有 split 作为这类事情的本机方法。

【讨论】:

感谢您的建议。我使用 ROW_NUMBER() 函数首先获取行号,然后在 sql 的 BETWEEN 子句中传递值。所以我的查询将与您所说的类似:)【参考方案2】:

嗯,可以使用标准 SSIS 组件和 SQL 2012+ 来完成。想法如下 - 使用 SELECT ... ORDER BY ... OFFSET <Row offset> ROWS FETCH NEXT <Row number> ROWS 作为存储桶源,并将其与 FOR 容器和带有表达式的平面文件目标一起使用。 更多详情:

    使用初始化值为 0 的 Iterator int 变量和平面文件目标创建包,其中连接字符串定义为“\Filename_”+[User::Iterator]+“.csv”的表达式。还将 Bucket_size 变量或参数定义为 int 创建 For 循环序列容器。暂时将其参数留空。下一步将在 For 循环中进行。 在循环容器(或包级别 - 由您决定)使用"SELECT count(*) FROM ... ORDER BY ... OFFSET "+(DT_WSTR,20)[User::Iterator]*[User::Bucket_Size]+" ROWS " 创建 SQL_rowcount 变量。此命令为您提供当前存储桶中的剩余行数。 使用来自 SQL_rowcount 变量的命令创建任务执行 SQL 命令,并将单个结果存储到变量 Bucket_Rowcount。 使用表达式"SELECT .. FROM ... ORDER BY ... OFFSET "+(DT_WSTR,20)[User::Iterator]*[User::Bucket_Size]+" ROWS FETCH NEXT "+(DT_WSTR,20)[User::Bucket_Size]+" ROWS" 创建字符串变量SQL_bucket。 使用来自 SQL_bucket 变量的命令和步骤 1 中的平面文件目标创建一个简单的数据流任务 - OLEDB 源。 现在小技巧 - 我们必须定义循环条件。我们根据当前桶的行数来做——最后一个桶的行数不超过桶大小。继续条件(在循环进入之前检查) - 最后一次迭代有多个 Bucket 行(下一次迭代至少还剩 1 行)。 因此,为 For 循环容器定义以下属性 InitExpression - @Bucket_Rowcount = @Bucket_Size + 1 EvalExpression - @Bucket_Rowcount > @Bucket_Size 赋值表达式 - @Iterator = @Iterator + 1

就是这样。 导出时不修改源表可以优化;首先(在 For 循环之前)获取行数并计算桶数,并执行此次数的迭代。因此,您可以避免在循环中重复 select count(*) 语句。

【讨论】:

以上是关于SSIS - 将表数据分块导出到平面文件的主要内容,如果未能解决你的问题,请参考以下文章

将数据从平面文件加载到 Sql Server 表,并使用 SSIS 导出到 excel

SSIS 2008 - 在平面文件目标中导出为指数值的浮点值

问题将数值数据导出到平面文件,SSIS

SQL 导出到平面文件比作业中 SSIS 中的相同导出运行得更快

如何在 SQL Standard 上导出 SSIS 数据并在 SQL Express 上使用 Bulk Insert 导入?

如何将表数据从 PostgreSQL (pgAdmin) 导出到 CSV 文件?