【问题标题】:Searching a field containing multiple values搜索包含多个值的字段
【发布时间】:2016-12-13 18:42:38
【问题描述】:

假设我的表中需要一个名为skills 的字段。它应该存储一个人的各种技能,例如phpjavaGolang

将此类数据存储在数据库中的适当方法是什么,以便更容易通过技能进行搜索

编辑 1

用户可以输入任何他想要的技能,上面只是一个例子

用户可以在文本框中输入一项或多项技能,以逗号分隔

例子

skill1,skill2,skill3 

【问题讨论】:

  • 也许您可以提供一个示例来说明您的 Edit 1 的含义。
  • 不明白为什么这被否决了!这很好地说明了使用SET 列的情况。

标签: mysql sql database database-design mariadb


【解决方案1】:

您可能应该重新考虑您的设计方法并将这些技能存储在一个名为skills 的相关表中,其中包含skill_idskill_nameskill_desc 等列...然后使用交叉引用表链接@ 987654325@ 来自您的人员表,skill_id 来自skills 表。

如果您无法执行重新设计,您可以使用带有一系列LIKE 调用的查询:

SELECT *
FROM people
WHERE skills LIKE '%php%' 
   OR skills LIKE '%java%' 
   OR skills LIKE '%Golang%';

但那是相当草率的。我会重新设计。使用LIKE 将否定索引的任何好处。

要扩展上面的多个表,当用户键入逗号分隔的技能列表时,您需要将其解析为集合/数组,检查它们是否存在于新的 skills 表中。如果它不存在,则插入它。然后,或者如果它确实存在,则拉取skill_id 并将其插入到带有person_idperson_skills_xref 表中(如果该组合尚不存在)。

这样您就可以执行如下选择语句:

SELECT s.skill_id, s.skill_name, s.skill_desc
FROM skills s
JOIN people_skills_xref ps
ON s.skill_id = ps.skill_id
WHERE ps.person_id = @personID;

这将为您提供 person_id@personID 的人的所有技能。

或者您可以使用以下查询选择people 表中具有特定skill_id 的所有人:

SELECT p.person_id, p.person_name, p.person_email
FROM people p
JOIN people_skills_xref ps
ON ps.person_id = p.person_id
WHERE ps.skill_id = @skillId;

skill_name 使用LIKE

SELECT p.person_id, p.person_name, p.person_email
FROM people p
JOIN people_skills_xref ps
ON ps.person_id = p.person_id
JOIN skills s
ON s.skill_id = ps.skill_id
WHERE s.skill_name LIKE @skillName;

其中@skillName 将包含'%sql' 的搜索字符串以匹配以sql 结尾的任何内容,例如mysqlpl/sql 或只是sql

【讨论】:

  • 检查编辑...用户可以输入任何技能,所以我事先不知道技能
  • 我不确定这会如何改变我的建议。通过people_skills_xref 表在peopleskills 上建立M:M 关系,您可以将任意数量的技能以任意组合形式应用于任意数量的人。另外,您不会复制您的技能。 skills 表中只需要一个条目。
【解决方案2】:

你应该使用 3 个表:

User
-----------------
id
name

Skill
-----------------
id 
name

User_Skill
-----------------
user_id
skill_id

表 User 包含您的所有用户,表 Skills 包含所有可用的技能,表 User_Skills 连接这两个表。因此,如果您想向用户添加技能,您应该在表 User_Skill 中插入值。

如果你想检索一个用户的所有技能,你可以使用:

select s.* from Skills s left join User_Skills us on us.skill_id = s.id where us.user_id = <insert user id>; 
【解决方案3】:

IMO 更简单(同时易于使用)的方式是使用 SET 类型的唯一列。

工作原理的基本总结:

  • 字段定义:类似于skills SET('php','java','goLang',...)

  • 填充字段(同时使用一项或多项技能):UPDATE table SET skills = 'php, java'

  • 寻找给定技能:SELECT * FROM table WHERE FIND_IN_SET('java', skills) &gt; 0

看看这个MySQL page,假设 MariaDB 应该提供相同的功能。

重要提示:我认为这是 only 方法为您提供所需的强大功能,因为您在 OP 中没有明确说明,但可能是要求:给定的人可能有几个技能!

第二个重要提示:OP 的编辑状态

用户可以输入任何他想要的技能

这是SET 不能根据需要直接工作的唯一一点,因为必须在列定义级别注册不同的可能值(但显然可以更新以发展) .
所以如果用户想要提及一些目前未知的技能,你必须向他提供一种方法来“声称”这个新技能被注册,然后在定义栏中注册它,并实际更新用户skills字段。

【讨论】:

  • 对方法的声明似乎很棒......stackoverflow风格:)
  • @user2650277 作为一个非英语母语的人,我不知道我的话听起来如何:从你的评论中我想我没有选择正确的表达方式......我也写了这个答案相当快,所以它有点缩写。我对“要求”的意思是:用户应该有一个建议的(注册)技能列表,他将从那里选择他想要的东西。 And this list should include something like `other', which when selected leads to an input area where to type the new skill.然后你的后端脚本应该检测到这种情况并相应地处理它(在更新表之前修改 col def)。
  • 我完全理解你的意思。我想说stackoverflow也使用你所指的建议系统
  • @user2650277 哦!所以我现在明白我误解了你之前的评论:) 同样,作为非母语人士,我经常会不确定任何事情。值得注意的是,因为“真棒”既可以是“令人印象深刻”,也可以是“非常棒”,所以我不知道应该正面还是负面地阅读它。感谢您的澄清。
【解决方案4】:

将此类数据存储在 数据库

您应该有一个名为 Skills 的单独表,其中应该存在所有技能,并且还应该有一个 FOREIGN KEY 引用父表 PRIMARY KEY 字段。

这样,在需要时,您可以使用父表 JOIN 和父表键字段 GROUP BY(如果您想列出所有技能,则 GROUP_CONCAT())并获得所有相关技能

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-23
    • 1970-01-01
    • 2019-07-26
    相关资源
    最近更新 更多