Я пытаюсь загрузить данные из единственного файла (с миллионом + записи) в несколько таблиц на SQL Server с помощью 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
Если моя схема базы данных Office имеет следующие таблицы:
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 и не играл вокруг с автоматической генерацией идентификаторов и установлением отношений внешнего ключа при выполнении Задачи Потока данных. Любые указатели ценились бы.
Спасибо!
Если вы уверены, что ваша ссылочная целостность в порядке с данными, которые вы хотите загрузить , вы можете отключить ограничения внешнего ключа в задаче сценария, затем выполнить поток данных с параллельной загрузкой данных и после завершения загрузки данных снова включить ограничения. Если с данными что-то не так, операция завершится ошибкой. Однако вам придется разработать стратегию отката или очистки.
Другой вариант - просто загружать данные последовательно, начиная с основных таблиц и заканчивая дочерними таблицами. Я думаю, что это «более безопасный» вариант, поскольку он не раскрывает целостность ваших данных другим пользователям, которые могут использовать эти таблицы во время загрузки ETL. Я бы предпочел этот вариант.
вы можете написать хранимую процедуру, которая сначала вставляет данные в базовые таблицы (сотрудник, офис и JobTitle), а затем считывает ваш файл построчно. после этого вы должны выполнить поиск в основных таблицах для получения идентификаторов и вставить данные в таблицы отношений.
Вот как - это немного сложно объяснить только текстом, но я попробую:
Определите таблицы сотрудников, офисов и должностей в вашей базе данных со столбцом идентификации, чтобы идентификаторы генерировались автоматически.
Определите таблицы "многие ко многим" без него (идентификация не нужна и не полезна)
В потоке данных SSIS вы должны сделать это за несколько проходов, чтобы сначала установить идентификаторы в базе данных, а затем вернуться и вставить строки "многие ко многим".
Сделайте один поток данных:
После первого потока данных добавьте второй поток данных. Он будет заполнять строки отношения "многие-ко-многим"
Интересный вопрос. Вот как я бы это сделал (Sql Server 2005). (Я предполагаю, что это ежемесячная работа, а не разовая, поэтому я добавил код для обеспечения повторяемости.)
Вывод поступает в компонент сценария с тремя столбцами в плоском файле в качестве ввода, тремя табличными переменными, импортированными в сценарий, пятью выводами в компоненте сценария, каждый с тем же номером группы исключения, и ввод, отмеченный как синхронный для этого output, семь новых столбцов (3 для emp, по одному для каждого вывода, в котором он будет находиться, 2 для работы, 2 для офиса) добавлены к выходным данным и со следующим кодом (Ссылка на System.xml.dll должна быть добавлена в заставить все это работать.):
Импортирует System
Импортирует System.Data
Импортирует System.Math
Импортирует Microsoft.SqlServer.Dts.Pipeline.Wrapper
Импортирует Microsoft.SqlServer.Dts.Runtime.Wrapper
Импортирует систему.Коллекции
Импортирует System.Data.OleDb
Открытый класс ScriptMain
Наследует UserComponent
Private da As New OleDbDataAdapter {{1 }} 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
Общедоступные переопределения Sub PreExecute ()
maxempid = 0
maxjobid = 0
maxoffid = 0
da.Fill (emp, Me.Variables.EmpTab) {{1 }} Для каждого 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)
Для каждого dr As DataRow в job.Rows
jobh.Add (dr.Item ("titleName"), dr.Item ("nID "))
Если (CInt (dr.Item (" nID "). ToString)> maxempid) Then
maxjobid = CInt (dr.Item ("nID"). ToString)
End If
Next
da.Fill (off, Me.Variables.OffTab)
Для каждого 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. Имя сотрудника).ToString)
Row.Emp3Id = CInt (emph.Item (Row.EmployeeName) .ToString)
End If
If Not jobh.ContainsKey (Row.JobLevelHistory) Then {{1 }} maxjobid + = 1
jobh.Add (Row.JobLevelHistory, maxjobid)
Row.JobId = maxjobid
Row.Job2Id = maxjobid
Row.DirectRowToJobTitle ( )
Иначе
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) {{ 1}} 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
Результаты этого сценария (сценарий генерирует идентификаторы для новых значений во входных данных. Он делает это путем загрузки до существующую таблицу в хэш-таблицы в предварительно выполняемой части скрипта, затем путем проверки существования имени и на основе этого либо увеличивает maxid, либо добавляет его в хэш, если он добавляется к хешу, он также добавляет строку в соответствующий ( emp, job или off) или извлекает maxid из хэша для каждой строки.) вся строка независимо от состояния выше будет записана в два оставшихся выхода (emp2job и emp2off).