标准化低完整性的表

时间:2020-03-05 18:38:38  来源:igfitidea点击:

我已经交给一张约有18000行的表格。每条记录都描述一个客户的位置。问题是,当该人创建表时,他们没有添加"公司名称"字段,只有"位置名称"字段,而一个公司可以有多个位置。

例如,以下是描述同一客户的一些记录:

位置表

ID  Location_Name     
 1   TownShop#1        
 2   Town Shop - Loc 2 
 3   The Town Shop     
 4   TTS - Someplace   
 5   Town Shop,the 3   
 6   Toen Shop4

我的目标是使其看起来像:

位置表

ID  Company_ID   Location_Name     
 1   1            Town Shop#1       
 2   1            Town Shop - Loc 2 
 3   1            The Town Shop     
 4   1            TTS - Someplace   
 5   1            Town Shop,the 3   
 6   1            Toen Shop4

公司表

Company_ID  Company_Name  
 1           The Town Shop

没有"公司"表,我将不得不从代表多个地点的最具描述性或者最佳地点名称中生成"公司名称"列表。

当前,我在想我需要生成一个相似的位置名称列表,然后手动查看该列表。

我对如何解决此问题的任何建议表示赞赏。

@Neall,谢谢发言,但不幸的是,每个位置名称都是不同的,没有重复的位置名称,只有相似的位置名称。因此,在语句结果中," repcount"在每一行中均为1.

@yukondude,第4步是我的问题的核心。

解决方案

回答

我以前必须这样做。唯一真正的方法是手动匹配各个位置。使用数据库的控制台界面,并对select语句进行分组。首先,添加"公司名称"字段。然后:

SELECT count(*) AS repcount, "Location Name" FROM mytable
 WHERE "Company Name" IS NULL
 GROUP BY "Location Name"
 ORDER BY repcount DESC
 LIMIT 5;

找出列表顶部位置所在的公司,然后使用UPDATE ... WHERE" Location Name" =" The Location"语句更新公司名称字段。

P.S.我们实际上应该将公司名称和位置名称分成单独的表,并通过其主键引用它们。

更新:哇没有重复吗?我们有几条记录?

回答

请更新问题,我们有可用的公司名称列表吗?我问是因为我们也许可以使用Levenshtein算法在CompanyNames和LocationNames列表之间找到关系。

更新

There is not a list of Company Names, I will have to generate the company name from the most descriptive or best Location Name that represents the multiple locations.

好吧...试试这个:

  • 通过查找由大部分或者所有字母字符组成的LocationName来建立候选CompanyName的列表。我们可以为此使用正则表达式。将此列表存储在单独的表中。
  • 按字母顺序对列表进行排序,并(手动)确定哪些条目应为公司名称。
  • 将每个CompanyName与每个LocationName进行比较,并得出一个匹配分数(使用Levenshtein或者其他一些字符串匹配算法)。将结果存储在单独的表中。
  • 设置阈值得分,以使任何MatchScore <阈值都不会被视为给定公司名称的匹配项。
  • 手动审核LocationNames by CompanyName | LocationName | MatchScore,并找出实际匹配的内容。通过MatchScore进行订购应该可以减轻过程的痛苦。

上述操作的全部目的是使部件自动化并限制问题的范围。它远非完美,但有望为我们省去手工处理18K记录的麻烦。

回答

我打算推荐一些复杂的令牌匹配算法,但是正确处理起来确实很棘手,如果数据没有很多相关性(打字错误等),那么它就不会给出很好的结果。

我建议我们将工作提交给Amazon Mechanical Turk,然后由人工进行分类。

回答

理想情况下,我们可能想要一个名为Company的单独表,然后在此" Location"表中需要一个company_id列,该列是Company表的主键的外键,可能称为id。这样可以避免该表中的大量文本重复(超过18,000行,整数外键将在varchar列上节省相当多的空间)。

但是我们仍然面临着加载该Company表,然后将其与Location中的行正确关联的方法。没有通用的解决方案,但是我们可以按照以下方式做一些事情:

  • 创建公司表,其id列会自动递增(取决于RDBMS)。
  • 查找所有唯一的公司名称,并将其插入"公司"中。
  • 将一列company_id添加到Location(该列现在接受NULL),并且这是Company.id列的外键。
  • 对于"位置"中的每一行,确定相应的公司,然后使用该公司的ID更新该行的company_id列。这可能是最具挑战性的步骤。如果数据与示例中显示的一样,则可能必须使用各种字符串匹配方法来进行多次运行。
  • 一旦Location中的所有行都具有company_id值,则可以更改Company表以将not NULL约束添加到company_id列中(假设每个位置都必须有一个公司,这似乎很合理)。

如果可以复制Location表,则可以逐步构建一系列SQL语句来填充company_id外键。如果输入有误,则可以重新开始并重新运行脚本,直到失败为止。

回答

是的,我上一篇文章中的第4步令人费解。

无论如何,我们可能必须手动执行其中的一些操作,但是我们可以自动执行其中的大部分操作。对于我们给出的示例位置,类似以下的查询将设置适当的company_id值:

UPDATE  Location
SET     Company_ID = 1
WHERE   (LOWER(Location_Name) LIKE '%to_n shop%'
OR      LOWER(Location_Name) LIKE '%tts%')
AND     Company_ID IS NULL;

我相信这将与示例匹配(我添加了" IS NULL"部分以不覆盖先前设置的Company_ID值),但是当然,在18,000行中,我们将必须具有相当的创造力才能处理各种组合。

其他可能有用的方法是使用Company中的名称来生成类似上面的查询。我们可以执行以下操作(在MySQL中):

SELECT  CONCAT('UPDATE Location SET Company_ID = ',
        Company_ID, ' WHERE LOWER(Location_Name) LIKE ',
        LOWER(REPLACE(Company_Name), ' ', '%'), ' AND Company_ID IS NULL;')
FROM    Company;

然后只运行它产生的语句。那可以为我们完成很多垃圾工作。