2010-02-06 2 views
7

Я пытаюсь загрузить данные из одного файла (с миллионами + записей) в несколько таблиц на SQL Server, используя SSIS, сохраняя отношения, определенные в файле.Загрузка нескольких таблиц с использованием SSIS, поддерживающих отношения внешних ключей

Чтобы лучше разобраться с примером, допустим, что я пытаюсь загрузить файл, содержащий имя сотрудника, офисы, которые они занимали в прошлом, и их историю заданий, разделенных вкладкой.

Файл:

EmployeeName<tab>OfficeHistory<tab>JobLevelHistory 
John Smith<tab>501<tab>Engineer 
John Smith<tab>601<tab>Senior Engineer 
John Smith<tab>701<tab>Manager 
Alex Button<tab>601<tab>Senior Assistant 
Alex Button<tab>454<tab>Manager 

Если моя схема базы данных Управление имеет следующие таблицы:

Employee (nId, name) 
Office (nId, number) 
JobTitle (nId, titleName) 
Employee2Office (nEmpID, nOfficeId) 
Employee2JobTitle (nEmpId, nJobTitleID) 

Как я могу использовать SSIS для загрузки файла в схеме выше автоматической генерации идентификаторов для сотрудника, Office и JobTitle и поддерживая отношения между сотрудником и офисами, а также служащими и названиями заданий?

Так что в этом случае. таблицы должны выглядеть следующим образом:

Employee 
1 John Smith 
2 Alex Button 

Office 
1 501 
2 601 
3 701 
4 454 

JobTitle 
1 Engineer 
2 Senior Engineer 
3 Manager 
4 Senior Assistant 

Employee2Office 
1 1 
1 2 
1 3 
2 2 
2 4 

Employee2JobTitle 
1 1 
1 2 
1 3 
2 4 
2 3 

Я новичок в SSIS и не играл с автоматической генерацией идентификаторов и установлением внешних ключей отношений при выполнении задачи потока данных. Любые указатели будут оценены.

Спасибо!

+0

Мой первый вопрос: как ваш импорт будет знать, являются ли две записи с тем же именем одним и тем же лицом или разными людьми? Поскольку имена не уникальны, вы должны иметь способ в файле знать, что есть. – HLGEM

+0

Хороший вопрос. Предположим, мы предполагаем, что для этого сценария имя сотрудника уникально. Таким образом, в этой организации будет только один Джон Смит. – mvm

ответ

1

Если вы уверены, что ваша ссылочная целостность в порядке с данными, которые вы хотите загрузить, вы можете отключить ограничения внешнего ключа в задаче скрипта, затем выполнить поток данных с параллельной загрузкой данных и после завершения загрузки данных, включить ограничения снова. Если с данными что-то не так, операция завершится неудачно. Однако вам придется разрабатывать стратегию отката или очистки.

Другой вариант - просто загрузить данные в последовательном порядке, начиная с основных таблиц и заканчивая дочерними таблицами. Я думаю, что это «безопасный» вариант, поскольку он не раскрывает вашу целостность данных другим пользователям, которые могут использовать эти таблицы во время загрузки ETL. Я бы предпочел этот вариант.

+0

Для первого варианта, как установить сопоставления в Employee2JobTitle и Employee2Office после загрузки данных? Предоставление данных пользователям не является актуальной проблемой в моем мире. Второй вариант потребует много времени для больших наборов данных. – mvm

0

вы можете написать хранимую процедуру, которая сначала вставляет данные в основные таблицы (сотрудник, офис и JobTitle), а затем читает ваш файл подряд за строкой. после этого вы должны искать свои базовые таблицы для получения идентификаторов и вставки данных в таблицы отношений.

1

Вот как - это немного трудно объяснить только текст, но я дам ему выстрелили:

Define работника, офиса и название задания таблиц в базе данных с столбца идентификации, так что идентификаторы будут создаваться автоматически.

Определить многие-ко-многим таблиц без (идентичность не нужны или полезные)

В вашем потоке данных SSIS, вы должны сделать это в несколько проходов, чтобы установить идентификаторы в сначала, затем вернитесь и вставьте строки «многие-ко-многим».

Сделать поток данных один:

  1. Поместите источник данных для чтения в файле
  2. разделить его на три копии с Multi-Cast. Один будет для сотрудников, одного офиса, одного звания.
  3. Для каждого поместите Сортировку (это, как правило, нет-нет, но поскольку источником является текст, а не база данных, мы должны туда поехать). Установите сортировку для прохождения только одного из трех полей и установите флажок в сортировке для удаления дубликатов. Это делает уникальный список (например, отдельный отчет) для каждой базовой таблицы.
  4. Поместите пункт назначения для каждого из трех, подключенных к каждой таблице.

После первого потока данных добавьте второй поток данных. Это один заполнит много-ко-многим строк

  1. Прочитайте файл с источником данных
  2. Добавить поиск, который находит для имени сотрудника в базе данных и возвращает идентификатор сотрудника. Это дает вам идентификатор сотрудника, который был сгенерирован выше. (это обычно называется поиском по бизнес-или натуральному ключу для суррогатного ключа)
  3. Добавить поиск, который находит для заголовка в базе данных, и возвращает идентификатор заголовка
  4. Добавить поиск, который находит для Office в базе данных, и возвращает Office ID
  5. Опять же, мульти-листинг результатов в двух экземплярах, один для сотрудника-офиса и один для сотрудника-титула
  6. В зависимости от логики, в которой вы нуждаетесь, возможно, снова используйте Сортировку для дедупликации (в зависимости от детали как вы нормализуетесь от ввода)
  7. Поместите результаты в таблицы «многие-ко-многим» с двумя пунктами назначения.
2

Интересный вопрос. Вот как я это сделаю (Sql Server 2005). (Я предполагаю, что это ежемесячная работа, а не только один раз, так что я добавил код для воспроизводимости.)

  1. Создайте три переменные для сотрудника, JobTitle и Стол офисный (тип = Object)
  2. Используйте три задачи sql, чтобы выбрать строки для этих трех таблиц в соответствующие переменные.
  3. Добавить задачу потока данных.
  4. Выберите нужный файл, используя плоский файл.
  5. Выход идет в компонент сценария с тремя столбцами в плоском файле в качестве входных данных, тремя переменными таблицы, импортированными в скрипт, пятью выводами в компоненте сценария, каждый с тем же номером группы исключений, и вход, помеченный как синхронный для этот вывод, семь новых столбцов (3 для emp по одному для каждого вывода, в котором он будет находиться, 2 для задания, 2 для офиса), добавленный к выходу, и со следующим кодом (A Reference to System.xml.dll должен быть добавлен чтобы сделать это все работы):.

    Imports System 
    Imports System.Data 
    Imports System.Math 
    Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper 
    Imports Microsoft.SqlServer.Dts.Runtime.Wrapper 
    Imports System.Collections 
    Imports System.Data.OleDb 
    
    Public Class ScriptMain 
        Inherits UserComponent 
    
        Private da As New OleDbDataAdapter 
        Private emp As New DataTable 
        Private emph As New Hashtable() 
        Private job As New DataTable 
        Private jobh As New Hashtable() 
        Private off As New DataTable 
        Private offh As New Hashtable() 
        Private maxempid As Integer 
        Private maxjobid As Integer 
        Private maxoffid As Integer 
    
        Public Overrides Sub PreExecute() 
         maxempid = 0 
         maxjobid = 0 
         maxoffid = 0 
         da.Fill(emp, Me.Variables.EmpTab) 
         For Each dr As DataRow In emp.Rows 
          emph.Add(dr.Item("Name"), dr.Item("nID")) 
          If (CInt(dr.Item("nID").ToString) > maxempid) Then 
           maxempid = CInt(dr.Item("nID").ToString) 
          End If 
         Next 
         da.Fill(job, Me.Variables.JobTab) 
         For Each dr As DataRow In job.Rows 
          jobh.Add(dr.Item("titleName"), dr.Item("nID")) 
          If (CInt(dr.Item("nID").ToString) > maxempid) Then 
           maxjobid = CInt(dr.Item("nID").ToString) 
          End If 
         Next 
         da.Fill(off, Me.Variables.OffTab) 
         For Each dr As DataRow In off.Rows 
          offh.Add(dr.Item("number"), dr.Item("nID")) 
          If (CInt(dr.Item("nID").ToString) > maxempid) Then 
           maxoffid = CInt(dr.Item("nID").ToString) 
          End If 
         Next 
         emp.Dispose() 
         job.Dispose() 
         off.Dispose() 
         da.Dispose() 
         MyBase.PreExecute() 
        End Sub 
    
    Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer) 
    
        If Not emph.ContainsKey(Row.EmployeeName) Then 
         maxempid += 1 
         emph.Add(Row.EmployeeName, maxempid) 
         Row.EmpId = maxempid 
         Row.Emp2Id = maxempid 
         Row.Emp3Id = maxempid 
         Row.DirectRowToEmployee() 
        Else 
         Row.EmpId = CInt(emph.Item(Row.EmployeeName).ToString) 
         Row.Emp2Id = CInt(emph.Item(Row.EmployeeName).ToString) 
         Row.Emp3Id = CInt(emph.Item(Row.EmployeeName).ToString) 
        End If 
        If Not jobh.ContainsKey(Row.JobLevelHistory) Then 
         maxjobid += 1 
         jobh.Add(Row.JobLevelHistory, maxjobid) 
         Row.JobId = maxjobid 
         Row.Job2Id = maxjobid 
         Row.DirectRowToJobTitle() 
        Else 
         Row.JobId = CInt(jobh.Item(Row.JobLevelHistory).ToString) 
         Row.Job2Id = CInt(jobh.Item(Row.JobLevelHistory).ToString) 
        End If 
        If Not offh.ContainsKey(Row.OfficeHistory) Then 
         maxoffid += 1 
         offh.Add(Row.OfficeHistory, maxoffid) 
         Row.OffId = maxoffid 
         Row.Off2Id = maxoffid 
         Row.DirectRowToOfficeNumber() 
        Else 
         Row.OffId = CInt(offh.Item(Row.OfficeHistory).ToString) 
         Row.Off2Id = CInt(offh.Item(Row.OfficeHistory).ToString) 
        End If 
        Row.DirectRowToEmp2Job() 
        Row.DirectRowToEmp2Off() 
    End Sub   
    End Class 
    
  6. результатов этого сценария (скрипт генерирует идентификаторы для новых значений во входных данных Она делает это путем загрузки до существующей таблицы в хеш-таблицу в preexecute части. сценарий, затем, проверяя наличие имени и основываясь на этом, либо увеличивает maxid, либо добавляет его в хэш, если он добавляет хэш, он также добавляет строку к соответствующему (emp, job или off) output, или извлекает maxid из хэша для каждой строки.) вся строка независимо от состояния выше будет записана на два оставшихся выхода (emp2job и emp2off).

  7. Затем отправьте потоки данных для поиска (чтобы проверить существующие строки в таблице назначения, а затем соединители назначения oledb (emp, job и off) установите флажок для вставок идентификаторов, emp2job и emp2off для отмены контрольных ограничений).
+1

Отличный ответ и хороший пример кодирования. – ajdams

Смежные вопросы