如何存储可以同时构建或不构建的数据?

如何存储可以同时构建或不构建的数据?

问题描述:

我有以下表和数据库:如何存储可以同时构建或不构建的数据?

PATIENT (PATIENT_ID*, MEDICAL_EXAMINATIONS) 

其中场MEDICAL_EXAMINATIONS包含由患者进行的检查的*文本描述。

最近,决定可以以结构化方式(分为考试名称,日期,结果等)以*文本(一如既往)或以结构化方式报告体检。

所以我想更改架构如下(字段标有星号组成的键):

PATIENT (PATIENT_ID*, MEDICAL_EXAMINATIONS) 
MEDICAL_EXAMINATION (PATIENT_ID*, NUMBER*, NAME, DATE, RESULT) 

,但我发现这个解决方案有点不安,因为我有同样的信息(体检)存储在TWO表中。在这种情况下,查询“选择患者进行的所有体检”的结果并不那么“优雅”。

我真的不知道如何表达我的问题,但这种情况对我来说似乎很奇怪。 我不知道这个问题是从规范(我无法改变)发生的,还是有更好的方法来模拟数据的“两个版本”。

就个人而言,我会单独进行体检的概念,完全从患者分成两个单独的表,就像这样:

PATIENT(PATIENT_ID) 
MEDICAL_EXAMINATION(PATIENT_ID,NAME,DATE,RESULT) 
MEDICAL_EXAMINATION_NOTES(PATIENT_ID,NOTES) 

“注释”是在表名粗略估计,有可能是一个基于用例的更合适的名称。

这可以让您增加一些灵活性,因为如果您选择了将来的某个时间点,您可能会有多个“*形式”考试。

因为您拥有不同的数据结构,所以选择这两者总是会很麻烦。你很可能被限制到最低公分母,和他们拉出来作为字符串,如果你想要让他们在一起,就像这样:

SELECT 'Name ' + NAME + ', Date ' + DATE + ', Result: ' + RESULT AS EXAM 
FROM MEDICAL_EXAMINATION WHERE PATIENT_ID = @PATIENT_ID 

UNION ALL 

SELECT NOTES AS EXAM FROM MEDICAL_EXAMINATION_NOTES WHERE PATIENT_ID = @PATIENT_ID 

更妙的是,如果这个数据库正在备份某种业务对象,为“*形式”和“结构化”考试提供单独的课程,然后提供一个通用的界面,用于表示体检的字符串。这样,您的业务层可以选择单独对待或一起使用它们。

您可以将NAME,DATE,RESULT列添加到PATIENT表。如果条件“具有*格式或结构化数据,但不能同时拥有”,则可以添加防止违反条件的触发器。

我会做:

  • 病人:ID,姓名,出生,考试日期等
  • 体检:ID,病人ID(FK),姓名,日期,结果

Patient.Examination*文本字段视为基本未处理或尚未转录的检查。这个想法是,当你从*文本字段中转录数据时,你从那里删除它并将其添加到另一个表中。

然而,这会带来各种错误检测和控制问题。医疗转录是一个微妙的领域(可以理解)。

可以说你可以进一步规范化,并描述每一个可能的考试,给它一个ID和其他数据,然后把考试ID放入医疗检查实体,而不是简单的名称列。

但这一切都取决于您的要求。

这不是一个好的情况。一种可能更清洁一点的方法是将医疗检查从病床中排除(它不属于那里),并且医疗检查表具有patient_id,姓名,日期,结果和free_text。如果输入给定行的free_text值,则其他行将被忽略。这意味着,例如,您不能将日期设为数据库中的必需字段,但我认为它仍比现有版本更好。

它还会给你从糟糕过渡到更好的数据路径:1

阶段:多数患者有一个描述多种考试*文本单个关联medical_examination行。

第2阶段:大多数患者有多个相关的医疗检查行,其*文本描述每个单独的检查。

阶段3:大多数患者有多个相关的医疗检查行,每个单独的检查都包含结构化数据。

您可以将列注释添加到MEDICAL_EXAMINATION表中。

它看起来像

MEDICAL_EXAMINATION (PATIENT_ID, NAME, DATE, RESULT,comment) 

所以,你可以存储在注释栏的非结构化数据。

Joe Celko已经将关系数据库的主要规则之一表述为“One Fact,One Place,One Way”(有时会添加“One Time”)。拥有数据 - 非常重要的数据,从它的外观来看 - 在数据库中呈现两次,存储在两种截然不同的时尚中,这不是一个好主意。你可以做这样的事情:

  • 如果有关键的事实,必须存在一检查,为他们创造的列(如你的姓名,日期,结果做)
  • 鉴于此,还有什么可能被包含在描述中?我试图让这个单独呈现并存储在它自己的专栏(说,评论)
  • 有了这个,你可以建立一个“标准化”的*文本描述,基于相关数据。

还有什么,你必须通过两个不同的,可能不同意你的信息来源。

我们这里有一个半结构化数据的例子,处理这个问题的一种方法是使用ExamDetails的XML数据类型字段。您可能有:

<root> 
<ExamName></ExamName> 
<ExamResult></ExamResult> 
<FreeText></FreeText> 
</root> 

并非所有元素都必须出现在每个记录中。您将使用您的数据库XML功能来查询该字段。所有市长DB(MS SQl服务器,Oracle,DB2)都可以存储和查询XML。

很少有更多音符
我将不得不至少三个表:患者,医生,考试

TABLE Patient (ID (PK), Name, other patient details...) 
TABLE Doctor (ID (PK), Name, other doctor details...) 
TABLE Exam (ID (PK), PatientID (FK), DoctorID (FK), Date, ExamDetails XML, more here...) 

如果两个医生和病人刚好是人(而不是兽医诊所或房屋检查)你可以在Person表中添加一个Person和Sub-type Patient和Doctor表格 - 这样一来,在诊所就诊的医生也很容易成为患者。例如:

TABLE Person (ID (PK), FirstName, LastName, Phone, Address, other details common to people...) 
TABLE Patient (PersonID (PK, FK), ...specific patient details only) 
TABLE Doctor (PersonID (PK, FK), ...specific doctor details only) 
TABLE Exam (ID (PK), PatientID (FK), DoctorID (FK), Date, ExamDetails XML, more here...) 

因为Patient和Doctor是人的类型,PersonID应该与Person表中的ID号码相同。

clinic_model

这是一个困难的问题,你在这里有几个很好的答案,我在upvoting的过程中,我理解他们。

我的个人路径是将*文本检查列从患者行中分离出来。在大多数物理模型中,它将是ntext,text或varchar(MAX)或类似的,并且您不希望它在行中占用空间,这些类型通常将其数据存储在行外,但无论如何,把它拿出来很好。通常情况下,我会在病人身上得到1-1。它使您的患者行更小,更易于管理。

然后,我会制作一个单独的表格,将数据解读,提取并标准化为列和行,与病人进行多对一。

你说数据是同一个。如果是这样,*文本没有必要保留,你可以使用规范化的考试表格(甚至可以重建原始的“*文本”)

实际上,我通常会把*文本作为传统并限制对其的访问,并从标准化数据驱动所有视图和更新。如果*文本需要与规范化版本保持同步,那么有许多技术可以处理这种触发器,但是如果允许单个事务更改并且“*文本”需要有一些零件改变了。

“最近,决定医疗检查可以以*文本(一如既往)或以结构化方式报告(分为考试名称,日期,结果等)”。

这让我觉得这是一个非决定(可能是由非cognoscenti做出的)。从我所能做到的这个所谓的“决定”中,信息提供者仍然可以*地以任何他想要的方式提供信息,结构化或非结构化。 (注:如果信息提供者*在“结构化”和“非结构化”之间做出明确选择,我的回复不适用)。

“结构化”意味着存在“布局规则”(例如CSV )和信息提供者必须符合的“内容规则”(例如“考试名称必须是已知课程/考试的名称”)。

但定义上的“非结构化”仍然意味着“信息提供者提供的任何信息,该信息总是至少满足”非结构化“,因此根据定义,提供的任何信息总是可接受的“非结构化”的解释。

因此,这个所谓的“允许结构化的决定”是对所有没有任何用处。并且(考虑到我提到的警告),合乎逻辑的结论是,这个决定(这看起来完全是假的)“完全不做任何事情”是最好的选择。

毫无疑问,你会想“但我不能那样做”。如果你的管理层对逻辑上有根据的推理完全不敏感,你可能是对的。

PS

至于已作上述表示的“”有一个事实,一个地方,一个道”:(!暂时的)这样的情况下可能会说明为什么有时需要放松,要“一个事实,一个地方,两种可能的方式之一”,只是为了方便用户的过渡。