如何拆分平面文件数据并加载到数据库中的父子表?

时间:2011-07-12 01:10:24

标签: sql-server sql-server-2008 import ssis etl

我有需要导入父子表的非规范化数据(来自文件)。源数据是这样的:

Account#    Name        Membership    Email
101         J Burns     Gold          alpha@foo.com
101         J Burns     Gold          bravo@foo.com
101         J Burns     Gold          charlie@yay.com
227         H Gordon    Silver        red@color.com
350         B Clyde     Silver        italian@food.com
350         B Clyde     Silver        mexican@food.com

我应该使用SSIS的哪些部分,部分或策略将前三列读入父表,将第4列(电子邮件)读入子表?我可以选择父键的几个选项:

  • 直接使用帐号#作为主键
  • 在导入过程中使用SSIS生成的代理键
  • 配置标识主键

我确信我已经按照增加难度的顺序列出了我的主键选项。我有兴趣知道如何做第一个和最后一个选项 - 我将推断如何实现中间选项。再次强调,我对一个明确的SSIS解决方案很感兴趣;我正在寻找使用SSIS语言的答案,而不是程序性的,技术中立的答案。

我的问题有点类似于another SO question,有一个模糊可行性的答案。我希望能给出更详细的指导。我已经知道如何通过创建一个“临时”中间步骤来解决这个问题,其中父子分离实际上是用直接SQL处理的。但是,我很好奇如果没有这种中间步骤可以做到这一点。

在我看来,这种重要性是如此常见,以至于会有一种公布的方法来处理它 - 这是SSIS擅长的一种技术。到目前为止,我还没有看到任何直接答案。

Update #1 :根据评论,我调整了示例数据,使其更加明显地非规范化。我还从“平面文件”中删除了“flat”,这样语义就不会干扰这个问题。

Update #2 :我已经放大了对使用SSIS语言的解决方案的兴趣。

2 个答案:

答案 0 :(得分:31)

以下是加载父子数据时可以考虑的一个可能选项。此选项包含两个步骤。在第一个步骤中,读取源文件并将数据写入父表。在第二个步骤中,再次读取源文件并使用查找转换来获取父信息,以便将数据写入子表。以下示例使用问题中提供的数据。此示例是使用SSIS 2008 R2和SQL Server 2008数据库创建的。

分步流程:

  1. 创建名为Source.txt的示例平面文件,如屏幕截图# 1 所示。

  2. 在SQL数据库中,使用 SQL Scripts 部分下提供的脚本创建两个名为dbo.Parentdbo.Child的表。这两个表都有一个自动生成的标识列。

  3. 在包上,放置OLE DB connection以连接到SQL Server,并Flat File connection读取源文件,如屏幕截图# 2 所示。配置平面文件连接,如屏幕截图# 3 - # 9 所示。

  4. 在“控制流”标签上,放置两个Data Flow Tasks,如屏幕截图# 10 所示。

  5. 在名为 Parent 的数据流任务中,放置一个平面文件源,排序转换和OLE DB目标,如屏幕截图# 11 所示。

  6. 配置平面文件来源,如屏幕截图# 12 和# 13 所示。我们需要阅读平面文件源。

  7. 配置排序转换,如屏幕截图# 14 所示。我们需要消除重复值,以便只将唯一记录插入父表dbo.Parent

  8. 配置ole db目标,如屏幕截图# 15 和# 16 所示。我们需要将数据插入父表dbo.Parent

  9. 在名为 Child 的数据流任务中,放置一个平面文件源,查找转换和一个OLE DB目标,如屏幕截图# 17 所示。

  10. 配置平面文件来源,如屏幕截图# 12 和# 13 所示。此配置与先前数据流任务中的平面文件源相同。

  11. 配置查找转换,如屏幕截图# 18 和# 20 所示。我们需要使用文件中存在的其他键列从表dbo.Parent中找到父ID。这里的关键列是帐户,名称和电子邮件。如果文件碰巧有一个唯一列,您可以单独使用该列来获取父ID。

  12. 配置ole db目标,如屏幕截图# 21 和# 22 所示。我们需要将电子邮件列和父ID一起插入表dbo.Child

  13. 屏幕截图# 23 会在 包执行之前的表中显示数据。

  14. 屏幕截图# 24 和# 25 显示示例包执行。

  15. 屏幕截图# 26 会在包执行后表格中显示数据。

  16. 希望有所帮助。

    SQL脚本:

    CREATE TABLE [dbo].[Child](
        [ChildId] [int] IDENTITY(1,1) NOT NULL,
        [ParentId] [int] NULL,
        [Email] [varchar](21) NULL,
    CONSTRAINT [PK_Child] PRIMARY KEY CLUSTERED ([ChildId] ASC)) ON [PRIMARY]
    GO
    
    CREATE TABLE [dbo].[Parent](
        [ParentId] [int] IDENTITY(1,1) NOT NULL,
        [Account] [varchar](12) NULL,
        [Name] [varchar](12) NULL,
        [Membership] [varchar](14) NULL,
    CONSTRAINT [PK_Parent] PRIMARY KEY CLUSTERED ([ParentId] ASC)) ON [PRIMARY]
    GO
    

    屏幕截图#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

    屏幕截图#21:

    21

    屏幕截图#22:

    22

    屏幕截图#23:

    23

    屏幕截图#24:

    24

    屏幕截图#25:

    25

    屏幕截图#26:

    26

答案 1 :(得分:0)

如果数据已排序且Account#为整数,我会:

将电子邮件插入表格(添加自动增量列,这是最佳做法)。

1  101    alpha@foo.com
2  101    bravo@foo.com
3  101    charlie@yay.com
etc.

然后我会将其他记录插入父表。

  • 使用帐号#作为主键
  • 省略电子邮件地址
  • 跳过重复项(如果数据很容易 已分类)。

如果您设置了外键关系,则需要先执行第二步(避免使用任何孤立记录)。

我的两分钱:我不知道你的要求是什么,但似乎有点过于规范化了。如果电子邮件地址的数量有一个小的限制,我会考虑在主表中添加几个电子邮件列...以提高速度和简单性。