【问题标题】:SSIS - Export table data to flat file in chunksSSIS - 将表数据分块导出到平面文件
【发布时间】: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 命令。这可以使用数据流任务完成吗?

【问题讨论】:

标签: sql-server 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 容器和带有表达式的平面文件目标一起使用。
更多详情:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多