我正在尝试使用SSIS将数据从单个文件(带有百万条+记录)加载到SQL Server上的多个表中,同时保持文件中定义的关系。
为了更好地举例说明,我们假设我正在尝试加载一个包含员工姓名的文件,他们过去占用的办公室以及用标签分隔的职位名称历史记录。
文件:
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的ID以及维护员工和办公室之间以及员工和职位标题之间的关系模式中?
所以在这种情况下。表格应如下所示:
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的新手,并且在执行数据流任务时没有使用自动生成ID和建立外键关系。任何指针都会受到赞赏。
谢谢!
答案 0 :(得分:2)
一个有趣的问题。这是我将如何做到这一点(Sql Server 2005)。 (我假设这是一个月工作而不只是一次,所以我添加了重复性代码。)
输出进入脚本组件,平面文件中的三列作为输入,三个表变量导入脚本,脚本组件中的五个输出,每个输出具有相同的排除组编号,输入标记为对于该输出同步,添加到输出的七个新列(每个输出3个用于emp一个,2个用于作业,2个用于office),并使用以下代码(对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
此脚本的结果(该脚本为输入数据中的新值生成id。它通过将现有表加载到脚本的预执行部分中的哈希表中,然后检查是否存在名称,并基于此增加maxid并将其添加到哈希,如果它添加到哈希,它还将行添加到适当的(emp,job或off)输出,或从每行的哈希中检索maxid 。)无论上述状态如何,所有行都将写入剩余的两个输出(emp2job和emp2off)。
答案 1 :(得分:1)
如果您确定要加载的数据的参照完整性正常,则可以在脚本任务中禁用外键约束,然后使用并行数据加载执行数据流,并在数据加载完成后启用约束再次。如果数据不正确,操作将失败。您必须设计回滚或清理策略。
另一种选择只是以串行方式加载数据,从主表开始并在子表上完成。我认为这是“更安全”的选项,因为它不会将您的数据完整性暴露给在ETL加载时可能正在使用这些表的其他用户。我更喜欢这个选项。
答案 2 :(得分:1)
这是怎么回事 - 在文本中解释起来有点困难,但我会试一试:
使用标识列定义数据库中的员工,办公室和职位名称表,以便自动生成ID。
定义多对多表(不需要身份或有用身份)
在您的SSIS数据流中,您必须在几次传递中执行此操作,以便首先在数据库中建立ID,然后返回并插入多对多行。
制作一个数据流:
在第一个数据流之后,添加第二个数据流。这个将填充多对多关系行
答案 3 :(得分:0)
您可以编写一个存储过程,首先在基本表(employee,office和JobTitle)中插入数据,然后逐行读取您的文件。之后,您应该搜索基本表以获取标识并将数据插入关系表。