【问题标题】:Talend Normalize Flat File into Relational Database TablesTalend 将平面文件规范化为关系数据库表
【发布时间】:2014-12-10 00:47:51
【问题描述】:

我们有一个单一的源表,它是平面的——我们需要将给定记录中的不同字段插入到多个表中。我们一次成功地使用了 lastInsertID,但我们正在努力解决如何在后续相关表中再次从同一源行重新添加字段。

例如,如果我们有一个邮寄地址(愚蠢的例子即将出现,但有利于共同讨论)

-----------Source----------
First Name
Middle Name
Last Name
Address 1
Address 2
City
State
Zip

-----------Targets-------------

People
 address_id
 First Name
 Last Name

Address
 address_id
 state_id
 zip_id
 Address 1
 Address 2

States
 state_id
 State Name

Zip
 zip_id
 Zip Code

此外,我们不能确定我们可能不需要将同一列添加到多个表中。

在 Talend 中这种数据规范化的最佳实践是什么?

【问题讨论】:

    标签: etl talend database-normalization


    【解决方案1】:

    我会迭代地处理这个问题,每一步都规范化表格的一部分。

    您应该能够一步将人员数据与地址、状态和 zip 数据进行规范化,然后将状态与地址和 zip 数据进行规范化,最后将 zip 数据与地址的其余部分进行规范化.

    作为一个例子,从你问题中的例子开始,这里有一些工作可以做到这一点:

    首先,我们应该创建示例数据。我将在本示例中使用 MySQL,但相同的原则适用于任何主要的 RDBMS。

    让我们先创建一个空表:

    DROP DATABASE IF EXISTS normalisation;
    
    CREATE DATABASE IF NOT EXISTS normalisation
    CHARACTER SET utf8 COLLATE utf8_unicode_ci;
    
    CREATE TABLE IF NOT EXISTS normalisation.denormalised (
        FirstName VARCHAR(255),
        MiddleName VARCHAR(255),
        LastName VARCHAR(255),
        Address1 VARCHAR(255),
        Address2 VARCHAR(255),
        City VARCHAR(255),
        State VARCHAR(255),
        Zip VARCHAR(255)
    ) ENGINE = INNODB;
    

    我们需要在其中填充一些示例数据,这些数据可以使用 Talend 的 tRowGenerator 组件轻松完成:

    我已经配置了 tRowGenerator 来给我们一些半明智的测试输出:

    我还添加了一个额外的步骤,使用以下 tMap 配置将一些同居者添加到大约 1/3 的地址:

    现在我们已经轻松生成了测试数据,我们可以继续对这个非规范化表中的数据进行实际规范化。

    如上所述,我们的第一步是将人员数据标准化。我们首先为人员数据和剩余的地址数据创建必要的表:

    CREATE TABLE IF NOT EXISTS normalisation.person (
        Person_id BIGINT AUTO_INCREMENT PRIMARY KEY,
        FirstName VARCHAR(255),
        MiddleName VARCHAR(255),
        LastName VARCHAR(255),
        Address_id BIGINT
    ) ENGINE = INNODB;
    
    CREATE TABLE IF NOT EXISTS normalisation.addressStateZip (
        Address_id BIGINT AUTO_INCREMENT PRIMARY KEY,
        Address1 VARCHAR(50),
        Address2 VARCHAR(50),
        City VARCHAR(50),
        State VARCHAR(50),
        Zip VARCHAR(50),
        UNIQUE KEY addressStateZip (Address1, Address2, City, State, Zip)
    ) ENGINE = INNODB;
    

    然后我们通过获取所有地址类型数据来填充这两个表,只获取唯一的行,然后将其放入 addressStateZip 临时表中:

    上述工作的第二部分然后将 addressStateZip 数据与初始非规范化表进行比较,并收集连接以获得人员表的 Address_id:

    其余步骤现在非常相似。

    接下来我们为地址和邮编数据创建状态表和另一个临时表:

    CREATE TABLE IF NOT EXISTS normalisation.state (
        State_id BIGINT AUTO_INCREMENT PRIMARY KEY,
        State VARCHAR(255),
        UNIQUE KEY state (State)
    ) ENGINE = INNODB;
    
    CREATE TABLE IF NOT EXISTS normalisation.addressZip (
        Address_id BIGINT AUTO_INCREMENT PRIMARY KEY,
        Address1 VARCHAR(50),
        Address2 VARCHAR(50),
        City VARCHAR(50),
        State_id BIGINT,
        Zip VARCHAR(50),
        UNIQUE KEY addressStateZip (Address1, Address2, City, State_id, Zip)
    ) ENGINE = INNODB;
    

    现在我们需要从 addressStateZip 表中取出唯一的状态并将它们放入状态表中:

    第二部分和之前一样,然后使用 State_id 而不是实际状态将数据创建到 addressZip 临时表中:

    现在,最后,我们可以创建 zip 表,然后将其链接到正确的地址表:

    CREATE TABLE IF NOT EXISTS normalisation.zip (
        Zip_id BIGINT AUTO_INCREMENT PRIMARY KEY,
        ZIP VARCHAR(255),
        UNIQUE KEY zip (ZIP)
    ) ENGINE = INNODB;
    
    CREATE TABLE IF NOT EXISTS normalisation.address (
        Address_id BIGINT AUTO_INCREMENT PRIMARY KEY,
        Address1 VARCHAR(50),
        Address2 VARCHAR(50),
        City VARCHAR(50),
        State_id BIGINT,
        Zip_id BIGINT,
        UNIQUE KEY addressStateZip (Address1, Address2, City, State_id, Zip_id)
    ) ENGINE = INNODB;
    

    使用与状态数据相同的方法,我们获取所有唯一的 zip 并将它们放入 zip 表中:

    而且,和以前一样,我们现在可以将 Zip_id 放入一个新的、已完成的地址表中:

    为了检查,我们现在可以运行以下查询来获取所有数据:

    SELECT p.FirstName, p.MiddleName, p.LastName, a.Address1, a.Address2, a.City, s.State, z.Zip
    FROM normalisation.person AS p
    INNER JOIN normalisation.address AS a ON a.Address_id = p.Address_id
    INNER JOIN normalisation.state AS s ON s.State_id = a.State_id
    INNER JOIN normalisation.zip AS z ON z.Zip_id = a.Zip_id;
    

    既然您已经完成设置,您可能还想为表添加一些外键约束:

    ALTER TABLE normalisation.person
    ADD FOREIGN KEY (Address_id) REFERENCES address(Address_id);
    
    ALTER TABLE normalisation.address
    ADD FOREIGN KEY (State_id) REFERENCES state(State_id),
    ADD FOREIGN KEY (Zip_id) REFERENCES zip(Zip_id);
    

    【讨论】:

      【解决方案2】:

      我非常怀疑这是最佳做法,但这是我所知的最佳做法。对于这类东西,我有两种不同的方法:

      假设 [First Name, Last Name] 是唯一的并且人们可以共享地址,我会:

      1. 插入 ZipStates 检查它们是否已经存在。在那种情况下不会插入;
      2. 插入 Address 并查找 StatesZip 以获取 state_idzip_id强>。
      3. 插入 People,首先在 ZipStates 上进行查找。然后查找 Address 以获取 address_id 并最终插入 People(如果它尚不存在)。

      如果 [First Name, Last Name] 不是唯一的,或者出于某种原因我不希望他们共享地址、邮编或状态,我通常会强制来源具有某种 ID,像 LINE_NUMBER 这样的显式或隐式,以便我们可以区分人。然后插入顺序将是相同的,但在这种情况下,我使用 people_id 来区分地址、zip 和状态,甚至在某些查找中区分人员,具体取决于预期结果。

      最后一种方法有点脏,因为我们最终可能会得到只需要插入的无用 ID。为了避免这种情况,我会使用带有额外字段的 tmp 表,最后只是盲目地插入最终表中。如果这不是一次性插入,则需要在 tmp 和最终表同步上进行一些额外的逻辑。

      【讨论】:

        猜你喜欢
        • 2013-09-01
        • 2013-01-29
        • 2016-03-21
        • 2010-09-18
        • 1970-01-01
        • 2016-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多