假设我有一个名为“学生”的表格。
此表包含列
让我们想象一下,我从该表中创建了另一个表“ OriginSurnames”,其中包含“ Students”表中学生的不同姓氏的来源国。
此表具有以下列:
在表“ Students”中声明StudentSurName是否有意义,如果我在表“ Students”中不存在“ OriginSurnames”项,那么我不能在该表中输入“ StudentSurName”。
答案 0 :(得分:2)
技术上的答案很简单,但是问题在于您自己的理解程度。
了解数据(建模的目的)和设计数据库(建模的最后一步)是一门科学,具有一整套方法和过程,自1970年以来就没有改变。它是Logic的应用,是的,但专门用于数据。
编写代码,程序设计,良好实践;等是完全不同的科学。尽管它是逻辑的另一种应用。如果一个人擅长一门科学,那么他们通常却不擅长另一门科学。一个人同时兼具两种能力是非常罕见的……现代程序员无论如何都会在不了解其相关性的情况下做到这一点。它总是会导致问题。
在表Student中声明StudentSurName是否有意义,这是因为如果表“ Students”中不存在“ OriginSurnames”表,则我无法在该表中输入“ StudentSurName”。
您会感到困惑,因为您没有将数据(以及必须考虑的规范化和设计问题)与程序(以及应该做什么以及何时分开)分开。
让我们把数据当作数据,而仅将数据作为数据。
一个简单的事实是,OriginSurname
包含每个Surname
的一个实例,而Student
包含许多Surname
的实例。因此,该关系是OriginSurname.Surname
与许多Student.Surnames
的关系。
现在表示数据库中的一致性。您希望OriginSurname.Surname
仅在存在一个或多个Student.Surnames
时才存在。那就是基数。因此,该关系是一对OriginSurname.Surname
与一对Student.Surnames
(而不是一对多)。
此时不必担心如何获得该信息,因为这与程序有关,与数据库无关,并且数据库是数据的独立,自描述和集成存储。
它看起来像这样:
我所有的数据模型均以 IDEF1X 呈现,这是自1993年以来建立关系数据库建模的标准
我的 IDEF1X Introduction 对初学者来说是必不可少的阅读内容。
您有一个良好的数据库表OriginSurname
和一个可怕的Student
文件。为什么呢因为当您将一个Record ID
声明为主键时,可以确保Record ID
是唯一的,但是您没有什么可以使数据行保持唯一。 关系模型要求表中的逻辑行(与记录相对)是唯一的。
这应该失败,我们希望它失败,但它会成功:
INSERT Student VALUES( "John", "Smith" ) -- should succeed
INSERT Student VALUES( "John", "Smith" ) -- duplicate row: should fail
INSERT Student VALUES( "John", "Smith" ) -- duplicate row: should fail
对于给定的列,您需要在( Surname, Name )
上建立索引。现在,行(无论Record ID
是什么)都是唯一的。现在第二个John Smith
将失败。看起来像这样:
最后...
在学生表中声明StudentSurName是否为外键[引用OriginSurname表中的PK]是否有意义
是的。绝对。这就是数据库平台如何在数据库中维护引用完整性。相反,如果不声明外键,则OriginSurname.Surname
和Student.Surname
之间将没有完整性。
现在,我们将考虑维护数据库所需程序的注意事项,以及我们在数据库中定义的特定一致性。也就是说,一致性首先在数据库中定义,其次由与数据库表交互的相关程序组件维护。
姓氏
不能[必须]在OriginSurnames表中不存在,如果在“ Students”表中没有人
同意。
因为在将具有该姓氏的学生插入到“学生”表中之后,将姓氏插入到“表OriginSurnames”表中。
那是错误的想法。在SQL中,自1981年以来,我们进行过 ACID交易。我们不会通过直接INSERT/UPDATE/DELETE
向数据库中写入任何内容,因为这会使数据库处于状态一致,尤其是在程序或SQL平台或计算机系统出现故障的情况下。所有写入均已正确打包并一起写入事务中。
首先要了解,数据库必须一致;然后;中;然后写入数据库。那就是 ACID 中的 C 。
在我们的定义中,正确的是,OriginSurname
是父行,没有父项的子项Student
是不行的。
因此,当将新的Surname
添加到Student
时,必须INSERTed
是父OriginSurname
的{{1}},然后是INSERT
的学生。
同样,当学生为DELETEd
时,如果这是该Surname
的最后一次出现,则DELETE Student
之后必须带有DELETE
OriginSurname。
A 代表原子。这个想法是,与我们一样,一个Transaction包含多个对数据库的写操作,并且该Transaction被完全应用或根本不应用。因此是原子的。事务用BEGIN TRAN
和COMMIT TRAN
括起来(如果需要代码退出部分应用的事务,则用ROLLBACK TRAN
括起来。)
Student_Add
事务将如下。我提供了框架代码,您需要添加错误检查等:
BEGIN TRAN IF NOT EXISTS ( SELECT 1 FROM OriginSurname -- test if parent not exists WHERE Surname = @Surname ) INSERT OriginSurname -- insert parent first VALUES( @Surname, @Origin ) INSERT Student -- insert child second VALUES( @Name, @Surname ) COMMIT TRAN
Student_Drop
交易如下:
BEGIN TRAN DELETE FROM Student -- delete child first WHERE Name = @Name AND Surname = @Surname IF NOT EXISTS ( SELECT 1 FROM Student -- test if parent obsolete WHERE Surname = @Surname ) DELETE FROM OriginSurname -- delete obsolete parent second WHERE Surname = @Surname COMMIT TRAN
您的注释中的“之前”或“之后”根本不适用,因为我们正在执行一个原子事务,在该事务中我们安排SQL动词以匹配数据库的定义,并且始终保持数据库的一致性。 / p>
要完成ACID交易,请执行以下操作:
我代表隔离。
在交易期间,即在BEGIN TRAN
和COMMIT TRAN
之间,正在写入的数据库更改尚未完成。我们不希望其他活动数据库用户看到此不完整的数据,正是由于事务是原子的,他们必须继续仅看到一致的数据。因此,交易将由平台与其他用户隔离执行。除了了解那是如何发生的,您无需执行任何操作。正是在这个很小的时期内,资源被锁定,并且并发成为一个问题(在某种程度上,OLTP标准并未减轻它的负担)。
D 代表耐用。
每个交易必须是持久的,即。一旦执行COMMIT
,事务就必须保留在数据库中,并且不得由于系统崩溃或炸弹摧毁建筑物而丢失。这是SQL平台本身不提供的功能,您作为编码器无需执行任何操作。每个平台都提供各种恢复工具,DBA必须对其进行设置,以确保业务需要从硬崩溃中恢复。
请勿使用触发器。它们造成的问题比他们声称要解决的问题多得多。更重要的是,如果您按照建议使用事务(并且不直接写入数据库),则不需要它们。
关系模型问世之后的头三个十年,以及SQL的数据子语言,所有SQL平台都是真实的平台(服务器体系结构;完全符合SQL标准;各种恢复和耐用性设施;等)。自从1981年首次发布SQL标准以来,ACID事务就一直存在。
在20世纪90年代,各种假装的SQL套件作为免费软件提供。共享软件;蒸气软体;没有软件这些是米老鼠套件(我们不能称其为平台),没有服务器体系结构;没有体面的备份或恢复;并且不符合SQL标准。这意味着他们使用 SQL 一词是欺诈行为。充其量它们是伪装的SQL。
PusGre NON sql
没有ACID交易。作为一种有点看起来很像的功能,这些功能声明为“事务性”。因此,缺少标准SQL BEGIN/COMMIT/ROLLBACK TRAN
动词,因此您必须将该代码放入函数中。希望在线用户不太多。
我的非 sql
确实有事务,但是它们不符合SQL,即。它们不是真正的ACID。对于您正在做的简单工作来说,它就足够了。 NONsql动词是BEGIN WORK
。并且您必须将表设置为TYPE = InnoDB
。
答案 1 :(得分:0)
这是一对多关系。在这种关系中,具有最低关系(“ 仅一个 ”)的实体持有该关系(外键)
回答您的问题“在表Students中将StudentSurName声明为外键[...]有意义吗?” ,这不仅有意义,而且这是良好做法
这提供了:
姓氏:
建议使用不包含任何信息的数字PK。例如,如果您输入错误,则可能需要编辑StudentSurName
。不应编辑PK。
学生:
关于SurNames,此表的设计仍然可以改进。
最后以:
来源:
姓氏: