设计具有类型的组和具有类型的项目,其中项目类型与组类型相关
Designing group with types and items with types where item type relate to group type
我们的翻译公司数据库中有 performers
个,他们远程工作。此时 performers
是翻译和 DTP 专业人员,他们可以有很多服务组,每个服务组可以有很多服务项目。当他们向我们公司提出申请时,他们需要填写表格并选择他们拥有的服务。每个服务组都有一个类型,例如翻译或 DTP。翻译服务组需要源语言和目标语言,而 DTP 服务组则不需要。问题是在 select 列表中显示服务组的正确服务项目。
此时我有如下设计:
我有 performer_service_group_type
和 performer_service_item_type
,它们与 performer_service_group_type
相关,用于显示 UI 中所选服务组类型的正确服务项目类型。但是我不知道通过约束来验证数据库完整性的方法,因为可以毫无问题地保存服务项类型与服务组类型的错误关系。对于某些服务组(如 DTP)
,第二个问题可为空 source_language_id
和 target_language_id
我认为可以呈现的第二种方式是为团体服务提供 2 个单独的表格 - performer_language_service_groups' and
performer_misc_service_groupswith 2 tables for each for service items and service items types. Here pros that misc service group wouldn't has
source_language_idand
target_language_id` 但缺点是必须为每个新服务组创建 3 个表,如果我们有一些(送货服务和快递员在路上)。
任何意见或建议都会有所帮助,提前表示赞赏。
这里的问题是,这似乎是一个更大项目的一部分,而且措辞相当混乱。我试图理清这一点,但我的问题多于答案。但是,您主要关心的似乎是 constraints,因此这个示例应该有所帮助。主要问题是依赖单列键——本身不一定不好,但很难正确约束。
请记住,这是一个逻辑设计,不会直接解决您所陈述的问题,但如果您"convert"将其转交给 PostgreSQL,它会起作用.这样您就可以尝试约束并调整您的项目。
Note:
All attributes (columns) NOT NULL
PK = Primary Key
AK = Alternate Key (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key
服务类型的自定义类型ID
(鉴别器);将此类型用于 每个 SVC_TYP_ID
列。
TYPE svc_typ ENUM (T, D)
定义基础知识:服务、服务类型、语言、人员。
-- Service type identified by SVC_TYP_ID,
-- named SVC_TYP_NAME exists.
--
service_typ {SVC_TYP_ID::svc_typ, SVC_TYP_NAME}
PK {SVC_TYP_ID}
AK {SVC_TYP_ID}
(T, translation)
(D, dtp)
-- Service named SVC_NAME of type SVC_TYP_ID
-- is identified by SVC_ID.
--
service_ {SVC_ID, SVC_TYP_ID, SVC_NAME}
PK {SVC_ID}
AK {SVC_NAME}
SK {SVC_ID, SVC_TYP_ID}
FK {SVC_TYP_ID} REFERENCES service_typ
(WTR, T, written translation)
(EDT, T, editing)
(PRF, T, proof reading)
(IND, D, in-design markup)
(PHT, D, photoshop markup)
(ACD, D, autocad markup)
-- Language name LANG_NAME,
-- identified by LANG_ID exists.
--
lang {LANG_ID, LANG_NAME}
PK {LANG_ID}
AK {LANG_NAME}
(EN, English)
(FR, French)
(RU, Russian)
-- Perfomer (person) identified by PERF_ID
-- named FNAME, LNAME exists.
--
perfomer {PERF_ID, FNAME, LNAME}
PK {PERF_ID}
(1, Lev, Tolstoy)
(2, Jim, Blah)
(3, Joe, Doe)
(4, Jane, Doe)
人提供服务,每个人可以提供不止一种服务类型。在这个例子中,提供服务的人的通用术语是 "performer"。 Translator 和 dtp-professional 是 performer supertype 的 subtypes,descriminator 是 service type。同一表演者可以提供不止一种服务类型。
-- Perfomer PERF_ID registered for service type SVC_TYP_ID.
--
perf_svc_typ {PERF_ID, SVC_TYP_ID, cols_common_to_all}
PK {PERF_ID, SVC_TYP_ID}
FK1 {PERF_ID} REFERENCES perfomer
FK2 {SVC_TYP_ID} REFERENCES service_typ
(1, T, ... )
(2, T, ... )
(3, D, ... )
(4, T, ... )
(4, D, ... ) -- PERF_ID = 4 does translations and dtp
-- Performer PERF_ID is registered as a translator.
--
-- note: (SVC_TYP_ID = T)
--
translator {PERF_ID, SVC_TYP_ID, cols_specific_to_translators}
PK {PERF_ID}
CHECK (SVC_TYP_ID = T::svc_typ)
FK {PERF_ID, SVC_TYP_ID} REFERENCES perf_svc_typ
(1, T, ...)
(2, T, ...)
(4, T, ...)
-- Performer PERF_ID is registered as a DTP professional.
--
-- note: (SVC_TYP_ID = D)
--
dtp_prof {PERF_ID, SVC_TYP_ID, cols_specific_to_dtp_prof}
PK {PERF_ID}
CHECK (SVC_TYP_ID = D::svc_typ)
FK {PERF_ID, SVC_TYP_ID} REFERENCES
perf_svc_typ {PERF_ID, SVC_TYP_ID}
(3, D, ...)
(4, D, ...)
一名译员可能能够提供不止一种语言的服务。
-- Performer PERF_ID, who registered as a translator,
-- speaks language LANG_ID.
--
perf_lang {PERF_ID, LANG_ID}
PK {PERF_ID, LANG_ID}
FK1 {PERF_ID} REFERENCES translator
FK2 {LANG_ID} REFERENCES lang
(1, EN)
(1, FR)
(1, RU)
(2, EN)
(2, FR)
(4, FR)
(4, RU)
每个人(表演者)可以提供多组服务。组中的每个服务必须属于相同的服务类型。执行者必须注册为该服务类型的提供者。
-- Performer PERF_ID offers a group of services,
-- identified by (PERF_ID, PERF_GROUP_NO);
-- each service in the group is of type SVC_TYP_ID.
--
svc_group {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID}
PK {PERF_ID, PERF_GROUP_NO}
SK {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID}
FK {PERF_ID, SVC_TYP_ID} REFERENCES perf_svc_typ
(1, 1, T)
(1, 2, T)
(2, 1, T)
(3, 1, D)
(4, 1, T)
(4, 2, D)
每个执行者的服务组,列出该组服务类型的服务,由该执行者提供。
-- Performer PERF_ID offers translation (SVC_TYP_ID = T)
-- service SVC_ID from FROM_LANG to TO_LANG,
-- in that performer's service group
-- identified by (PERF_ID, PERF_GROUP_NO)
--
trans_svc {
PERF_ID
, PERF_GROUP_NO
, SVC_ID
, SVC_TYP_ID
, FROM_LANG
, TO_LANG
}
PK {PERF_ID, PERF_GROUP_NO, SVC_ID, FROM_LANG, TO_LANG}
CHECK (SVC_TYP_ID = T::svc_typ)
FK1 {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID} REFERENCES svc_group
FK2 {SVC_ID, SVC_TYP_ID} REFERENCES service_
FK3 {PERF_ID} REFERENCES translator
FK4 {PERF_ID, FROM_LANG} REFERENCES
perf_lang {PERF_ID, LANG_ID}
FK5 {PERF_ID, TO_LANG} REFERENCES
perf_lang {PERF_ID, LANG_ID}
(1, 1, WTR, T, EN, RU) -- for translation from <> to
(1, 1, WTR, T, FR, RU)
(1, 2, PRF, T, RU, RU) -- for edit and proof from = to
(1, 2, EDT, T, RU, RU)
(1, 2, PRF, T, EN, EN)
(2, 1, WTR, T, EN, FR)
(2, 1, WTR, T, FR, EN)
(2, 1, EDT, T, EN, EN)
(2, 1, PRF, T, EN, EN)
(2, 1, PRF, T, FR, FR)
(4, 1, WTR, T, FR, RU)
(4, 1, PRF, T, FR, FR)
-- Performer PERF_ID offers DTP (SVC_TYP_ID = D) service_ SVC_ID
-- in group identified by (PERF_ID, PERF_GROUP_NO).
--
dtp_svc {PERF_ID, PERF_GROUP_NO, SVC_ID, SVC_TYP_ID}
PK {PERF_ID, PERF_GROUP_NO, SVC_ID}
CHECK (SVC_TYP_ID = D::svc_typ)
FK1 {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID} REFERENCES svc_group
FK2 {SVC_ID, SVC_TYP_ID} REFERENCES service_
FK3 {PERF_ID} REFERENCES dtp_prof
(3, 1, PHT, D)
(3, 1, ACD, D)
(4, 2, IND, D)
(4, 2, ACD, D)
可以通过为 SOURCE 和 TARGET 语言(例如 source_languages
, target_languages
。您将在其中添加一个 default 值,例如 ID = 1,VALUE = "DEFAULT",它将对应于您的 NULL performer_service_groups
处的 字段不应再为空(即删除 performer_service_groups
上的空标志)。
这样您将保留固有的 SQL 外键约束,并且在 DML 上,如果您在 performer_service_groups
处修改 source_language_id
/target_language_id
(分别)(即如果你想要 NULL
你将被迫添加 ID = 1 以满足你的 DML,如果不是,你将添加一个适当的并且在任何语言加入 performer_service_groups
期间你将始终有一个返回值,因此,如果您这样做,则无需在后端检查是否为 null;对于 UI,只需隐藏语言 <select>
或 dropdown
(如果 ID = 1 或 VALUE = "DEFAULT")。
关于密钥验证我还在想,我可能会更新。
考虑过密钥验证。如果你为你的 2 个状态创建一个 table,它基本上会反映你的 UI。这将需要 performer_service_groups
有另一个 ID 字段,state_id
将指向您的状态 table。这将迫使您在查询中包含 state_id
字段,从而按州过滤结果集。基本上是数据的逻辑划分,实际上没有物理分离数据(通过仅添加另一个维度;因为每个 ID 都是一个新维度,所以可以 pivot
或 group by
导致 xyz table)。
如果你想完全严格,理论上你可以使用 BEFORE TRIGGERS 或 check constraint validations 验证可为空字段的 DML,但是这些将增加开销和inevitable脆弱性和复杂性。同样在理论上可以应用于密钥验证,但我不知道 pgSQL 触发器可以灵活地围绕它进行编码(来自 Oracle/PLSQL 和 MYSQL 这里)。
希望它有意义。
如果你有一百个服务组,那么我相信你也有很多字段只适用于某些组。我认为您必须使用 table 来存储 "allowed fields" 以及是否需要它们。
<table name="Service Group" comment="for example, DTL">
<column name="ID" pk="true" />
<column name="Name" />
</table>
<table name="Service Group Type" comment="for example, Photoshop Markup">
<column name="ID" pk="true" />
<column name="Service Group" fk="[Service Group].[ID]" />
<column name="Name" />
</table>
<table name="List Of Values" comment="for example, Language">
<column name="ID" pk="true" />
<column name="Name" />
</table>
<table name="Choice Of List Of Values" comment="for example, Japanese">
<column name="ID" pk="true" />
<column name="List Of Values" fk="[List Of Values].[ID]" />
<column name="Description" />
</table>
<table name="Field" comment="for example, From Language">
<column name="ID" pk="true" />
<column name="Name" />
<column name="List Of Values" fk="[List Of Values].[ID]" />
</table>
<table name="Service Group Field">
<column name="Service Group" pk="true" fk="[Service Group].[ID]" />
<column name="Field" pk="true" fk="[Field].[ID]" />
<column name="Nullable" comment="N means optional, Y means mandatory" />
</table>
<table name="Service Record" comment="only retain core fields here, e.g. Performer, Currency, etc">
<column name="ID" pk="true" />
<column name="Service Group Type" fk="[Service Group Type].[ID]" />
<column name="Performer" fk="[Performer].[ID]" />
<column name="Currency" fk="[Currency].[ID]" />
...
</table>
<table name="Service Record Detail" comment="to organize all conditional fields">
<column name="ID" pk="true" />
<column name="Service Record" fk="[Service Record].[ID]" />
<column name="Field" fk="[Field].[ID]" />
<column name="Choice" fk="[Choice Of List Of Values].[ID]" />
<column name="Free Text" />
</table>
问题 1 已通过仅在每个服务记录中存储服务类型来解决。您仍然应该对屏幕逻辑和预保存逻辑进行验证。要按服务组轻松分组服务记录,您可以创建视图,将数据从服务组类型连接回服务组。
问题 2 由可选/必填字段列表解决。您仍然必须添加所需的验证:
1 - 如果提供了一个值但无法从 [服务组字段] 中找到模式,则这是一个字段的过量输入
2 - 如果未提供值但来自 [服务组字段],则该值是强制性的,这缺少字段输入
现在我会坚持以下解决方案。
如果我要为特定服务组创建具有特殊字段的新组,我会创建具有 1-1 关系的新 table 并将布尔字段添加到 service_group
作为获取某些内容的必要标志.也许以后我会去寻找更有活力的东西。如果有人仍然知道如何改进这个模式 - 我想知道:)
我们的翻译公司数据库中有 performers
个,他们远程工作。此时 performers
是翻译和 DTP 专业人员,他们可以有很多服务组,每个服务组可以有很多服务项目。当他们向我们公司提出申请时,他们需要填写表格并选择他们拥有的服务。每个服务组都有一个类型,例如翻译或 DTP。翻译服务组需要源语言和目标语言,而 DTP 服务组则不需要。问题是在 select 列表中显示服务组的正确服务项目。
此时我有如下设计:
我有 performer_service_group_type
和 performer_service_item_type
,它们与 performer_service_group_type
相关,用于显示 UI 中所选服务组类型的正确服务项目类型。但是我不知道通过约束来验证数据库完整性的方法,因为可以毫无问题地保存服务项类型与服务组类型的错误关系。对于某些服务组(如 DTP)
source_language_id
和 target_language_id
我认为可以呈现的第二种方式是为团体服务提供 2 个单独的表格 - performer_language_service_groups' and
performer_misc_service_groupswith 2 tables for each for service items and service items types. Here pros that misc service group wouldn't has
source_language_idand
target_language_id` 但缺点是必须为每个新服务组创建 3 个表,如果我们有一些(送货服务和快递员在路上)。
任何意见或建议都会有所帮助,提前表示赞赏。
这里的问题是,这似乎是一个更大项目的一部分,而且措辞相当混乱。我试图理清这一点,但我的问题多于答案。但是,您主要关心的似乎是 constraints,因此这个示例应该有所帮助。主要问题是依赖单列键——本身不一定不好,但很难正确约束。
请记住,这是一个逻辑设计,不会直接解决您所陈述的问题,但如果您"convert"将其转交给 PostgreSQL,它会起作用.这样您就可以尝试约束并调整您的项目。
Note:
All attributes (columns) NOT NULL
PK = Primary Key
AK = Alternate Key (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key
服务类型的自定义类型ID
(鉴别器);将此类型用于 每个 SVC_TYP_ID
列。
TYPE svc_typ ENUM (T, D)
定义基础知识:服务、服务类型、语言、人员。
-- Service type identified by SVC_TYP_ID,
-- named SVC_TYP_NAME exists.
--
service_typ {SVC_TYP_ID::svc_typ, SVC_TYP_NAME}
PK {SVC_TYP_ID}
AK {SVC_TYP_ID}
(T, translation)
(D, dtp)
-- Service named SVC_NAME of type SVC_TYP_ID
-- is identified by SVC_ID.
--
service_ {SVC_ID, SVC_TYP_ID, SVC_NAME}
PK {SVC_ID}
AK {SVC_NAME}
SK {SVC_ID, SVC_TYP_ID}
FK {SVC_TYP_ID} REFERENCES service_typ
(WTR, T, written translation)
(EDT, T, editing)
(PRF, T, proof reading)
(IND, D, in-design markup)
(PHT, D, photoshop markup)
(ACD, D, autocad markup)
-- Language name LANG_NAME,
-- identified by LANG_ID exists.
--
lang {LANG_ID, LANG_NAME}
PK {LANG_ID}
AK {LANG_NAME}
(EN, English)
(FR, French)
(RU, Russian)
-- Perfomer (person) identified by PERF_ID
-- named FNAME, LNAME exists.
--
perfomer {PERF_ID, FNAME, LNAME}
PK {PERF_ID}
(1, Lev, Tolstoy)
(2, Jim, Blah)
(3, Joe, Doe)
(4, Jane, Doe)
人提供服务,每个人可以提供不止一种服务类型。在这个例子中,提供服务的人的通用术语是 "performer"。 Translator 和 dtp-professional 是 performer supertype 的 subtypes,descriminator 是 service type。同一表演者可以提供不止一种服务类型。
-- Perfomer PERF_ID registered for service type SVC_TYP_ID.
--
perf_svc_typ {PERF_ID, SVC_TYP_ID, cols_common_to_all}
PK {PERF_ID, SVC_TYP_ID}
FK1 {PERF_ID} REFERENCES perfomer
FK2 {SVC_TYP_ID} REFERENCES service_typ
(1, T, ... )
(2, T, ... )
(3, D, ... )
(4, T, ... )
(4, D, ... ) -- PERF_ID = 4 does translations and dtp
-- Performer PERF_ID is registered as a translator.
--
-- note: (SVC_TYP_ID = T)
--
translator {PERF_ID, SVC_TYP_ID, cols_specific_to_translators}
PK {PERF_ID}
CHECK (SVC_TYP_ID = T::svc_typ)
FK {PERF_ID, SVC_TYP_ID} REFERENCES perf_svc_typ
(1, T, ...)
(2, T, ...)
(4, T, ...)
-- Performer PERF_ID is registered as a DTP professional.
--
-- note: (SVC_TYP_ID = D)
--
dtp_prof {PERF_ID, SVC_TYP_ID, cols_specific_to_dtp_prof}
PK {PERF_ID}
CHECK (SVC_TYP_ID = D::svc_typ)
FK {PERF_ID, SVC_TYP_ID} REFERENCES
perf_svc_typ {PERF_ID, SVC_TYP_ID}
(3, D, ...)
(4, D, ...)
一名译员可能能够提供不止一种语言的服务。
-- Performer PERF_ID, who registered as a translator,
-- speaks language LANG_ID.
--
perf_lang {PERF_ID, LANG_ID}
PK {PERF_ID, LANG_ID}
FK1 {PERF_ID} REFERENCES translator
FK2 {LANG_ID} REFERENCES lang
(1, EN)
(1, FR)
(1, RU)
(2, EN)
(2, FR)
(4, FR)
(4, RU)
每个人(表演者)可以提供多组服务。组中的每个服务必须属于相同的服务类型。执行者必须注册为该服务类型的提供者。
-- Performer PERF_ID offers a group of services,
-- identified by (PERF_ID, PERF_GROUP_NO);
-- each service in the group is of type SVC_TYP_ID.
--
svc_group {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID}
PK {PERF_ID, PERF_GROUP_NO}
SK {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID}
FK {PERF_ID, SVC_TYP_ID} REFERENCES perf_svc_typ
(1, 1, T)
(1, 2, T)
(2, 1, T)
(3, 1, D)
(4, 1, T)
(4, 2, D)
每个执行者的服务组,列出该组服务类型的服务,由该执行者提供。
-- Performer PERF_ID offers translation (SVC_TYP_ID = T)
-- service SVC_ID from FROM_LANG to TO_LANG,
-- in that performer's service group
-- identified by (PERF_ID, PERF_GROUP_NO)
--
trans_svc {
PERF_ID
, PERF_GROUP_NO
, SVC_ID
, SVC_TYP_ID
, FROM_LANG
, TO_LANG
}
PK {PERF_ID, PERF_GROUP_NO, SVC_ID, FROM_LANG, TO_LANG}
CHECK (SVC_TYP_ID = T::svc_typ)
FK1 {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID} REFERENCES svc_group
FK2 {SVC_ID, SVC_TYP_ID} REFERENCES service_
FK3 {PERF_ID} REFERENCES translator
FK4 {PERF_ID, FROM_LANG} REFERENCES
perf_lang {PERF_ID, LANG_ID}
FK5 {PERF_ID, TO_LANG} REFERENCES
perf_lang {PERF_ID, LANG_ID}
(1, 1, WTR, T, EN, RU) -- for translation from <> to
(1, 1, WTR, T, FR, RU)
(1, 2, PRF, T, RU, RU) -- for edit and proof from = to
(1, 2, EDT, T, RU, RU)
(1, 2, PRF, T, EN, EN)
(2, 1, WTR, T, EN, FR)
(2, 1, WTR, T, FR, EN)
(2, 1, EDT, T, EN, EN)
(2, 1, PRF, T, EN, EN)
(2, 1, PRF, T, FR, FR)
(4, 1, WTR, T, FR, RU)
(4, 1, PRF, T, FR, FR)
-- Performer PERF_ID offers DTP (SVC_TYP_ID = D) service_ SVC_ID
-- in group identified by (PERF_ID, PERF_GROUP_NO).
--
dtp_svc {PERF_ID, PERF_GROUP_NO, SVC_ID, SVC_TYP_ID}
PK {PERF_ID, PERF_GROUP_NO, SVC_ID}
CHECK (SVC_TYP_ID = D::svc_typ)
FK1 {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID} REFERENCES svc_group
FK2 {SVC_ID, SVC_TYP_ID} REFERENCES service_
FK3 {PERF_ID} REFERENCES dtp_prof
(3, 1, PHT, D)
(3, 1, ACD, D)
(4, 2, IND, D)
(4, 2, ACD, D)
可以通过为 SOURCE 和 TARGET 语言(例如 source_languages
, target_languages
。您将在其中添加一个 default 值,例如 ID = 1,VALUE = "DEFAULT",它将对应于您的 NULL performer_service_groups
处的 字段不应再为空(即删除 performer_service_groups
上的空标志)。
这样您将保留固有的 SQL 外键约束,并且在 DML 上,如果您在 performer_service_groups
处修改 source_language_id
/target_language_id
(分别)(即如果你想要 NULL
你将被迫添加 ID = 1 以满足你的 DML,如果不是,你将添加一个适当的并且在任何语言加入 performer_service_groups
期间你将始终有一个返回值,因此,如果您这样做,则无需在后端检查是否为 null;对于 UI,只需隐藏语言 <select>
或 dropdown
(如果 ID = 1 或 VALUE = "DEFAULT")。
关于密钥验证我还在想,我可能会更新。
考虑过密钥验证。如果你为你的 2 个状态创建一个 table,它基本上会反映你的 UI。这将需要 performer_service_groups
有另一个 ID 字段,state_id
将指向您的状态 table。这将迫使您在查询中包含 state_id
字段,从而按州过滤结果集。基本上是数据的逻辑划分,实际上没有物理分离数据(通过仅添加另一个维度;因为每个 ID 都是一个新维度,所以可以 pivot
或 group by
导致 xyz table)。
如果你想完全严格,理论上你可以使用 BEFORE TRIGGERS 或 check constraint validations 验证可为空字段的 DML,但是这些将增加开销和inevitable脆弱性和复杂性。同样在理论上可以应用于密钥验证,但我不知道 pgSQL 触发器可以灵活地围绕它进行编码(来自 Oracle/PLSQL 和 MYSQL 这里)。
希望它有意义。
如果你有一百个服务组,那么我相信你也有很多字段只适用于某些组。我认为您必须使用 table 来存储 "allowed fields" 以及是否需要它们。
<table name="Service Group" comment="for example, DTL">
<column name="ID" pk="true" />
<column name="Name" />
</table>
<table name="Service Group Type" comment="for example, Photoshop Markup">
<column name="ID" pk="true" />
<column name="Service Group" fk="[Service Group].[ID]" />
<column name="Name" />
</table>
<table name="List Of Values" comment="for example, Language">
<column name="ID" pk="true" />
<column name="Name" />
</table>
<table name="Choice Of List Of Values" comment="for example, Japanese">
<column name="ID" pk="true" />
<column name="List Of Values" fk="[List Of Values].[ID]" />
<column name="Description" />
</table>
<table name="Field" comment="for example, From Language">
<column name="ID" pk="true" />
<column name="Name" />
<column name="List Of Values" fk="[List Of Values].[ID]" />
</table>
<table name="Service Group Field">
<column name="Service Group" pk="true" fk="[Service Group].[ID]" />
<column name="Field" pk="true" fk="[Field].[ID]" />
<column name="Nullable" comment="N means optional, Y means mandatory" />
</table>
<table name="Service Record" comment="only retain core fields here, e.g. Performer, Currency, etc">
<column name="ID" pk="true" />
<column name="Service Group Type" fk="[Service Group Type].[ID]" />
<column name="Performer" fk="[Performer].[ID]" />
<column name="Currency" fk="[Currency].[ID]" />
...
</table>
<table name="Service Record Detail" comment="to organize all conditional fields">
<column name="ID" pk="true" />
<column name="Service Record" fk="[Service Record].[ID]" />
<column name="Field" fk="[Field].[ID]" />
<column name="Choice" fk="[Choice Of List Of Values].[ID]" />
<column name="Free Text" />
</table>
问题 1 已通过仅在每个服务记录中存储服务类型来解决。您仍然应该对屏幕逻辑和预保存逻辑进行验证。要按服务组轻松分组服务记录,您可以创建视图,将数据从服务组类型连接回服务组。
问题 2 由可选/必填字段列表解决。您仍然必须添加所需的验证:
1 - 如果提供了一个值但无法从 [服务组字段] 中找到模式,则这是一个字段的过量输入
2 - 如果未提供值但来自 [服务组字段],则该值是强制性的,这缺少字段输入
现在我会坚持以下解决方案。
如果我要为特定服务组创建具有特殊字段的新组,我会创建具有 1-1 关系的新 table 并将布尔字段添加到 service_group
作为获取某些内容的必要标志.也许以后我会去寻找更有活力的东西。如果有人仍然知道如何改进这个模式 - 我想知道:)