下表设计(请参阅下面的完整架构)留下了很多不足之处并造成了很多困难,但我无法弄清楚如何最好地规范化它们。表格的目的是:
ICD9
- 提供CICD9
和CDESC
组合的主查询。每个组合在ICD9
表中都是唯一的,并且没有重复。CICD9,CDESC
表中唯一键(ICD9
)的更改将级联到DX
表。 DX
表永远不会有CICD9,CDESC
表中未表示的(ICD9
)组合。DX
- 此表中的记录提供有关特定时间的人的特定信息。此表中的记录不能基于密钥(CICD9,CDESC,GROUPID,TPOSTED
)重复,其中GROUPID
对于此人是唯一的,TPOSTED
是创建记录的时间。DX
表包含关于具有唯一键(CICD9,CDESC,GROUPID,TPOSTED
)的记录的关联非关键信息。由于数据不正确,有时会在ICD9
和DX
中创建重复记录。例如:
ICD9
|CICD9|CDESC |
|1234 |" TEST1"|
|1234 |"TEST1" |
DX
|CICD9|CDESC |GROUPID|TPOSTED |
|1234 |" TEST1|H |12301212|
|1234 |"TEST1" |H |12301212|
为了解决重复数据,ICD9
表已更新,修改CDESC
以使" TEST1"
变为"TEST1"
。由于这是密钥(CICD9,CDESC
)的一部分,因此DX
中外键上的级联设置将导致CDESC
中的DX
列也发生变化。此更改可能导致DX
表中的记录与DX
表中的其他记录冲突,并违反CICD9,CDESC,GROUPID,TPOSTED
中密钥(DX
)上允许的无重复内容表。
我可以删除ICD9
中的重复记录,我已经完成了这项工作。但我需要保留DX
中的其余数据(例如RESOLVED
和TREATED
),因此我不能只删除其中一行。我还需要保留唯一的密钥(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
);
答案 0 :(得分:3)
首先,由于您使用了代理主键,因此您的外键应指向那些,而不是您的代理键所代表的唯一键。使用代理键的好处之一就是当你有一个或多个列可能会改变的唯一键时,它会让生活变得更加容易。您不再需要级联更新,因为这些字段只保存在一个地方。您已经拥有合适的唯一约束来管理数据质量。
从cicd9
删除cdesc
和dx
列。添加一个名为idc9_recid
的列。更改dx
中的唯一约束以考虑此更改。理想情况下,您也应该在数据库的其他位置进行此更改。
您应该能够删除一些已添加的过度工程,然后。我通常会大量使用触发器,因为您已经将其描述为一个警告信号,表明出现了问题。进行这些更改,然后考虑一下真正需要的内容。您需要做的就是这样:
update dx
set idc9_recid = 25
where idc9_recid = 12;
delete idc9
where recid = 12;
显然,您需要确定您感兴趣的行以确定这些ID - 因此您实际上可能首先要求查询ID,要么查询子查询选择正确的ID。但无论如何,它比多个触发器更简单,更简单,依赖于无法设置更新的约束等等。从开发的角度来看,从后来的支持角度来看都是如此。
关于不良数据/重复问题:简而言之,问题是由于数据质量不佳,有时您最终会得到两条icd9
条记录,这些记录实际上应该是同一条记录。这些都可以在dx
中包含子记录,虽然您需要dx
中的唯一约束保持不变,但您还需要保留dx
中其他字段中的数据。答案是将dx
拆分为两个表,并将所有不依赖于dx
中的唯一键的字段移动到新表中,然后将新表中的外键包含回来到dx
。
请注意,不一定是正确的设计,这是一个简单的模型,可帮助您查看上述两个建议:
(我使用draw.io制作模型 - 如果您还没有获得任何其他建模软件,强烈建议使用它,因为您可以在将更改应用到数据库之前使用它来完成更改。如果您需要回来并在此处提出更多问题,它会有所帮助。)
我怀疑有人提到你的规范化的原因是,很明显这个数据库是在没有遵循规范化过程的情况下创建的。 不要只实现我上面提到的内容。这可能会帮助您解决这个问题,但我怀疑即使在数据库的这个小样本中也存在其他问题,并且不可避免地会在其他地方出现进一步的问题。
对于首发来说 - dx
中的唯一键是肯定的吗?对于相同的idc9,同一组和同一时间发布,你真的没有两条记录吗?即使它是patients
中不同的记录?或者也许不应该是该表中patients
的外键? (注意,这些只是示例,让您思考的事情 - 无需在此处回答。)
您肯定需要考虑移动到dx_detail
的所有字段所依赖的哪个键。可能有些情况属于dx
,有些属于dx_detail
- 但我无法告诉您哪些因为我不知道数据的含义。
所以:最重要的是你了解数据建模和规范化 - there are lots of {{3} } resources(那是7个链接,就在那里!)。或者,如果你能够向你的雇主解释你真的需要一些培训,然后才能拿到这么大的东西 - 其中没有任何耻辱,数据建模就是它自己的学科。我做了一个为期一周的数据建模专业课程,解释了创建概念数据模型的过程,然后转向逻辑数据模型并应用规范化规则来达到Boyce-Codd正规形式。这是非常宝贵的。
简而言之,您需要考虑数据代表什么,并且您需要考虑实际依赖于什么的内容。通过标准化步骤逐步完成此操作可以帮助您避免遗漏任何内容,尤其是当您对该过程不熟悉时。
我还建议您尽可能修改表和列以获得真正有意义的名称。除了帮助其他人并且需要支持该系统或从中读取一些数据之外,您可能会发现它可以帮助您在处理数据时考虑数据的含义。而且,如果您需要回来并在这里寻求帮助,它会让事情变得更简单。即使你在数据库中更改它已经太晚了,也许值得制作一个既有数据库级名称又有每个描述性术语或短语的图表;当你的建模意义明显时,数据建模就容易多了。