Talend将平面文件规范化为关系数据库表

时间:2014-12-10 00:47:51

标签: etl talend database-normalization

我们有一个单独的源表,它是平的 - 我们需要将给定记录中的不同字段插入到多个表中。我们一次成功使用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中此类数据规范化的最佳做法是什么?

2 个答案:

答案 0 :(得分:2)

我会迭代地接近这个,用每一步规范化表格的一部分。

您应该能够在一步中将人员数据从地址,状态和zip数据中标准化,然后将状态标准化为远离地址和z​​ip数据,然后最终将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组件轻松完成一些示例数据填充它:

Row generating job layout

我已经配置tRowGenerator给我们一些半合理的测试输出:

tRowGenerator component

我还添加了一个额外的步骤,使用以下tMap配置向〜1/3地址添加一些共同控制器:

tMap configuration to add co-habitors to some addresses

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

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

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登台表中:

Normalise people data job layout

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

tMap configuration to get Address_id for person table

其余步骤现在非常相似。

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

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表中获取唯一的状态并将它们放入状态表中:

Normalise state data job layout

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

tMap configuration to get State_id for addressZip table

现在,最后,我们可以创建我们的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表中:

Normalise zip data job layout

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

tMap configuration to get Zip_id for address table

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

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);

答案 1 :(得分:0)

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

假设[名字,姓氏]是唯一的,人们可以分享地址我会:

  1. 插入 Zip 状态,检查它们是否已存在。在那种情况下不会插入;
  2. 状态 Zip 上插入地址,以获取 state_id zip_id
  3. 首先在 Zip 状态上插入。然后查找地址以获取 address_id ,并在人员上进行最终插入(如果它尚不存在)。
  4. 如果[名字,姓氏]不是唯一的或由于某种原因我不希望他们共享地址,拉链或状态我通常会强制源有某种ID,像LINE_NUMBER这样的显式或隐式的,所以我们可以区分人。插入顺序将是相同的,但在这种情况下,我使用 people_id 来区分地址,zip和状态甚至是某些查找中的人,具体取决于预期的结果。

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