基本上,我想创建一个数据库结构,允许以无限的方式对无限量的库存项目进行分类,但是,其中许多项目共享某些“traits”。例如,Cars
和Trucks
:
red
或blue
。
2wd
或4wd
。
Cars
可以manual
或automatic
传输。Trucks
可以有cloth
或leather
个席位我希望避免的是手动输入存在的每种可能的组合。有5种颜色和5种车辆,已经有25个条目,没有功能集分类。
是否存在允许这些关系和共享“特征组”的数据模型,或者更重要的是,是否允许对我可以想象的任何数据集的每种可能组合进行单一引用?任何帮助将不胜感激。
让我尽可能具体。我的主要目标是跟踪材料使用情况 我们为预算和历史目的而做的工作。一些材料, 即 studs 和 track ,将共享相同的子分类, 跟踪还有第3个子分类。有些人会完全 不同的分类。假设如下。
metal_widths
metal_gagues
track_types
insulation_widths
insulation_types
......关系(可能的组合):
Studs
> metal_widths
> metal_gagues
( 25 )Track
> metal_widths
> metal_gagues
> track_types
( 100 )Insulation
> insulation_widths
> insulation_types
( 15 )为了了解我的最终目标,应用程序工作流程将是 像这样的东西:
我认为我的预算与费用应用程序的目标非常简单,
我只是想让之前的材料相关数据库的设计正确
向前进。我意识到最简单的解决方案是创建单个
material
表中每个可能组合的条目并限制它
数据库到n
个可能的特征。问题是,当我决定
添加x width
个帖子,我还想添加x width
曲目,意思是我
将可能的组合增加30 ,因此需要30
额外的条目(我真的宁愿避免)。
我的问题仍然相同:是否有允许这些的数据模型 关系,更重要的是,有一个允许单一参考 对于每种可能性...... 或,我应该抓住这个概念并继续使用 每种材料的单个条目,并限制特征的数量。
答案 0 :(得分:5)
你的意思是这样的吗?
这个简单的模型允许您将特征组合在一起然后将整个特征组“应用”到任意数量的项目(ITEM_TRAIT_GROUP表格是M:N关系的典型示例可以用关系范式表示)。如果您主要关心的是避免通过“重复使用”特征来重复,那么这个模型可能适合该法案。
然而,这将不强制执行:
(1)和(2)会要求某种类型的系统甚至是“继承”(在OOP意义上),这在关系范式中并不乐趣。如果你真的需要它,你最好在客户端或中间层强制执行这种逻辑。
(3)可以合理地建模,但并非没有使模型复杂化,这可能是也可能不值得付出努力。
答案 1 :(得分:1)
我不确定我理解你的意思“因此需要30个额外的条目”。除非实际携带信息,否则您不必明确输入所有组合。例如,如果您有一个包含所有价格的供应商价格表,那么您将有30个额外的行,每个行都有一个新价格。但这似乎不是你想要的。您似乎想要为构成工作的所有项目的预算和后期发票价格输入。
让我们尝试以直截了当的方式解决问题:
METAL_WIDTH
id | unit | amount | displaytext
1 | mm | 10 | 2/5 in
2 | mm | 15 | 3/5 in
3 | mm | 20 | 4/5 in
4 | mm | 25 | 1 in
5 | mm | 30 | 1 1/5 in
METAL_GAUGE...
TRACK_TYPE...
INSULATION_WIDTH...
INSULATION_TYPE...
我跳过了其他四个表的细节,它们的结构类似于METAL_WIDTH
JOB
id | name
1 | test job
BUDGET_ITEM
id | job_id | type | metal_width_id | metal_gauge_id | track_type_id | insulation_width_id | insulation_type_id | price_in_dollar
1 | 1 | STUD | 1 | 1 | null | null | null | 50
INVOICE_ITEM
id | job_id | type | metal_width_id | metal_gauge_id | track_type_id | insulation_width_id | insulation_type_id | price_in_dollar
1 | 1 | STUD | 1 | 1 | null | null | null | 49.95
这里我将INVOICE_ITEM和BUDGET_ITEM分开,因为我觉得你可能想要使用INVOICE_ITEM而不仅仅是预算控制。但是你可以把所有项目都放到一个大的JOB_ITEMS表中。相反的情况也是可能的:您可以创建一个STUD_PRICE表,一个TRACK_PRICE和一个INSULATION_PRICE。更多表意味着查询变得更长,但现在您可以存储STUD只能具有METAL_GAUGE和METAL_WIDTH属性的信息:
STUD_PRICE
id | job_id | purpose | metal_width_id | metal_gauge_id | price
1 | 1 | BUDGET | 1 | 1 | 50
2 | 1 | INVOICE | 1 | 1 | 49.95
现在您可能会注意到您有一个冗余:两次输入相同的螺柱,如果您想比较预算和发票,并且在工作中有多个螺柱,这将成为一个问题:< / p>
STUD_PRICE
id | job_id | purpose | metal_width_id | metal_gauge_id | price
1 | 1 | BUDGET | 1 | 1 | 50
2 | 1 | INVOICE | 1 | 1 | 49.95
3 | 1 | BUDGET | 1 | 2 | 75
4 | 1 | INVOICE | 1 | 2 | 89.95
INVOICE现在属于哪个BUDGET?你是一个有趣问题的错字。所以你可能会更好:
STUD_ITEM
id | job_id | metal_width_id | metal_gauge_id | budget_price | invoice_price
1 | 1 | 1 | 1 | 50 | 49.95
2 | 1 | 1 | 2 | 75 | null
其中null表示“尚未开票”,一旦您在那里,您可以从上面获取BUGET_ITEM和INVOICE_ITEM表并将它们组合到JOB_ITEM
JOB_ITEM
id | job_id | type | metal_width_id | metal_gauge_id | track_type_id | insulation_width_id | insulation_type_id | budget_price | invoice_price
1 | 1 | STUD | 1 | 1 | null | null | null | 50 | 49.95
您的应用程序将允许您创建新作业,设置其属性,然后将项目添加到其预算中。您可以说“新项目......”并可在STUD,TRACK和INSULATION之间进行选择。选择STUD后,您将获得一个包含允许的METAL_WIDTH的菜单,另一个包含允许的METAL_GAUGE。您可以选择它们,设置预算价格并存储该项目。根据需要重复。进入发票阶段后,选择存储的项目并设置发票价格。预算/发票比较是通过查看作业中的所有项目,添加预计总预算的所有预算价格,并添加实际总发票金额的所有发票,还有奖励积分,也仅显示那些项目的预算成本invoice_price不为空。
要为发票创建文本,您只需连接displaytext列的内容,从而节省每个“Stud - 2/5 in - 10ga”到“Stud - 1 1/5”的行的需要在 - 18ga“。如果你现在添加一个METAL_WIDTH,你所要做的就是在METAL_WIDTH表中添加一行,你很好。
答案 2 :(得分:0)
上汽车课。汽车可以是卡车,也可以是汽车。也许你应该研究继承和抽象 - 面向对象设计的两个基础。
答案 3 :(得分:0)
我不确定“每种可能性的单一参考点”是什么意思。
你可以简单地将数据输入到一个宽的varchar()列中,如
这不要求您提前输入任何内容,并且它提供了最大的灵活性,尽管这种灵活性是以数据完整性为代价的。 (或者通过不断观察错误条目来增加管理开销。)它也会使报告复杂化。例如,仅报告8个量规螺柱更复杂。
现成的会计系统 - 已经过编程处理预算,估算和发票 - 通常会要求您以这种方式存储库存。
假设您已经做出有意识的,明智的决定不使用您的会计系统,那么您根本不会以这种方式存储值,而是希望外键约束带来更大的数据完整性,自动生成集合可能是有意义的。
-- This table will be used as a foreign key reference for tracks.
-- Adjust the CHECK() constraints for your actual values. If you're using MySQL,
-- replace the CHECK() constraints with foreign key references to separate tables.
--
create table studs (
metal_width_mm integer not null check (metal_width_mm between 5 and 10),
metal_gauge integer not null check (metal_gauge between 8 and 16),
primary key (metal_width, metal_gauge)
);
要填充它,将已知值放入公用表表达式,并生成笛卡尔积。
insert into studs
with gauge as (
select 8 as metal_gauge
union all
select 10
union all
select 12
union all
select 14
union all
select 16
),
width as (
select 5 as metal_width_mm
union all
select 6
union all
select 7
union all
select 8
union all
select 9
union all
select 10
)
select *
from width, gauge
如果必须经常添加值,则编写SQL存储过程以仅插入新组合并不困难。
如果您没有寻求这么大的灵活性或这么多的数据完整性,请考虑澄清您的问题。
答案 4 :(得分:0)
当我在Onan工作并且他们必须跟踪发电机组的有效配置时,他们使用了两个表,并且必须使用&#39;并且不允许。&#39;
所以,举个例子:
cars and trucks,
Both can be red or blue only.
Either color car/truck can be 2wd or 4wd.
Cars can have manual or automatic transmission.
Trucks can have cloth or leather seats
必须使用&#39;表,会有像
这样的规则 <强> object | attribute | mustUse1 | orMustUse2
强>
car | color | red | blue
truck | color | red | blue
car | wd | 2wd | 4wd
truck | wd | 2wd | 4wd
car | transmission | manual | automatic
truck | seats | cloth | leather
在您的情况下,如果您有很多重复项,您可能会存储更高级别的关系,例如cars
和trucks
autos
,然后在&#中39;必须使用&#39;表,只是
auto | color | red | blue
auto | wd | 2wd | 4wd
car | transmission | manual | automatic
truck | seats | cloth | leather
另外,我不确定为什么可能的组合会让你感到困惑。 给定
5 possible metal_widths
5 possible metal_gagues
4 possible track_types
5 possible insulation_widths
3 possible insulation_types
...the relationships (possible combinations):
Studs > metal_widths > metal_gagues (25)
Track > metal_widths > metal_gagues > track_types (100)
Insulation > insulation_widths > insulation_types (15)
为metal_widths
提供5行,metal_gauges
包含5行,studs
包含metal_widthID和metal_gaugeID,track
包含(studID?)和track_typeID,和insulation
,其中包含insulation_widthID和insulation_typeID。
如果您觉得自己的体验不足以建模并应用数据,那么您可以让其他人这样做。
答案 5 :(得分:0)
答案 6 :(得分:0)
我通过将项目(和引号)建模为具有类型的对象并使用键值对指定特征来接近它。以示例的方式显示表格,并忽略主键之类的内容:
首先有一个包含所有有效键值对的表:
VALID_KEY_VALUES
| key | value |
=============================
| metal_width | mwidth1 |
| metal_width | mwidth2 |
...
| insulation_type | itype3 |
这可满足您的要求,如果您需要添加新的metal_width
,则可以在此表中插入一个。{p> (目前示例中有22行)。
现在有一个每种类型的有效密钥表:
VALID_TYPE_KEYS
| type | key |
=================================
| stud | metal_width |
| stud | metal_gauge |
| track | metal_width |
| track | metal_gauge |
| track | track_type |
| insulation | insulation_width |
| insulation | insulation_type |
现在,一个项目(或引用)由两个表定义,首先是ID:
的项目ITEMS
| ID | type | .... whatever columns you need ...
================================================
| 1 | stud | ..................................
现在&#34;特征&#34;该项目:
ITEM_TRAITS
| itemID | type | key | value |
=========================================
| 1 | stud | metal_width | mwidth1 |
| 1 | stud | metal_gauge | mgauge2 |
(这有点非规范化,因为每行包含来自itemID
表的type
和ITEMS
,但我们暂时可以使用它。换句话说,第1项是具有metal_width=mwidth1, metal_gauge=mgauge2
的螺柱。
您可以使用ITEM_TRAITS
表中的多列外键将它们粘在一起。
(itemID, type) is a foreign key into the ITEMS table
(type, key) is a foreign key to the VALID_TYPE_KEYS table
(key, value) is a foreign key to the VALID_KEY_VALUES table
这似乎是您需要的良好开端。如果您需要添加新类型,新特征或特征的新值,则使用最小插入完成。您的报价可以使用QUOTES
和QUOTE_TRAITS
表格以类似方式完成。您可以通过连接匹配带引号的项目,计算项目和引用之间匹配的特征数量(并将其与给定类型的特征总数进行比较)。
您可能需要在客户端上做一些工作,迭代给定类型的所有键,以确保输入所有必要的数据,并且这确实假设您的每一个&#34;组合&#34;已验证。 (如果你做的情况下某些组合是有效的而有些组合不是,那么你将无法避免全部枚举它们)。这也假设没有&#34;下钻&#34;也就是说,指定一个特征的逻辑并不限制任何后期特征的值,但你甚至可以将这个想法扩展到这种情况(假设你的要求也不是)疯了)。