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 - 在平面文件目标中导出为指数值的浮点值
SQL 导出到平面文件比作业中 SSIS 中的相同导出运行得更快
如何在 SQL Standard 上导出 SSIS 数据并在 SQL Express 上使用 Bulk Insert 导入?