Mar*_*ark 6 sql database foreign-key-relationship relational-database
我在关系数据库中有以下表:
[Sensor]
LocationId [PK / FK -> Location]
SensorNo [PK]
[AnalogSensor]
LocationId [PK/FK -> Sensor]
SensorNo [PK/FK -> Sensor]
UpperLimit
LowerLimit
[SwitchSensor]
LocationId [PK/FK -> Sensor]
SensorNo [PK/FK -> Sensor]
OnTimeLimit
[Reading]
LocationId [PK/FK -> Sensor]
SensorNo [PK/FK -> Sensor]
ReadingDtm [PK]
[ReadingSwitch]
LocationId [PK/FK -> Reading]
SensorNo [PK/FK -> Reading]
ReadingDtm [PK/FK -> Reading]
Switch
[ReadingValue]
LocationId [PK/FK -> Reading]
SensorNo [PK/FK -> Reading]
ReadingDtm [PK/FK -> Reading]
Value
[Alert]
LocationId [PK/FK -> Reading]
SensorNo [PK/FK -> Reading]
ReadingDtm [PK/FK -> Reading]
Run Code Online (Sandbox Code Playgroud)
基本上,ReadingSwitch和ReadingValue是Reading和SwitchSensor的子类型,AnalogSensor是Sensor的子类型.读取可以是SwitchReading或ValueReading值 - 它不能同时为两者,并且Sensor可以是AnalogSensor或SwitchSensor.
到目前为止我遇到的唯一方法是在这里.
肯定有一个更好的方法来做这种事情.
我能想到的另一种方法是没有子类型但完全扩展所有内容:
[SwitchSensor]
LocationId [PK/FK -> Location]
SensorNo [PK]
[AnalogSensor]
LocationId [PK/FK -> Location]
SensorNo [PK]
[SwitchReading]
LocationId [PK/FK -> SwitchSensor]
SensorNo [PK/FK -> SwitchSensor]
ReadingDtm
Switch
[AnalogReading]
LocationId [PK/FK -> AnalogSensor]
SensorNo [PK/FK -> AnalogSensor]
ReadingDtm
Value
[AnalogReadingAlert]
LocationId [PK/FK -> AnalogReading]
SensorNo [PK/FK -> AnalogReading]
ReadingDtm [PK/FK -> AnalogReading]
[SwitchReadingAlert]
LocationId [PK/FK -> SwitchReading]
SensorNo [PK/FK -> SwitchReading]
ReadingDtm [PK/FK -> SwitchReading]
Run Code Online (Sandbox Code Playgroud)
这可能不是那么糟糕,但我也有引用Alert表的表,所以它们也必须重复:
[AnalogReadingAlertAcknowledgement]
...
[AnalogReadingAlertAction]
...
[SwitchReadingAlartAcknowledgement]
...
[SwitchReadingAlartAction]
Run Code Online (Sandbox Code Playgroud)
等等
这个问题对任何人都有意义吗?
Per*_*DBA 18
这些都不是必要的,尤其不是表格翻倍.那是纯粹的疯狂.
由于关系数据库建模标准(IDEF1X)已经使用超过25年(至少在高质量,高性能的市场末端),我使用该术语.日期和达尔文,尽管1与他们都做了伟大的工作一致进步抑制关系模型,他们不知道IDEF1X的,直到我把它带到了他们的注意,2009年,因此有一个新的术语2对,我们有标准术语几十年来一直在使用 此外,新术语并不像IDEF1X那样处理所有情况.因此,我使用既定的标准术语,并避免使用新的术语.
即使是"分布式密钥"的概念也无法识别潜在的普通PK :: FK关系,它们在SQL中的实现以及它们的功能.
Relational和IDEF1X概念是其标识符和迁移.
当然,供应商并不是完全正确的,他们有奇怪的东西,如"部分指数"等,在理解基础知识时完全没有必要.但是,当这个概念被标准化并在25年前给予全面处理时,着名的"学者"和"理论家"提出了不完整的新概念......这是意想不到的,也是不可接受的.
IEC/ISO/ANSI SQL几乎不能完全处理Codd的3NF(Date和Darwen的"5NF"),它根本不支持Basetype-Subtype结构.对此没有声明性约束(应该有).
CHECK CONSTRAINTs等进行一些操作(我出于多种原因避免使用Triggers). 但是,我考虑到了所有这些.为了让我能够在StackOverflow上有效地提供数据建模服务,而不必以完整的话语为前提,我故意提供可以由有能力的人使用现有SQL和现有约束来实现的模型,无论他们需要什么程度.它已经简化,并包含共同的执行级别.如果有任何问题,请询问,您将收到.
我们可以使用链接文档中的示例图形和完全符合IDEF1X标准的传感器数据模型
不熟悉关系建模标准的读者可能会发现 IDEF1X表示法很有用.认为数据库可以映射到对象,类和子类的读者被告知,进一步阅读可能会造成伤害.这比福勒和安布勒读过的还要多.
Basetype-Subtype结构有两种类型.
独占意味着每个Basetype行必须有一个且只有一个Subtype行.在IDEF1X术语中,Basetype中应该有一个Discriminator列,用于标识为其存在的Subtype行.
对于两个以上的子类型,这是需要的,我实现了一个Discriminator列.
对于两个Subtypes,因为这很容易从现有数据派生(例如,Sensor.IsSwitch是鉴别器Reading),我不为其他显式Discriminator列建模Reading.但是,您可以自由地遵循标准,并实施一个鉴别器.
我将详细介绍每个方面.
Discriminator列需要CHECK CONSTRAINT确保它在值的范围内,例如:IN ("B", "C", "D").IsSwitch是a BIT,它是0或1,因此已经受到限制.
由于Basetype的PK定义了它的唯一性,因此只允许一个Basetype行; 不能插入第二个Basetype行(因此没有第二个Subtype行).
因此,如链接建议的那样,在Basetype中实现诸如(PK,Discriminator)之类的索引是过度的,完全冗余的,额外的不必要的索引.唯一性在于PK,因此PK加上任何东西都是独一无二的).
IDEF1X不需要Subtype表中的Discriminator.在Subtype中,它再次受到其PK的唯一性的约束,根据模型,如果Discriminator被实现为该表中的列,则其中的每一行将具有相同的Discriminator值(每本书将是" B";每一个ReadingSwitch都是一个IsSwitch).因此,将Discriminator实现为子类型中的列是荒谬的.再次,完全冗余,一个额外的不必要的索引,在子类型中实现索引,如(PK,Discriminator):唯一性在PK中,因此PK加上任何东西都是唯一的).
链接中确定的方法是实现参照完整性的火腿臃肿和膨胀(大量数据重复,无用).作者可能没有在其他任何地方看到过这种结构.理解SQL并使用它是一个基本的失败,因为它是有效的.这些"解决方案"是典型的遵循教条"SQL无法做到......"的人,因此对SQL可以做什么视而不见.福勒和安布勒的盲目"方法"导致的恐怖事件更加严重.
子类型PK也是Basetype的FK,这是所有必需的,以确保子类型在没有父类型的情况下不存在.
SQL CHECK CONSTRAINT仅限于检查插入的行.我们需要在同一个表或另一个表中检查插入的行与其他行.因此,需要"用户定义"功能.
编写一个简单的UDF,它将检查Basetype中是否存在PK 和 Discriminator,并返回1 if EXITS或0 if NOT EXITS.每个Basetype需要一个UDF(不是每个Subtype).
在Subtype中,CHECK CONSTRAINT使用PK(既是Basetype和Subtype)又使用Discriminator 值实现调用UDF的方法.
此特定语法和代码在Sybase ASE 15.0.2上进行了测试(它们对SQL标准符合性非常保守).
我知道"用户定义"函数的限制因每个SQL平台而异.但是,这是最简单的,而AFAIK的每个平台都允许这种结构.(不知道Non-SQL做了什么.)
是的,当然,这个聪明的小技术可用于实现您可以在数据模型中绘制的任何非平凡的数据规则.特别是要克服SQL的局限性.请注意我要避免双向约束(循环引用).
因此,CHECK CONSTRAINT在Subtype中,确保PK加上正确的 Discriminator存在于Basetype中.这意味着只有 Basetype(PK)存在该子类型.
任何后续尝试插入另一个子类型(即打破独占规则)都将失败,因为BaseType中不存在PK + Discriminator.
通过其PK约束的唯一性来阻止任何后续尝试插入相同子类型的另一行.
唯一缺少的部分(链接中未提及)是规则"每个Basetype必须至少有一个Subtype"未强制执行.交易代码中很容易说明这一点(我不建议两个方向的约束或触发器); 使用正确的工具来完成工作.
Basetype(父级)可以托管多个子类型(子级)
没有单一的子类型可供识别.
鉴别符不适用于非独占子类型.
通过使用Basetype PK对Subtype表执行存在性检查来识别Subtype的存在.
只需排除CHECK CONSTRAINT调用上面的UDF即可.
PRIMARY KEY,FOREIGN KEY和通常的范围CHECK CONSTRAINTS,充分支持非排他性亚型的所有要求. 有关详细信息; 图表概述,包括细节; 以及Subtypes和Optional Column表之间的区别,请参阅此Subtype文档.
我也被CJ Date和Hugh Darwen不断提到"进一步" 关系模型.经过多年的互动,基于一致的证据,我得出的结论是,他们的工作实际上是对它的贬低.他们没有采取任何措施来进一步推动EF Codd博士的开创性工作,即关系模型,以及破坏和压制它的一切.
他们对关系术语有私人定义,这当然会严重阻碍任何沟通.对于我们自1970年以来的术语,他们有了新术语,以表明他们已经"发明"了它.典型的欺诈和盗贼.
所有未发表评论的读者都可以跳过此部分.
不幸的是,有些人接受过错误处理的事情(正如那些在这个空间里为"理论家"传递的怪人所建议的那样),需要付出巨大的额外代价,即使以正确的方式明确指示,他们也无法理解.也许这就是为什么正确的教育不能用问答格式代替的原因.
山姆:我注意到这种方法并不能阻止某人
UPDATE用来改变Basetype的鉴别器值.怎么能阻止这种情况?FOREIGN KEY子类型方法中的+重复Discriminator列似乎克服了这一点.
是.此方法不会阻止某人使用UPDATE更改密钥,某些不相关的表中的列或头痛.它回答了一个具体的问题,而没有别的.如果您希望阻止某些DML命令或其他任何命令,请使用为此目的设计的SQL工具.所有这些都超出了这个问题的范围.否则,每个答案都必须解决每个不相关的问题.
回答.由于我们应该使用自1993年开始提供的开放式架构标准,因此对数据库的所有更改都只通过ACID事务处理.这意味着直接INSERT/UPDATE/DELETE禁止所有表格; 数据保留完整性和一致性(ACID术语).否则,当然,你有一个流血的混乱,例如你的.以及后果.那些怪胎不懂交易,他们只懂单个文件INSERT/UPDATE/DELETE.再次,超出范围.如果您需要更多详细信息,请打开一个新问题,我会详细解答.
此外,FK +重复D +重复索引(以及其中的大量成本!)没有任何类似的东西,我不知道你从哪里"看似".
dtheodor:这个问题是关于参照完整性的.参照完整性并不意味着"检查引用是否对插入有效并忘记它".它意味着"永远保持参考的有效性".重复鉴别器+ FK方法保证了这种完整性,而您的UDF方法则不然.毫无疑问,
UPDATEs不应该破坏参考.
这里的问题是双重的.首先,您需要在关系数据库和开放架构标准的其他领域进行基础教育.其次,你需要去编程,因为即使我已经给你答案了,你也不理解它,你是盲目地重复这种狂热的咒语,这种特殊的方法不会做那种大规模低效的邪教方法.没有重复我打开一个新问题的请求,因此提供了你明显不理解的关系数据库的其他领域的完整答案(在Date和Darwen邪教中没有人理解关系数据库的基础知识),我真的这样做了不知道该怎么办.
好的,简短的回答,这真的属于另一个问题.独家子类型中的判别器如何受到无效更新的保护?
明晰.是的,参照完整性并不意味着"检查引用是否对插入有效并且忘记了它."我没有说它也意味着.
参照完整性意味着数据库中的引用FOREIGN KEY具有PRIMARY KEY与其引用的完整性.
声明性引用完整性表示数据库中声明的引用...
CONSTRAINTFOREIGN KEY ... REFERENCES ...
CONSTRAINT CHECK ...
由RDBMS平台维护,而不是由应用程序代码维护.
它并不意味着"保持基准的有效性永远"要么.
原始问题关于RI的子类型,我已回答它,提供DRI.
您的问题不考虑RI或DRI.
您的问题,虽然被错误地询问,因为您希望方法提供方法未提供的内容,并且您不了解您的要求是通过其他方式实现的,独家子类型中的判别者如何受到无效更新的保护?
答案是,使用自1993年以来我们应该使用的开放式架构标准.这可以防止所有无效UPDATE的.如果您不愿意阅读链接文档并理解它们,那么您的担忧就不是问题,它就不存在了.这是简短的答案.
但你第一次和第二次都不明白简短的回答,为了避免让你第三次重复口头禅,我将不得不解释它.这里.在错误的地方.
不允许任何人走到数据库并在此处更改列或在那里更改值.直接使用SQL或直接使用SQL的应用程序.如果这是允许的,你将没有安全的数据库,你将在廉价的妓院有一个妓女.
数据库(包括多行INSERT/UPDATE/DELETE)的所有更新(小写)都实现为ACID SQL事务.而且只有交易.所述组交易的构成数据库API,暴露到使用数据库的任何应用程序.
SQL有ACID事务.非SQL没有事务.你的崇拜喜欢非SQL.他们对交易一无所知,让芦荟Open Architecture.他们的非架构是一个单片堆栈.还有一个每月都会被重构的"数据库".
由于您编写的唯一事务将在单个事务中插入basetype +子类型,因此作为单个逻辑工作单元,将保持basetype :: subtype关系的Integrity(数据完整性,而不是参照完整性),并在数据库.因此,对数据库的所有更新都将是有效的,不会有任何无效更新.
既然你没有那么愚蠢到UPDATE没有服务员在一行中编写Discriminator列的代码DELETE Previous_Subtype,将它放在一个Transaction中,并且GRANT EXEC对用户ROLES有权限,那么数据库中的任何地方就不会有Invalid Discriminator.