数据库 table 规范化困难 (2NF)

Difficulty in database table normalization (2NF)

下面的 table 设计(请参阅下面的完整架构)有很多不足之处,也造成了很多困难,但我想不出如何最好地规范化它们。 table 的目的是:

  1. ICD9 — 提供 CICD9CDESC 组合的主查找。每个组合在 ICD9 table 中都是唯一的&hellip 没有重复。
  2. ICD9 table 中唯一键 (CICD9,CDESC) 的更改将级联到 DX table。 DX table 永远不会有 ICD9 table.
  3. 中未表示的 (CICD9,CDESC) 组合
  4. Table DX -- 这个table中的记录给出了这个人在特定时间的特定信息。此 table 中的记录无法根据 Key(CICD9,CDESC,GROUPID,TPOSTED) 进行复制,其中 GROUPID 对个人而言是唯一的,而 TPOSTED 是记录的创建时间.
  5. 如下所示,DX table 包含有关具有唯一键 (CICD9,CDESC,GROUPID,TPOSTED) 的记录的关联非键信息。

有时由于数据错误,ICD9DX 中会创建重复记录。例如:

ICD9
|CICD9|CDESC    |
|1234 |"  TEST1"|
|1234 |"TEST1"  |

DX
|CICD9|CDESC   |GROUPID|TPOSTED |
|1234 |"  TEST1|H      |12301212|
|1234 |"TEST1" |H      |12301212|

为了解决重复数据,更新ICD9table,修改CDESC,使" TEST1"变为"TEST1"。因为这是 Key(CICD9,CDESC) 的一部分,所以 DX 中外键上的级联设置将导致 DX 中的 CDESC 列也发生变化。此更改可能会导致 DX table 中的记录与 DX table 中的其他记录冲突,并违反 Key(CICD9,CDESC,GROUPID,TPOSTED ) 在 DX table 中。

我可以删除 ICD9 中的重复记录,我已经成功了。但是我需要保留 DX 中的其余数据(如 RESOLVEDTREATED),所以我不能只删除其中一行。我还需要保留唯一的密钥 (CICD9,CDESC,GROUPID,TPOSTED)。有人建议这需要标准化,但我不知道该怎么做。

      CREATE TABLE icd9
(
  recid serial NOT NULL,
  cicd9 character varying(8),
  cdesc character varying(80) NOT NULL,
  "timestamp" timestamp without time zone DEFAULT now(),
  modified timestamp without time zone DEFAULT now(),
  chronic boolean,
  common boolean,
  CONSTRAINT pk_icd9_recid PRIMARY KEY (recid),
  CONSTRAINT constraint_cdesc UNIQUE (cicd9, cdesc),
  CONSTRAINT desccheck CHECK (cdesc::text <> ''::text)
)
WITH (
  OIDS=FALSE
);


     CREATE TABLE dx
(
  recid serial NOT NULL,
  cpatient character varying(33) NOT NULL,
  cicd9 character varying(8),
  cdesc character varying(80) NOT NULL,
  tposted timestamp without time zone NOT NULL,
  "timestamp" timestamp without time zone DEFAULT now(),
  modified timestamp without time zone DEFAULT now(),
  resolved boolean DEFAULT false,
  treated boolean DEFAULT false,
  chronic boolean DEFAULT false,
  groupid character varying(33) NOT NULL,
  service integer DEFAULT 0,
  explanation text,
  pmh boolean DEFAULT false,
  CONSTRAINT pk_dx_recid PRIMARY KEY (recid),
  CONSTRAINT dx_cpatient_fkey FOREIGN KEY (cpatient)
      REFERENCES patients (cpatient) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE RESTRICT,
  CONSTRAINT dx_groupid_fkey FOREIGN KEY (groupid)
      REFERENCES charts (groupid) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE RESTRICT,
  CONSTRAINT fk_icd9 FOREIGN KEY (cicd9, cdesc)
      REFERENCES icd9 (cicd9, cdesc) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT noduplicate_dx UNIQUE (cicd9, cdesc, groupid, tposted),
  CONSTRAINT desccheck CHECK (cdesc::text <> ''::text),
  CONSTRAINT groupcheck CHECK (groupid::bpchar <> ''::bpchar),
  CONSTRAINT patientcheck CHECK (cpatient::bpchar <> ''::bpchar)
)
WITH (
  OIDS=FALSE
);

简化更新和删除

首先,由于您使用的是代理主键,因此您的外键应该指向这些主键,而不是您的代理键所代表的唯一键。使用代理键的好处之一恰恰是,当您拥有一个或多个列可能会更改的唯一键时,它会让生活变得更加轻松;您将不再需要级联更新,因为这些字段只保存在一个地方。您已经有 suitable 个独特的约束来管理数据质量。

dx 中删除 cicd9cdesc 列。添加一个名为 idc9_recid 的列。更改 dx 中的唯一约束以考虑此更改。理想情况下,您也应该在数据库的其他地方进行此更改。

那么您应该能够删除您添加的一些过度设计。我通常会大量使用触发器,因为您一直将其描述为出现问题的警告信号。进行这些更改,然后考虑什么是真正必要的。您需要做的就是这样:

update dx
set idc9_recid = 25
where idc9_recid = 12;

delete idc9
where recid = 12;

显然,您需要确定您对哪些行感兴趣才能确定这些 ID - 因此实际上您可能首先有一个查询来获取 ID,或者有一个子查询来选择正确的 ID。但无论如何,它比多个触发器简单得多,依靠约束无法设置更新等。无论是从开发的角度,还是从后续支持的角度来看。

绕过唯一约束错误

关于不好的 data/duplicate 问题:简而言之,问题是由于数据质量差,您有时会得到两条 icd9 记录,而这两条记录实际上应该是同一条记录。这些都可以在 dx 中有子记录,虽然您需要 dx 中的唯一约束保持不变,但您还需要保留 dx 中其他字段中的数据。答案是将dx拆分为两个table,将dx中不依赖unique key的字段全部移动到新的table中,然后包括从新的 table 回到 dx.

的外键

示例模型

请注意,这 不一定是正确的设计 ,这里有一个简单的模型可以帮助您形象化上述两个建议:

(我使用 draw.io 制作模型 - 如果您没有任何其他建模软件,强烈推荐,因为您可以使用它来完成您的更改,然后再将它们实际应用到数据库。如果您需要回来在这里提出更多问题,这将很有帮助。)


从这里去哪里

我怀疑有人向您提到规范化的原因是很明显这个数据库是在没有遵循规范化过程的情况下创建的。 不要只是实施我上面给你的东西。它可能会帮助你解决这个问题,但我怀疑即使在你的数据库的这个小样本中也存在其他问题,并且不可避免地会在其他地方出现更多问题。

首先 - 您在 dx 中的唯一密钥绝对正确吗?对于同一个 idc9、同一个组和同一个发布时间,你真的不能有两条记录吗?即使它用于 patients 中的不同记录?或者也许 table 中不应该有 patients 的外键? (注意,这些只是例子,让你思考的东西 - 不需要在这里回答。)

而且您肯定需要考虑已移至 dx_detail 的所有字段都依赖于哪个键。可能有些属于 dx,有些属于 dx_detail - 但我不能告诉你是哪一个,因为我不知道数据的含义。

因此:最重要的是您 了解数据建模和规范化 - there are lots of resources online(即 7 个​​链接,就在那里!)。或者,如果您可以向您的雇主解释在您选择像这样大的东西之前您确实需要一些培训 - 这并不丢人,数据建模是它自己的学科。我参加了为期一周的数据建模专业课程,解释了创建概念数据模型的过程,然后转向逻辑数据模型并应用规范化规则以达到 Boyce-Codd 范式。这是无价的。

简而言之,您需要考虑您的数据代表什么,并且您需要考虑什么实际上取决于什么。通过标准化过程逐步执行此操作可帮助您避免遗漏任何内容,尤其是当您不熟悉该过程时。

我还建议您尽可能修改 table 和列,使其具有真正有意义的名称。除了帮助需要支持该系统或从中读取数据的其他人之外,您可能会发现它可以帮助您在处理数据时思考数据的含义。再说一次,如果您需要返回此处寻求帮助,事情会变得更简单。即使您在数据库中更改它为时已晚,也可能值得制作一个图表,其中包含数据库级别的名称以及每个名称的描述性术语或短语;当您所建模的内容的含义显而易见时,数据建模会容易得多。