Как программно получить список таблиц MS Access в пакете служб SSIS?
Я унаследовал ужасно написанную базу данных MS Access, которую мне нужно импортировать в SQL. База данных Access содержит несколько тысяч таблиц с одинаковыми определениями полей. У меня есть некоторый опыт работы с SSIS, и импортировать одну таблицу довольно просто.
Однако мне нужно создать процесс, в котором я мог бы перебрать список из нескольких тысяч имен таблиц и импортировать каждую таблицу. Я нашел это утверждение, которое получит список всех имен таблиц в базе данных Access:
ВЫБРАТЬ Имя ОТ MSysObjects WHERE (((MSysObjects.Type)=1) И ((Слева ([Имя],4))<>"MSys"));
Однако я не уверен, как это использовать (синтаксис задачи скрипта?). Я думаю, я бы хотел сделать это, чтобы заполнить переменную SSIS типа "объект". Таким образом, я могу использовать цикл ForEach для циклического перемещения по этому списку таблиц и выполнения импорта. Как я могу это сделать? Или есть лучший способ циклически проходить по каждой таблице в базе данных и выполнять один и тот же процесс?
Буду очень признателен за любые предложения. Спасибо вам!
3 ответа
Вот один из возможных способов загрузки данных Access в SQL Server, если все таблицы в Access имеют одинаковую структуру. Этот пример будет проходить по таблицам в Access, а именно Country
а также StateProvince
, Пакет в этом примере создаст эти две таблицы в SQL, если они не существуют, а затем заполнит их данными из Access.
Пошаговый процесс:
Таблицы доступа
Country
а такжеStateProvince
показаны на скриншотах № 1 и № 2.В пакете служб SSIS создайте два подключения OLE DB для подключения к SQL Server и Access, как показано на снимке экрана № 3. Также создайте 3 переменные, как показано на скриншоте # 4. переменные
SelectQuery
а такжеTableName
должен быть указан действительной таблицей в Access. Это необходимо для начальной настройки пакета. Вот в этом случае я выбралCountry
, который существует в Access.Выберите переменную
SelectQuery
и нажмите F4, чтобы просмотреть панель свойств. На панели свойств установите свойствоEvaluateAsExpress
True и вставьте выражение"SELECT * FROM " + @[User::TableName]
вExpression
имущество. Это выражение будет соответствовать таблице, которая в данный момент проходит через. Смотрите скриншот №4Скриншоты № 5 и № 6 показывают, что таблицы
dbo.Country
а такжеdbo.StateProvince
не существует в SQL Server.Настройте
Control Flow
вкладка пакета служб SSIS, как показано на скриншоте # 7. ПоместитеScript Task
и подключить его кForeach Loop container
, Внутри контейнера поместитеExecute SQL Task
иData Flow Task
,Замените код в Задаче сценария на код, указанный в разделе "Код задачи сценария". Этот код будет зацикливать схему доступа и извлекать только имена таблиц. Список имен таблиц затем сохраняется в переменной пакета
AccessTables
, который затем будет использованForeach loop container
,В базе данных SQL Server создайте хранимую процедуру с именем
dbo.CreateTable
используя скрипт, предоставленный в разделе SQL Scripts. Эта хранимая процедура создаст таблицу в SQL Server, если она еще не существует.Make sure that you alter the table schema defined in the stored procedure according to your needs.
Настройте
Foreach loop container
как показано на скриншотах № 8 и № 9.Настройте задачу "Выполнение SQL", как показано на снимках экрана № 10 и № 11.
На этом этапе мы не можем настроить задачу потока данных, поскольку таблицы не существуют в SQL Server. Итак, мы выполним пакет на этом этапе, чтобы структуры таблицы Access были созданы в SQL Server. Снимок экрана № 12 показывает пример выполнения пакета. Снимок экрана № 13 показывает, что структуры таблиц были созданы в SQL Server, но они еще не заполнены данными.
Теперь мы настроим
Data Flow Task
, ПоместитеOLE DB Source
а такжеOLE DB Destination
внутри задачи потока данных. Подключите источник OLE DB к назначению OLE DB. Смотрите скриншот №14.Настройте
OLE DB Source
как показано на скриншотах № 15 и № 16.Настройте
OLE DB Destination
как показано на скриншотах № 17 и № 18.Снимок экрана № 19 показывает пример выполнения пакета в
Data Flow Task
,Снимок экрана № 20 показывает, что таблицы SQL Server теперь заполнены данными из таблиц доступа.
Этот пример будет работать только для таблиц, имеющих одинаковую структуру, но различающихся по имени. Если другая таблица с именем Employees
добавлены в доступ только с колонками Id
а также Name
, Выполнение этого примера пакета создаст ту же таблицу в 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
Код задачи скрипта:
C# код, который можно использовать только в 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:
Снимок экрана № 2:
Снимок экрана № 3:
Снимок экрана № 4:
Снимок экрана № 5:
Снимок экрана № 6:
Снимок экрана № 7:
Снимок экрана № 8:
Снимок экрана № 9:
Снимок экрана № 10:
Снимок экрана № 11:
Снимок экрана № 12:
Снимок экрана № 13:
Снимок экрана № 14:
Снимок экрана № 15:
Снимок экрана № 16:
Снимок экрана № 17:
Снимок экрана № 18:
Снимок экрана № 19:
Снимок экрана № 20:
Как кто-то, у кого есть доступ к Access, я сначала исправил бы данные в Access (т. Е. Объединил несколько таблиц в главные таблицы), а затем использовал помощник по миграции SQL Server для Access для увеличения размера. Это позволяет вам смоделировать импорт и исправить любые проблемы, прежде чем вы действительно это сделаете.
Первым этапом объединения таблиц данных я бы просто кодировал в VBA, хотя, вероятно, мне пришлось бы создать несколько таблиц с метаданными, которые отображали бы, что импортируется во что (если только таблицы не используют соглашения об именах, которые позволяют это определять алгоритмически).
Вы можете поместить результаты задачи sql в переменную типа object object. Затем эта переменная будет доступна для использования в задаче цикла.
Внутри цикла for вы можете изменить имя таблицы, с которой вы работаете, используя выражения.
После быстрого просмотра этой статьи может быть подробно описана первая часть процесса:
http://www.sqlservercentral.com/articles/Integration+Services+(SSIS)/64014/