在SQL数据库中存储自定义字段的首选方法是什么?

时间:2010-01-18 23:09:03

标签: sql database database-design

我的朋友正在构建一个供不同的独立医疗单位使用的产品。

数据库存储了在不同时间进行的大量测量,如温度,血压等......

我们假设这些内容保存在名为exams的表格中,其中包含temperaturepressure等列...(以及id,{{1}和patient_id)。大多数测量都存储为浮点数,但有些是其他类型(字符串,整数......)

虽然这些测量中的许多都是由他们的产品处理的,但它需要允许不同的医疗单位记录和处理其他自定义测量。一个非常漂亮的用户界面允许管理员编辑这些海关字段,指定其名称,类型,可能的值范围等...

他不确定如何存储这些自定义字段。

他倾向于一个单独的表(比如表timestamp,其中包含custom_exam_dataexam_idcustom_field_idfloat_value等字段,...

我担心这会使搜索更难以实现且效率更低。

我倾向于直接修改考试表(同时避免使用某些方案在列名称上发生冲突,例如在所有自定义字段前加下划线或将其命名为custom_1,...)

他担心动态修改数据库并为每个医疗单位设置不同的模式。

希望一些有更多经验的人可以在这个问题上权衡。

备注:

  • 他正在使用Ruby on Rails,但我认为这个问题几乎与框架无关,只是因为他只是在SQL数据库中寻找解决方案。

  • 由于自定义字段需要可用于多个表格,因此我对问题进行了简化,但我相信这并不会影响您采取的方向。

  • (已添加)非常通用的报告模块需要搜索,排序,生成此数据的统计信息等,因此需要将此数据存储在相应类型的列中

  • (已添加)将针对标准字段以及自定义字段筛选用户输入。例如,将在给定范围内检查数字(不能具有-12或+444的温度)等等。因此,转换为适当的SQL类型不是问题。

10 个答案:

答案 0 :(得分:10)

多年来,我不得不多次处理这种情况,我同意你最初的想法是直接修改数据库表,并使用动态SQL生成语句。

创建字符串UserAttribute或Key / Value列首先听起来很吸引人,但它会导致inner-platform effect,您最终不得不重新实现外键,数据类型,约束,事务,验证,排序,分组,计算,等。在你的RDBMS里面。你也可以只使用平面文件而不是SQL。

SQL Server提供INFORMATION_SCHEMA表,允许您在运行时创建,查询和修改表模式。这有完整的类型检查,约束,事务,计算,以及你已经内置的所有东西,不要重新发明它。

答案 1 :(得分:7)

奇怪的是,当有一个有充分记录的模式时,很多人为此提出了临时解决方案:

Entity-Attribute-Value (EAV) Model

两种选择是XML和嵌套集。 XML更易于管理,但通常很慢。嵌套集通常需要某种类型的专有数据库扩展,而不会像SQL Server 2005+中的CLR类型那样混乱。它们违反了第一范式,但仍然是性能最快的解决方案。

答案 2 :(得分:5)

Microsoft Dynamics CRM通过在每次更改时更改数据库设计来实现此目的。讨厌,我想。

我想说更好的选择是考虑一个属性表。尽管这些通常不受欢迎,但它为您提供了所需的灵活性,并且您始终可以使用动态SQL创建视图以再次将数据转出。只需确保在创建这些视图时始终使用LEFT JOIN和FK,以便查询优化器可以更好地完成工作。

答案 3 :(得分:1)

我在商业会计软件包中看到过你朋友的想法。该表分为两个,第一个包含仅由系统定义的字段,第二个包含USER_STRING1,USER_STRING2,USER_FLOAT1等字段。表通过标识值链接(当记录插入主表时,具有相同标识的记录被插入第二个)。需要用户字段的每个表都是这样分开的。

答案 4 :(得分:1)

好吧,每当我需要在数据库字段中存储一些未知类型时,我通常将其存储为String,根据需要对其进行序列化,并存储数据类型。

这样,您可以使用任何类型的数据库获得任何类型的数据。

答案 5 :(得分:1)

我倾向于将测量结果作为字符串(varchar)存储在数据库中,另一列标识测量类型。我的理由是,它可能来自UI作为字符串并且转换为任何其他数据类型可能会在用户输入get存储之前引入损坏。

缺点是,当您按照某个度量指标过滤结果集时,您仍然需要执行转换,但至少存储和持久性机制不会引入损坏。

答案 6 :(得分:1)

我不能告诉你最好的方法,但我可以告诉你Drupal如何实现一种无模式结构,同时仍然使用现有的标准RDBMS。

一般的想法是,有一个包含字段列表的模式表。每行实际上只有两列,'table':String列和'column':String列。对于这些列中的每一列,它实际上定义了一个只有id的整个表以及该列的实际数据。

诀窍在于,当您使用数据时,它永远不会超过捆绑表中的一个联接,列出所有可能的列,因此您最终不会失去尽可能多的速度。与您提出的custom_前缀不同,这还可以让您比仅仅几家医疗公司扩展得更远。

MySQL在返回具有少量列的短行的行数据方面非常快。通过这种方式,这个方案可以很快地结束,同时为您提供很大的灵活性。

至于搜索,我的建议是索引页面内容而不是数据库内容。使用Solr解析呈现的页面并保持指向实际页面的链接,而不是尝试使用聪明的SQL搜索数据库。

答案 7 :(得分:1)

定义两个新表:custom_exam_schemacustom_exam_data

custom_exam_data有一个exam_id列,以及每个自定义属性的附加列。

custom_exam_schema将有来描述如何解释custom_exam_data表的每个。它会包含nametypeminValuemaxValue等列。

因此,例如,要创建自定义字段以跟踪某个人的手指数量,您可以将('fingerCount', 'number', 0, 10)添加到custom_exam_schema,然后将名为fingerCount的列添加到exam表。

有人可能会说在运行时更改数据库架构很糟糕,但我认为配置这些自定义字段是设置的一部分,并且不会经常发生。尽管如此,这种方法可以让您随时处理更改,并且不会冒险使用核心表模式。

答案 8 :(得分:0)

我会将这些自定义字段存储在一个表中,其中每个记录(dataType,dataValue,dataUnit)将在一行中使用。因此,从一个样本到数据会有一个关系。您还可以创建一个表来记录您将使用的所有cutom类型。例如:

create table DataType
(
id int primary key,
name varchar(100) not null unique
description text,
uri varchar(255) //<-- can be used for an ONTOLOGY
)


create table DataRecord
(
id int primary key,
sample_id int not null,//<-- reference to the sample
dataType_id int not null, //<-- references DataType
value varchar(100),//<-- the value as string
unit varchar(50)//<-- g, mg/ml, etc... but it could also be a link to a table describing the units just like DataType
)

答案 9 :(得分:0)

假设您朋友的数据库必须存储来自多个来源的数据值,例如demogrphic值,诊断,干预,生理价值,生理检查值,住院价值等。

他可能也可以定义选择,假设他的数据库缺少比赛,而且单位工作人员需要患者的比赛(不同的种族更不可能得到某些疾病),他们可能想要使用下拉菜单有几个选择。

我建议使用另一个有这些选择的表,或者你只使用一个“Custom_field_choices”表,它在某些时候完全相同,但名称不同。

考虑到数据库:
- 需要灵活 - 可以添加和定制来自多个表的数据 - 您可能希望保持数据库主结构的完整性,以便进行分发和统一 - 该数据必须有限制,警报和警告
- 数据必须有单位(10公斤或10磅)? - 该数据可以有多种选择 - 该数据可以具有不同的权限(从简单用户到管理员)
- 可能需要这些数据来生成报告而无需修改代码(自动化)
- 可能需要这些数据来在系统内进行交叉参考分析而无需修改代码

自定义表将是我的解决方案,修改每个表最终会有太大的风险。