Sql server SSIS-将存储过程中的结果集插入另一台DB服务器上的表中

Sql server SSIS-将存储过程中的结果集插入另一台DB服务器上的表中,sql-server,sql-server-2008,ssis,Sql Server,Sql Server 2008,Ssis,我想我偶然发现了一个edge案例,ADO.NET数据源和OLDEB数据源都不能完全满足我的需求: 控制流->执行SQL任务->ADO.NET数据源允许处理以用户定义的表(表值参数)作为参数的存储过程 但是,我不知道如何将数据插入到另一台服务器上的表中 数据流->OLEDB数据源允许通过管道将一台服务器上的数据源的结果直接传输到另一台服务器上的数据源 但是,所有数据流源(OLEDB数据源,甚至ADO.NET数据源)似乎都不允许传入参数映射,因此无法传入复杂的用户定义类型 我也不能使用变量表达

我想我偶然发现了一个edge案例,ADO.NET数据源和OLDEB数据源都不能完全满足我的需求:

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

    • 但是,我不知道如何将数据插入到另一台服务器上的表中
  • 数据流->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
    
    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包如下所示:

    .-[Sequence Container]-----------------------------------------------.
    |                                                                    |
    | .-[Data Flow Task - Populate User Variable User::OrderList]-.      |
    | |                                                           |      |
    | '-----------------------------------------------------------'      |
    |                               |                                    |
    |                              \|/                                   |
    | .-[Execute SQL Task - call dbo.GetOrdersByOrderList]--------.      |
    | |                                                           |      |
    | '-----------------------------------------------------------'      |
    |                               |                                    |
    |                              \|/                                   |
    | .-[ ?????????????????????????????????????? ]----------------.      |
    | |                                                           |      |
    | '-----------------------------------------------------------'      |
    '--------------------------------------------------------------------'
    
    我能想到的唯一解决方案是在源数据库上添加第二个存储过程,它采用@OrderList varchar(max)而不是dbo.OrderKeyList表,并调用dbo.Split(“,”,@OrderList)并将其传递给实际的存储过程:

    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
    
    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
    
    但我真的不喜欢这种方法,因为:

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

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

    我会这样做: 将数据推送到源上的表(可能是temp),而不是将数据推送到对象变量。可以使用表名作为参数运行存储过程,然后执行动态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
    

    也许其他人有一种方法可以完全按照您所描述的那样来做,我自己会非常有兴趣看到这样的解决方案。

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


    如果您使用您提到的包装器存储过程方法,那么对于ETL过程来说,即使是数千行,它也不会有太大的扩展性。如果是我,这是我的选择

    在进一步研究之后,我发现了一个关于堆栈溢出的问题,它将我引向了本文--

    它的网络是将User::OrderList作为参数传递给脚本任务,并编写一个C#程序直接使用ADO.net,从而绕过SSIS GUI的限制

    你为什么要这样做?为什么不把所有的东西都用C写呢?好的,通过这样做,我个人仍然看到SSIS的好处,因为ETL过程的整体编排仍然是图形化的,因此应该非常容易阅读,即使写起来更痛苦(哈!SSIS什么时候写起来不痛苦?)

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