如何链接包含不同列和ID的相同产品的许多表

Tal*_*lor 16 mysql sql database-design

我有来自不同供应商的许多表格,其中包含有关他们提供的产品的信息.表的格式是不同的 - 不同的ID,不同的描述等 - 因为每个供应商存储关于其产品的单独信息.不同表中的某些产品可能是相同的但我不知道插入行时的情况; 我必须手动完成它们以确定哪些产品是相同的.

例如,请考虑以下表(SQL Fiddle):

CREATE TABLE A (
  id char(10)PRIMARY KEY,
  name char(16),
  color char(16),
  weight float
  );

CREATE TABLE B (
  id int(11) PRIMARY KEY,
  name varchar(60),
  color char(3)
  );
Run Code Online (Sandbox Code Playgroud)

每个表可能具有不同的ID值,列,甚至同一列的值; 例如:

Table A:
+------------+-----------------+---------------+-----------------+
|         ID |            NAME |         COLOR |          WEIGHT |
+------------+-----------------+---------------+-----------------+
| RFY-55-001 |  Wagon, Classic |           Red | 15.199999809265 |
| RFY-62-001 | Trike, My First |           Red |   8.60000038147 |
| RFY-64-001 |  Trike, 12 Inch |           Red |  15.39999961853 |
| SWN-35-001 | Trike, Roadster | Metallic Blue | 20.700000762939 |
| SWN-35-002 | Trike, Roadster |        Silver | 20.700000762939 |
| SWN-35-003 | Trike, Roadster |    Cherry Red | 20.700000762939 |
+------------+-----------------+---------------+-----------------+

Table B:
+-------+--------------------------------------------+--------+
|    ID |                                       NAME |  COLOR |
+-------+--------------------------------------------+--------+
| 10560 |                  Schwinn Roadster Tricycle |    BLU |
| 10685 |              Radio Flyer Classic Red Wagon | (null) |
| 10880 | Radio Flyer Classic Red Dual Deck Tricycle | (null) |
| 12008 |         Fisher-Price I Can Play Basketball | (null) |
+-------+--------------------------------------------+--------+
Run Code Online (Sandbox Code Playgroud)

供应商A存储简短的产品名称,但在其他列中包含详细的产品信息.供应商B存储更详细的产品名称,但没有更多的附加信息.在这两种情况下,制造商的身份都混合到其他一些领域.

行自动插入,我无法在插入之前检查每个产品.我只能偶尔检查它们并更新我手动找到的链接.例如,一项小小的研究表明,Radio Flyer Classic Red双层三轮车有一个12英寸的前轮,重15.4磅,表明RFY-64-001表A中的项目10880与表B中的项目相同.

如果在插入相同的产品后,我会使用什么关系来"链接"不同表中的行,以便每个独特的产品都有一个密钥?

显而易见的解决方案是使用我的密钥添加连接表,并在插入其他表时使用触发器.该解决方案的问题在于"同步"过程变得非常手动,并且容易出错.

Air*_*Air 24

好的; 因此,您有许多源自不同来源的表,每个表都使用自己的逻辑结构实现相同的实体(Product).任何给定的记录可能存在于多个表中,您的任务是协调这些不同的数据源,使用一些手动过程来确定哪些记录在表中相似/相同.

这听起来类似于我们在Cal/EPA进行的一个过程,用于协调来自许多不同来源的数据,以创建全州范围的空气污染清单.这些来源包括几个不同的建模团队,每个团队使用一组不同的输入和输出参数; 监测站的直接测量; 地方和市政机构的年度报告; 在某些情况下,个人和企业直接向我们报告的数据.这些数据以许多不同的格式呈现给我们,其中大部分都是重叠的.

我不会向你介绍我们和解过程的细节,但我可以告诉你一些我从中学到的东西,并建议一种可能适合你的方法.

首先,将以多种不同格式存在的重叠数据放在一起很糟糕.如果每个人都使用相同的桌面结构并且彼此保持不变,那么我们的工作就会容易得多.那就是说,这是我们必须应对的现实; 这就是为什么我们有工作.不同的组织和个人以不同的方式运营,期间和大部分时间您将无权改变其运营方式.

你需要一个计划,否则将犯错误 - 不是偶然的错误,而是不断的错误.您可以采取的一种广泛的方法是:我将接受来自所有这些格式的数据,并将其放入一个临时数据库中,在那里我将根据需要操作和聚合并剪切和拍打和破坏数据以使其适合我的闪亮的,表现良好的数据库,其中只有一个物理模型,一切都很棒.然后我可以忘记我对数据所做的所有无法形容的事情,以便首先将它放在那里,生活将是美好的...直到我必须重新做到这一点.这被称为ETL,它代表Extract,Transform,Load -or可能包含,酷刑,Lobotomize取决于你有多少乐趣.您可以如果你愿意,可以在维基百科上阅读它(或者在这里,或者在DBA.SE上,或者在一个知道一两件关于折磨的公司的指南中).

关于ETL的好处是你最终会感觉良好.关于ETL的不太好的事情是,通过转换数据以满足您的特定需求,您经常会丢失源中存在的某种程度的细节或实用程序.另一方面,如果您创建一个高度通用的数据模型,以便尽可能多地捕获源数据并避免破坏性转换,那么最终会得到一个高度通用的数据模型,这意味着即使您的文档和维护工作也更多模特是完美的 - 它永远不会是.

现在,听起来您不愿意或无法转换源数据以适应合理关注的模型.而且你不应该把它全部塞进一个满是重复列和NULL的表中,以免你在R'lyeh的家中被克苏鲁的视觉点缀成疯狂的快速下降:

+-----+---------+------------+---------+-----------------+-------------+-----+
| id  | sup1_id | sup1_color | sup2_id | sup2_color      | sup2_weight | ... |
+-----+---------+------------+---------+-----------------+-------------+-----+
| 1   | 7124    | brn        | 93      | Burnt Sienna    | 0.65        | ... |
| 2   | 415     | yel        | 8552    | Bananas Foster  | 12.50       | ... |
| 3   | NULL    | NULL       | 51      | Mostly Red      | 2.00        | ... |
| 4   | 159     | wht        | NULL    | NULL            | NULL        | ... |
| 5   | NULL    | NULL       | NULL    | NULL            | NULL        | NULL NULLNULLNULLUNNLUNUL gratuitous Unicode diacritics, you get the idea
Run Code Online (Sandbox Code Playgroud)

这根本不属于关系数据库; 它是一个平面文件/电子表格范例,应该限制在像Excel这样的非数据库环境中.(或访问.Zing!)

你还剩下什么,如果你需要以各种形式保留不同的表,但仍然希望它们彼此联系起来并保留某种"主"记录,那就是创建额外的表来表征这些关系并存储你的"统治他们的一把钥匙." 现在我们正朝着谈论子类型和角色的方向前进.您有一个以各种方式表示的实体(产品); 如果产品的每个实例都只存在于一个表示中,那么您将处理实体子类型.在存在重叠的情况下,就像在这里一样,最好考虑实例可以对每个供应商采取的角色.这是数据建模的一个例子,:

您的"主"ID和任何相关信息将属于左侧的关系,我将其称为Product.无论供应商是哪种,您都希望存储对于给定产品始终相同的属性; 或者,您知道的属性的"官方"版本因供应商而异,如果需要的话.例如,如果您是制造商,则产品的MSRP不依赖于携带产品的零售商; 它应该在主表中.与不同零售商相关的各种定价相比,它也可以作为"官方"价格.

您的各种供应商表位于右侧.这些是产品所扮演的角色; 这里将存储您希望能够在供应商之间变化的任何信息(在您的示例中,产品颜色)或与某些供应商相关联的信息,而不是其他供应商(在您的示例中,重量).由于产品和角色之间存在多对多关系,因此您需要在它们之间添加一个联结表,其中分配了角色; 如果您没有保留历史记录,则不需要在联结表中包含日期,如上图所示,但这是一个示例,其中有关角色分配的信息适合存储在联结表中.

由于您指定需要在插入后将供应商表中的记录链接在一起,通过您的神秘手动过程,您在此方法下的工作流程可能类似于:

  1. 记录被插入到各种供应商表中.
  2. 您注意到已插入新记录(此处触发器可能有用).
  3. 使用神奇的神秘手动过程,您可以确定每条新记录在产品中是否存在.
  4. 每当产品中不存在供应商的新记录时,您都会在Product中插入一个新行,以唯一标识(并可能表征)该项目.
  5. 您为来自供应商的每条新记录在联结表中插入一个新行,将该项目的唯一记录链接到与该供应商的角色中表征该项目的其他信息.

请注意,由于您的外键将位于联结表中,因此可能没有角色/供应商的产品以及没有产品的供应商.至于跟上工作流程并避免错误,除非您准备向我们提供有关您在供应商表之间链接产品的流程的更多信息,我建议的最好的方法是AFTER INSERT在每个供应商表上使用触发器来放置将表的名称和行的PK放入一个表中,该表跟踪新产品,直到他们完成手动链接过程,并在您完成手动链接过程时删除这些行.

您可以在联结表上使用另一个触发器来清除新的/未链接的产品表,但更新或删除行的触发器风险更大.实际上,如果您可以使用应用程序逻辑而不是触发器来填充新的/未链接的产品表,那么这也是可取的.你可以通过博客阅读Triggers Considered Harmful,Considered Harmful仔细分析触发器争论的两个方面,尽管它并不是针对MySQL的.

  • 作为同样这样做的人,我同意.在答案中没有足够强调手册,但你捕获了基本要点.我将你的"主人"记录描述为"黄金"记录; 最后的观点_You_有你的供应商告诉你的.你必须根据你所知道的最终决定做出"正确"的决定.偶尔会出现问题. (2认同)