10

我继承了一个写得很糟糕的MS Access 数据库,我需要将它导入 SQL。Access 数据库中有数千个表,其字段定义相同。我对 SSIS 有一些经验,导入一张表非常简单。

但是,我需要创建一个流程,在该流程中,我可以遍历数千个表名的列表并导入每个表。我找到了这个语句,它将获取 Access 数据库中所有表名的列表:

从 MSysObjects 中选择名称 WHERE (((MSysObjects.Type)=1) AND ((Left([Name],4))<>"MSys")) ;

但是,我不确定如何使用它(脚本任务语法?)。我想我会想要这样做来填充“对象”类型的 SSIS 变量。这样,我可以使用 ForEach 循环循环遍历这个表列表并执行导入。我怎样才能做到这一点?或者有没有更好的方法来循环浏览数据库中的每个表并执行相同的过程?

我将不胜感激任何建议。谢谢!

4

3 回答 3

19

这是一种可以实现将 Access 数据加载到 SQL Server 的可能方法,只要 Access 中的所有表具有相同的结构即可。此示例将遍历 Access 中的表,即CountryStateProvince。如果这两个表不存在,此示例中的包将在 SQL 中创建这两个表,然后使用 Access 中的数据填充它们。

分步过程:

  1. 访问表CountryStateProvince屏幕截图# 1和# 2中显示。

  2. 在 SSIS 包上,创建两个 OLE DB 连接以连接到 SQL Server 和 Access,如屏幕截图 # 3所示。此外,创建 3 个变量,如屏幕截图 # 4所示。变量SelectQuery,并且TableName应该由 Access 中的有效表指定。这是软件包的初始配置所必需的。在这种情况下,我选择Country了 Access 中确实存在的 。

  3. 选择变量SelectQuery并按 F4 以查看属性窗格。在“属性”窗格上,将属性设置EvaluateAsExpressTrue并将表达式粘贴"SELECT * FROM " + @[User::TableName]Expression属性中。此表达式将评估当前正在循环的表。参考截图# 4

  4. 屏幕截图 # 5和 # 6显示 SQL Server 中不存在这些dbo.Countrydbo.StateProvince

  5. 配置Control FlowSSIS 包的选项卡,如屏幕截图 # 7所示。放置 aScript Task并将其连接到 a Foreach Loop container。在容器内,放置 anExecute SQL Task和 a Data Flow Task

  6. 将脚本任务中的代码替换为脚本任务代码部分下给出的代码。此代码将循环访问模式并仅获取表名。然后将表名列表存储在包变量AccessTables中,然后由Foreach loop container.

  7. 在 SQL Server 数据库中,使用SQL 脚本部分dbo.CreateTable下提供的脚本创建一个名为的存储过程。此存储过程将在 SQL Server 中创建一个表(如果该表尚不存在)。Make sure that you alter the table schema defined in the stored procedure according to your needs.

  8. 配置Foreach loop container如屏幕截图 # 8和 # 9所示。

  9. 配置执行 SQL 任务,如屏幕截图 # 10和 # 11所示。

  10. 此时我们无法配置数据流任务,因为 SQL Server 中不存在这些表。因此,我们将在此时执行包,以便在 SQL Server 中创建 Access 表结构。屏幕截图 # 12显示了示例包执行。屏幕截图 # 13显示表结构已在 SQL Server 中创建,但尚未填充数据。

  11. 现在,我们将配置Data Flow Task. 在数据流任务中放置一个OLE DB Source和。OLE DB Destination将 OLE DB 源连接到 OLE DB 目标。参考截图# 14

  12. 配置OLE DB Source如屏幕截图 # 15和 # 16所示。

  13. 配置OLE DB Destination如屏幕截图 # 17和 # 18所示。

  14. 屏幕截图 # 19显示了在Data Flow Task.

  15. 屏幕截图 # 20显示 SQL Server 表现在填充了来自 Access 表的数据。

此示例仅适用于具有相同结构但名称不同的表。如果将另一个名为Employees的表添加到包含列IdName. 执行此示例包将在 SQL Server 中创建相同的表,并且还将使用数据填充它。

希望有帮助。

SQL 脚本:

CREATE PROCEDURE [dbo].[CreateTable]
(
    @TableName  VARCHAR(255)
)
AS
BEGIN

    SET NOCOUNT ON

    DECLARE @SQL VARCHAR(MAX)

    SET @SQL = 'IF NOT EXISTS ( SELECT  * 
                                FROM    sys.objects 
                                WHERE   object_id = OBJECT_ID(N''[dbo].' + @TableName + ''') 
                                AND     type in (N''U''))
                    CREATE TABLE [dbo].' + @TableName + '(
                        [ID] [int] NOT NULL,
                        [Name] [nvarchar](255) NULL
                        ) ON [PRIMARY]'

    EXEC (@SQL)
END
GO

脚本任务代码:

只能SSIS 2008 and above.

/*
   Microsoft SQL Server Integration Services Script Task
   Write scripts using Microsoft Visual C# 2008.
   The ScriptMain is the entry point class of the script.
*/

using System;
using System.Collections;
using System.Data;
using System.Data.OleDb;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;

namespace ST_9b2714c55db14556be74ca92f345c4e3.csproj
{
    [System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
    public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
    {

        #region VSTA generated code
        enum ScriptResults
        {
            Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
            Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
        };
        #endregion

        public void Main()
        {
            Variables varCollection = null;
            DataTable schemaTables = null;
            ArrayList tableNames = new ArrayList();

            Dts.VariableDispenser.LockForWrite("User::AccessTables");
            Dts.VariableDispenser.GetVariables(ref varCollection);

            using (OleDbConnection connection = new OleDbConnection(Dts.Connections["AccessDB"].ConnectionString.ToString()))
            {
                string[] restrictions = new string[4];
                restrictions[3] = "Table";    
                connection.Open();
                schemaTables = connection.GetSchema("Tables", restrictions);
            }

            foreach (DataRow row in schemaTables.Rows)
            {
                foreach (DataColumn column in schemaTables.Columns)
                {
                    if (column.ColumnName.ToUpper() == "TABLE_NAME")
                    {
                        tableNames.Add(row[column].ToString());
                    }
                }
            }

            varCollection["User::AccessTables"].Value = tableNames;

            Dts.TaskResult = (int)ScriptResults.Success;
        }
    }
}

截图#1:

1

截图#2:

2

截图#3:

3

截图#4:

4

截图#5:

5

截图#6:

6

截图#7:

7

截图#8:

8

截图#9:

9

截图#10:

10

截图 #11:

11

截图#12:

12

截图#13:

13

截图#14:

14

截图#15:

15

截图#16:

16

截图#17:

17

截图#18:

18

截图#19:

19

截图#20:

20

于 2011-06-10T03:30:25.777 回答
0

作为有访问权限的人,我会先修复 Access 中的数据(即将多个表合并到主表中),然后使用 SQL Server Migration Assistant for Access 进行升迁。它允许您在实际执行之前模拟导入并纠正任何问题。

合并数据表的第一步我只是在 VBA 中编写代码,尽管我可能必须创建一些带有元数据的表,这些表将导入的内容映射到什么中(除非表使用允许通过算法确定的命名约定)。

于 2011-06-12T21:58:51.753 回答
0

您可以将 sql 任务的结果放入object variable类型的变量中。然后,您可以在循环任务中使用该变量。

在您的 for 循环中,您可以使用表达式修改您正在操作的表名。

快速浏览后,本文可能会详细介绍该过程的第一部分:

http://www.sqlservercentral.com/articles/Integration+Services+(SSIS)/64014/

于 2011-06-09T23:44:18.763 回答