【问题标题】:How to Move Data from Transactional Databases to a Master Database with SSIS如何使用 SSIS 将数据从事务数据库移动到主数据库
【发布时间】:2024-01-24 08:25:01
【问题描述】:

我是 SSIS 的新手,我需要编写一个包,将数据从事务数据库移动到主数据库。我们每个工厂都有一个事务数据库,所有这些的架构都是相同的。我需要遍历每个数据库中的每个表,并将所有未标记为导出的数据复制到主数据库中的相应表中。记录成功复制到主数据库后,它们应在事务数据库中标记为已导出。

到目前为止,我已经将我的 SSIS 包放到了可以遍历植物数据库并从其中一个表中读取的位置。我目前正在将该表中的结果存储到一个变量中。我通过在 For Each 循环容器的连接管理器中使用一个表达式来完成迭代部分,该表达式将初始目录设置为循环中的当前数据库名称。

但是,我不确定之后如何进行。这是我的包裹当前状态的图片:

我尝试创建另一个执行 SQL 任务,该任务从 Get New Apples 获取结果并将它们复制到主数据库。但是,从我到目前为止搜索的内容来看,似乎没有一种简单的方法可以实现这一点。

我尝试过的另一种方法是使用与 For Each 循环容器相同的连接管理器来创建 OLE DB 源。当我这样做时,我收到一条错误消息,指出 Apple 表不是有效对象(我的查询是 select * from Apple where exported = 0;)。

任何关于如何从变量中读取结果集或让 OLE DB 源与上述连接管理器一起工作的建议都会非常有帮助。

我也愿意使用其他方法来实现这一点。就像我说的,我是 SSIS 的新手,并且还在摸索。

最初我试图将其作为一个存储过程,但它开始很快变得难以管理和丑陋:

SELECT * 
INTO   #tempapple
FROM   (SELECT * 
        FROM   [Plant1].[dbo].[Apple] 
        WHERE  exported = 0 
        UNION 
        SELECT * 
        FROM   [Plant2].[dbo].[Apple] 
        WHERE  exported = 0) AS x; 

INSERT INTO [Master].[dbo].[Apple] 
SELECT id, 
       NAME, 
       description, 
       active, 
       plant 
FROM   #tempapple
WHERE  id NOT IN (SELECT id 
                  FROM   [Master].[dbo].[Apple]); 

UPDATE [Plant1].[dbo].[Apple] 
SET    exported = 1 
WHERE  id IN (SELECT id 
              FROM   #tempapple); 

UPDATE [Plant2].[dbo].[Apple] 
SET    exported = 1 
WHERE  id IN (SELECT id 
              FROM   #tempapple); 

DROP TABLE #tempapple; 

【问题讨论】:

  • 如果所有事务数据库和主数据库都在同一个 SQL Server 上,则不必使用 SSIS。您可以编写 T-SQL/存储过程来完成此操作。
  • 存储过程是我最初的方法,但它不适合从所有事务数据库中获取数据。在存储过程中参数化数据库名称也是不可能的(据我所知),所以我最初的尝试看起来很长且难以管理。我将用我的存储过程中的一个例外来更新我的问题
  • Bruno,存储的 proc 路由需要一个游标。这在 SSIS 术语中就像一个 foreach
  • @KeithL 就性能而言,游标不是魔鬼吗?我主要是一名程序员,所以我根据过去从同事那里听到的事情来做这个
  • 他们可以,但这是合理的,不会成为问题,并且完全按照您在上面所做的,但更干净

标签: sql-server database ssis


【解决方案1】:

我必须在这里做一些假设:

  1. 变量是“对象”类型
  2. foreach 循环位于 ADO.Object 枚举器上,将数据库名称设置为变量
  3. 在数据流前插入表达式
  4. 在表达式中将新的变量类型字符串设置为“Select * from” + [dbname] + “.[schema].[tablename] where exports = 0” 4a。请注意,dbname 来自 #2 中的可枚举集
  5. 在您的数据流中,将源设置为变量并在 #4 中使用该变量。

这应该至少会加载您的数据。

您可以选择更新源中的 isExported 列。

【讨论】:

    【解决方案2】:

    我是直接写的,所以你可能需要稍微修改一下。

    declare  @dbname as varchar(100) -- dbname
    declare @SQL varchar(max)
    
    declare db_cursor cursor for
    [ this is where you insert your code for getting DBnames]
    
    OPEN db_cursor
    fetch next from db_cursor into @dbname
    
    while @@fetch_status = 0
    BEGIN
        set @SQL = "Select * into #temptable from " + @dbname + ".[dbo].[Apple] where exported = 0
    INSERT INTO [Master].[dbo].[Apple] 
    SELECT id, 
           NAME, 
           description, 
           active, 
           plant 
    FROM   #tempapple
    -- no where clause needed
    
    UPDATE " + @dbname + ".[dbo].[Apple] 
    SET    exported = 1 
    from " + @dbname + ".[dbo].[Apple] a
    join #temptable tt  on a.id=tt.id
    
    DROP TABLE #tempapple; "
    
    exec(@sql);
    fetch next from db_cursor into @dbname
    END
    
    close db_cursor
    deallocate db_cursor
    

    【讨论】:

    • 我在考虑使用存储过程时确实考虑过使用动态语法,但我不太喜欢在字符串中编写 sql。
    • 诀窍是让它在没有字符串格式的情况下工作,然后替换 SQL 周围的变量。
    【解决方案3】:

    我决定将我的两种方法混合使用。 SSIS 包与遍历每个植物数据库的逻辑基本相同。在循环中,我现在有几个执行 SQL 任务来从各种表中导入数据。导入苹果任务的逻辑如下所示:

    SELECT * 
    INTO   #tempapple 
    FROM   (SELECT * 
        FROM   apple 
        WHERE  exported = 0); 
    
    INSERT INTO [Master].[dbo].[apple] 
    SELECT id, 
       NAME, 
       description, 
       active, 
       plant 
    FROM   #tempapple 
    WHERE  id NOT IN (SELECT id 
                  FROM   [Master].[dbo].[apple]); 
    
    UPDATE apple 
    SET    exported = 1 
    WHERE  id IN (SELECT id 
              FROM   #tempapple); 
    
    DROP TABLE #tempapple; 
    

    这让我没有多余的 SQL,因为每个任务将在每个植物数据库中执行一次。

    【讨论】:

      最近更新 更多