草庐IT

mysql - 在没有存储过程、触发器或 UDF 的情况下实现父类(super class)型和子类型数据完整性

coder 2023-10-06 原文

我经营一家小型食品生产企业,我需要管理客户订单。我已经为我的业务的这方面构建了一个概念数据模型,但我需要一些关于如何在 RDMS 中完全实现它的指导。

作为第一步,我提出了下面给出的逻辑模型。我的数据建模知识有限,所以我的图表可能有错误,但希望它传达了我的意图。请注意,这只是更大模式的简化部分,为了简单起见,我只展示了相关的表格。

数据模型简介

  • 一个客户 Ordr 可以有一个或多个 OrdrItems
  • OrdrItem 可以是 FoodItem 或 ComboItem
  • ComboItem 是两个或多个 FoodItem 的逻辑分组

我已经在 MySQL 中实现了上述模式,并且编写了一些小程序来用客户订单填充表。这样就完成了工作,但没有太多考虑数据完整性。我注意到,在这个实现中,一些数据完整性规则并没有在数据库级别强制执行。

例如,FoodItem 是 OrdrItem 的子类型。对于 FoodItem 中的每一行,OrdrItem 中必须恰好有一个对应的行。但是,在其当前实现中,我可以从 FoodItem 中删除一行,从而在 OrdrItem 中留下一行,而在其中一个子类型表中没有相应的行。这应该是不允许的。

一些进一步的数据限制

  • 一份订单必须至少有一个关联的“订单项”(即订单不能为空)
  • 订单项必须恰好属于 FoodItem 或 ComboItem 的一个关联子类型(即,OrderItem 不能既是 FoodItem 又是 ComboItem)。
  • 将来可能会出现一些进一步的限制

我希望将这些数据完整性规则嵌入到数据库中,这样我就不必担心它们在我编写的每个新客户端应用程序、一次性脚本或劣质 SQL 语句中的执行情况。我怀疑如果我不在数据库级别做出这些保证,我以后遇到数据完整性问题的可能性会大大增加。

问题

我对存储过程、触发器和用户定义函数只有最微不足道的了解。我的印象是这些功能中的部分或全部可以帮助我实现我想要的。但是,如果我可以单独使用检查约束、外键和相对简单的功能来完成工作,我会很乐意走那条路。基本上,我想尽可能地限制复杂性,如果没有必要,我不会引入每一个漂亮的数据库特性。是否可以在不借助存储过程、触发器、用户定义函数和其他更深奥的数据库功能的情况下确保我想要的数据完整性?

我愿意使用 MySQL 或 Postgresql 来实现我的解决方案,因为我对这两个系统都有基本的工作知识。

最后,如果这种实现数据完整性的方法被认为是矫枉过正,或者如果有更实用但略有不完美的解决方案,我也持开放态度。

最佳答案

不幸的是,“现代”DBMS 并不直接支持您可以放入 ER 图中的所有奇特符号1。物理 FOREIGN KEY 实际强制执行的所有内容是子行不能在没有父行的情况下存在,这会为您提供一个普通的“1 到 0 或 N” 关系2

你可以...

  • 使 FK 可以为 NULL 以将关系的左侧变形为“0 或 1”
  • 和/或您可以在 FK 顶部放置一个键,将右侧变形为“0 或 1”

...但这就是您“开箱即用”所能做的一切。

要执行其他规则3,您要么必须显着“丑化”模型并可能使用延迟约束4,要么您可以在程序代码5.

虽然将尽可能多的完整性规则放入数据库本身的直觉是正确的,但在程序代码中执行“异常”情况而不是强制执行“异常”情况仍然被认为是一种较小的邪恶将数据模型扭曲成椒盐卷饼以适应声明性约束的局限性。

事实上,最流行的技术之一是创建“API”:

  • 禁止客户端直接修改表(通过撤销适当的权限)
  • 并允许他们仅通过您编写的存储过程修改数据,这些存储过程执行所有必要的业务规则6。这样,您就可以通过同一个“票据交换所”汇集所有客户,没有人会行为不端。

不过,这是一个相当“繁重”的解决方案,如果场景足够简单,可能不值得这么麻烦。如果您的应用程序是唯一一个要修改数据库的应用程序,那么只需在客户端代码中实现规则就足够了...


1 例如继承(也称为子类型、类别、泛化层次)。

2 左侧:任何给定的 child 都必须有“1”个 parent 。右侧:任何给定的 parent 必须有“0 或 N”个 child 。

3exclusivity and presence正如您已经指出的那样,这对继承很重要。

4 PostgreSQL 支持,MySQL 不支持。

5 按优先顺序:

  • 触发器和存储过程
  • 中间层
  • 或客户。

6 但要注意竞争条件:transaction isolation将保护您免受其中一些攻击,但不是全部,您可能需要进行一些显式锁定。

关于mysql - 在没有存储过程、触发器或 UDF 的情况下实现父类(super class)型和子类型数据完整性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23313461/

有关mysql - 在没有存储过程、触发器或 UDF 的情况下实现父类(super class)型和子类型数据完整性的更多相关文章

  1. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  3. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  4. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  5. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  6. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  7. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

    我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

  8. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  9. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  10. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

随机推荐