SSIS - 以块的形式将表数据导出到平面文件

时间:2016-06-29 00:49:39

标签: sql-server ssis

我要求将表数据导出为平面文件(.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命令。可以使用数据流任务完成吗?

2 个答案:

答案 0 :(得分:1)

不,这不是SSIS本能支持的东西。

脚本任务或作为目的地的脚本组件可以实现此目的,但是您需要重新发明轮子的重要部分,并且需要所有文件处理。

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

一样简单

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

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

另一种方法是按原样导出文件,然后使用类似PowerShell的内容将其拆分为更小的单元。 Unix很不错,因为它们只有split作为本机方法。

答案 1 :(得分:0)

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

  1. 使用初始值为0的Iterator int变量和Flat File Destination创建包,其中连接字符串定义为表达式“”\ Filename _“+ [User :: Iterator] +”。csv“。同时将Bucket_size变量或参数定义为int
  2. 创建For循环序列容器。暂时将其参数保留为空。接下来的步骤将在For循环中。
  3. On循环容器(或包级别 - 由您决定)使用"SELECT count(*) FROM ... ORDER BY ... OFFSET "+(DT_WSTR,20)[User::Iterator]*[User::Bucket_Size]+" ROWS "创建SQL_rowcount变量。此命令为您提供当前存储桶中的剩余行数。
  4. 使用SQL_rowcount变量中的命令创建任务执行SQL命令,并将单个结果存储到变量Bucket_Rowcount中。
  5. 使用表达式"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。
  6. 使用来自步骤1的SQL_bucket变量和Flat File目标的命令创建一个简单的数据流任务 - OLEDB Source。
  7. 现在小技巧 - 我们必须定义循环条件。我们根据当前的存储桶行数进行操作 - 最后一个存储桶不超过存储桶大小行。连续条件(在循环输入之前检查) - 最后一次迭代有多个Bucket行(下一次迭代至少剩下1行)。
    因此,为For Loop Container定义以下属性
    • InitExpression - @Bucket_Rowcount = @Bucket_Size + 1
    • EvalExpression - @Bucket_Rowcount&gt; @Bucket_Size
    • AssignExpression - @Iterator = @Iterator + 1
  8. 就是这样 如果在导出期间未修改源表,则可以对其进行优化;首先(在For循环之前)获取行数并计算出桶的数量,并执行此迭代次数。因此,您可以避免在循环中重复选择count(*)语句。