【问题标题】:Multivalued attributes in MySQLMySQL中的多值属性
【发布时间】:2017-12-07 12:23:34
【问题描述】:

我正在使用 MySQL 中的数据库来显示多值属性。我正在尝试找到一种方法来创建父表和子表。我正在使用的想法是拥有一个员工表和一个爱好表。爱好表中的爱好将被视为多值属性,因为员工可以拥有多个爱好。我的问题是,在创建这些表时,我应该使用 3NF 并添加一个 3 表来显示两者之间的关系,还是有办法用两个表来实现这个想法。我对多值属性不是很熟悉,所以我需要帮助来创建表,以了解每个表将使用什么样的键,以及最终形式。我相信我需要将其设为 3NF 形式并将爱好作为多值属性,但将爱好表中的爱好 id 作为主键,将员工 id 作为另一个主键,然后使关系表同时包含员工 id 和爱好 id 作为引用其他两个表的外键。任何有关显示多值属性的帮助或建议将不胜感激!

【问题讨论】:

  • 听起来你必须正确答案,即employee,hobby, & employee_hobby table。你被什么困住了?
  • 主要是创建表时的键,以确保我已经正确实现了所有内容。
  • 员工表,爱好表,两者都以id 列作为主键。一个多对多关联员工和爱好的表,有两列,employee_idhobby_id。这两列一起应该是相关表的复合主键。
  • 这是一个常见问题解答,您从谷歌搜索中学到了什么? “多值属性”是什么意思?关系/SQL 表每行/元组每列/属性有一个值。很多是不可能的。那你想说什么?非关系设计可能有这样的东西,但是你必须解释你的意思这样的设计。您是否想说关于在功能上不依赖于某些关系/表中的某些列集的列/属性?您是在谈论 MVD 吗?解释你的意思,而不是随便使用一个模糊的词。
  • SQL: multi valued attributes 的可能副本(以及许多其他)

标签: mysql data-structures database-design multivalue


【解决方案1】:

您已经为员工准备了一张桌子。它可能有一个主键,我们称之为employee_id

您需要一张桌子来满足您的爱好。它需要一个主键,我们称之为hobby_id

然后,您需要一种将员工和爱好多对多关联的方法。这是用第三个表实现的,我们称之为employees_hobbies。使用这样的名称是个好主意,因为下一个处理您的代码的人会立即认识到它的用途。

employees_hobbies 应该有两列,employee_idhobby_id。这两列一起应该是复合主键。然后,为了赋予员工一种爱好,您向 employees_hobbies 添加一行,其中包含两个 id 值。如果员工放弃了一项爱好,则删除该行。

如果您想要一份显示其爱好的员工列表,您可以这样做

 SELECT e.name, GROUP_CONCAT(h.hobbyname) hobbies
   FROM employees e
   LEFT JOIN employees_hobbies eh ON e.employee_id = eh.employee_id
   LEFT JOIN hobbies h ON eh.hobby_id = h.hobby_id
  GROUP BY e.employee_id, e.name

在此处使用LEFT JOIN 操作将没有任何爱好(所有工作和娱乐)的员工保留在您的列表中。

如果你想找出最常见的五个爱好和从事这些爱好的员工,试试这个

 SELECT COUNT(*) hobbycount, h.hobbyname, 
        GROUP_CONCAT(e.name ORDER BY e.name) people
   FROM hobbies h
   LEFT JOIN employees_hobbies eh ON h.hobby_id = eh.hobby_id
   LEFT JOIN employees e ON eh.employee_id = e.employee_id 
  GROUP BY h.hobbyname
  ORDER BY 1 DESC
  LIMIT 5

这种处理多对多关系的方式为您提供了各种对数据进行切片和切块的方式。

MySQL 是为这类事情而设计的,无论大小,都可以非常有效地处理它,尽管有相反的意见。

(避免将代理主键 id 放入您的 employees_hobbies 表中。它不会增加任何价值。)

【讨论】:

  • 一个简单的问题...在设置爱好表时,每个 hobby_id 中是否会有多个爱好?例如,我会将其设置为看起来像....hobby_id = 1(篮球、视频游戏、锻炼)还是每个特定的爱好都有自己的 hobby_id?我假设每个人都有自己的 ID。
  • hobbies 表中每行一个爱好。每个爱好都有自己的 ID。
【解决方案2】:

mva 对 mysql 不是很好。

存储它的最佳方式取决于您可以支付的价格和可访问性需求。如果你需要索引,因为数据库很大,而且负载很高,那么你可能需要 2 个表。

employee( id , name )
employee_hobbies ( id , employeeid , hobbyid )

但在最简单的情况下,或者如果您需要良好的可访问性,您可以将文本字段添加到员工表,将逗号分隔的 hobbyid 存储在那里,然后通过 FIND_IN_SET() 函数进行选择。

e.q.单表

employee( id , name , MVA VARCHAR(512) )

您需要确保以逗号分隔的所有 id 都适合 field , side 。

SELECT * from employee where FIND_IN_SET(some_hobbyid , MVA)

这种方法的优点是查询少, 劣势 - 可能比第一慢。

高负载系统也有优势,当导入狮身人面像时......但这是另一回事......

【讨论】:

  • 出于三个原因投反对票:1) MVA 在 MySQL 中确实工作得很好。 2) 连接表一般不应该有代理主键。 3) 非规范化、逗号分隔的方法确实是可伸缩性的可恶。
  • mysql 的可扩展性? :-)
  • O.Jones,我使用大数据,我知道它好不好,在 mysql 和 sphinx 中通过 MVA 查询需要多少毫秒。每个解决方案都有它的成本。 Mysql 不适合 MVA 。 Mysql 没有通过 MVA 属性索引或选择的本地方法。有时最好有一些异常然后编写大量代码来支持额外的表。我们的生活并不完美。
  • 只是好奇有没有人听说过普通连接?就像我知道左右、内连接和外连接一样,但是一个朋友在询问“常规”或“普通”连接……我假设常规连接只是简单地连接两个表中的所有条目问题,但他们也说有一种方法可以在不使用连接语句的情况下连接表......这是一回事吗?
  • @Justin 做一些研究然后发布另一个问题,不要在评论中提问。在 SQL 中,join on 单独表示 inner join on。逗号/.cross join,其优先级低于使用“join”的连接。将cross joininner join 视为相同的东西是合理的,onwhere 相同但绑定更紧密。转到一些介绍和手册并学习表达式的定义。 Read this.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-08
  • 1970-01-01
  • 2014-10-17
  • 1970-01-01
  • 2012-02-10
  • 1970-01-01
相关资源
最近更新 更多