【问题标题】:SSIS - Insert result set from stored proc into table on another DB serverSSIS - 将存储过程中的结果集插入另一个数据库服务器上的表中
【发布时间】:2016-07-18 13:47:05
【问题描述】:

我想我偶然发现了一个极端情况,即 ADO.NET 数据源和 OLDEB 数据源都不能完全满足我的需求:

  1. 控制流 -> 执行 SQL 任务 -> ADO.NET 数据源允许以用户定义的表(表值参数)作为参数来处理存储过程。

    • 但是,我没有办法/不知道如何将数据插入到另一台服务器上的表中。
  2. 数据流 -> OLEDB 数据源允许将一台服务器上数据源的结果直接通过管道传输到另一台服务器上的数据源中。

    • 但是,所有数据流源(OLEDB 数据源甚至 ADO.NET 数据源)似乎都不允许传入参数映射,因此无法传入复杂的用户定义类型。
    • 我也不能使用变量表达式,因为似乎没有办法将对象作为表达式值插入。

Server1 有以下存储过程:

CREATE TYPE [dbo].[OrderKeyList] AS TABLE(
  [OrderKey] [varchar](50) NULL
)
GO

CREATE PROCEDURE [dbo].[GetAllOrdersInOrderList] (
  @OrderList dbo.OrderKeyList not null
)
AS
BEGIN
  SELECT o.*
  FROM dbo.Orders o
  WHERE o.OrderKey in (SELECT o.OrderKey FROM @OrderList);
END
GO

SSIS包如下:

.-[Sequence Container]-----------------------------------------------.
|                                                                    |
| .-[Data Flow Task - Populate User Variable User::OrderList]-.      |
| |                                                           |      |
| '-----------------------------------------------------------'      |
|                               |                                    |
|                              \|/                                   |
| .-[Execute SQL Task - call dbo.GetOrdersByOrderList]--------.      |
| |                                                           |      |
| '-----------------------------------------------------------'      |
|                               |                                    |
|                              \|/                                   |
| .-[ ?????????????????????????????????????? ]----------------.      |
| |                                                           |      |
| '-----------------------------------------------------------'      |
'--------------------------------------------------------------------'

我能想到的唯一解决方案是在 Source DB 上添加第二个存储过程,它采用 @OrderList varchar(max) 而不是 dbo.OrderKeyList 表,并调用 dbo.Split(',', @OrderList) 并将其传递给真正的存储过程:

CREATE PROCEDURE [dbo].[GetAllOrdersInOrderListWrapper] (
   @OrderList varchar(max)
)
AS
BEGIN
  DECLARE @tmpOrderList dbo.OrderKeyList
  SELECT
    DISTINCT CAST(o.Data as varchar(50))
  INTO @tmpOrderList
  FROM dbo.Split(',', @OrderList) o;

  EXEC dbo.GetAllOrdersInOrderList @tmpOrderList
END;
GO

但我真的不喜欢这种方法,因为:

  • 它将如何扩展到数千行?
  • 它需要存储过程源添加另一个存储过程,仅用于 SSIS。

【问题讨论】:

    标签: sql-server sql-server-2008 ssis


    【解决方案1】:

    如果您使用控制流/执行 SQL 任务方法,您可以通过链接服务器将数据移动到另一台服务器上的表中。

    如果您使用您提到的包装存储过程方法,它不会对 ETL 过程进行可怕的扩展,即使是数千行。如果是我,这是我会选择的选择。

    【讨论】:

      【解决方案2】:

      您的问题可能与尝试将对象作为用户定义类型传递有关,我从未尝试将“表”作为参数传递。

      我会这样做: 与其将数据推送到对象变量,不如将其推送到源上的表(可能是临时表)。你的存储过程可以以表名作为参数运行,然后执行动态sql

      CREATE PROCEDURE [dbo].[GetAllOrdersInOrderList] (
        @OrderList varchar(500) not null
      )
      AS
      BEGIN    
      Set @Sql = '  SELECT o.*
            FROM dbo.Orders o
            WHERE o.OrderKey in (SELECT o.OrderKey FROM ' + @OrderList +')';
          Exec @Sql
      END
      

      也许别人有办法完全按照你的描述来做,我自己会很感兴趣看到这样的解决方案。

      【讨论】:

        【解决方案3】:

        在研究了更多之后,我在 Stack Overflow 上找到了一个 suggestion,它通过@Jon Seigel 向我指出了这篇文章——Using table-valued parameters in SSIS

        它的net-net是将User::OrderList作为参数传递给Script Task,编写C#程序直接使用ADO.NET,从而绕过SSIS GUI的限制。

        您为什么要这样做?为什么不直接用 C# 编写所有内容?好吧,通过这种方式,我个人仍然看到了 SSIS 的好处,因为 ETL 过程的整体编排仍然是图形化的,因此应该非常容易阅读,即使写起来更痛苦(哈!当SSIS写起来不痛苦吗?)。

        我现在正在尝试这种方法,因为我可以看到多种好处,包括将来可以使用 C# SqlBulkCopy 类批量插入数据以加快加载速度。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-16
          • 2021-01-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多