结果基于用户技能

时间:2014-02-01 18:24:13

标签: mysql sql

我在users表中有一个名为skills的列,其类型为VARCHAR,值为implod,由PHP编写。例如1,2,3,4,5

我正在尝试制作作品列表,作品具有相同的技能组合(不同的ID ),每个work都有自己的技能列,其格式与前一个。例如2,6,5,3,7

所以我想将这两个列与查询进行比较,看看作品是否具有用户的全部或部分技能,如果是,则显示它。

正如已发布的社区主题,我发现了FIND_IN_SET或多个LIKE语句的一些解决方案,但实际上它们不适合我的情况。

由于我不是查询粉丝,所以这种比较的最佳或最佳做法是什么?

2 个答案:

答案 0 :(得分:3)

最佳解决方案是更改架构。不要在一列中存储多个值。用户和技能之间的关系是“多对多”的关系。对于任何多对多关系,您应该使用三个表:

users -- one record for each user
+----+------+
| id | name |
+----+------+
| 1  | Bob  |
| 2  | Joe  |
| 3  | Ken  |
+----+------+

skills -- one record for each possible skill
+----+-------------+
| id | name        |
+----+-------------+
| 1  | PHP         |
| 2  | CSS         |
| 3  | JS          |
| 4  | MySQL       |
+----+-------------+

userSkills -- relational table that maps skills to users
+--------+---------+
| userId | skillId |
+--------+---------+
| 1      | 1       |
| 1      | 2       |
| 1      | 3       |
| 1      | 4       |
| 2      | 2       |
| 2      | 3       |
| 2      | 4       |
| 3      | 1       |
| 3      | 4       |
+--------+---------+

现在,当您想要了解Joe的技能时,您可以执行以下查询:

SELECT
    s.name
FROM
    users u
    INNER JOIN userSkills us
        ON u.id = us.userId
    INNER JOIN skills s
        ON us.skillId = s.id
WHERE
    u.name = 'Joe'

作品和技能之间的关系也是多对多的关系。我们还需要两个表,因为我们已经有了skills表。

works
+----+-----------------------+
| id | name                  |
+----+-----------------------+
| 1  | Client-side developer |
| 2  | Server-side developer |
| 3  | All-around developer  |
+----+-----------------------+

workSkills
+--------+---------+
| workId | skillId |
+--------+---------+
| 1      | 2       |
| 1      | 3       |
| 2      | 1       |
| 2      | 4       |
| 3      | 1       |
| 3      | 2       |
| 3      | 3       |
| 3      | 4       |
+--------+---------+

现在,您可以通过以下查询找到服务器端开发人员所需的所有技能:

SELECT
    s.name
FROM
    works w
    INNER JOIN workSkills ws
        ON w.id = ws.workId
    INNER JOIN skills s
        ON ws.skillId = s.id
WHERE
    w.name = 'Server-side developer'

现在是棘手的部分。获取给定工作的用户列表。以下查询将为您提供具有与指定工作相同技能的用户列表。他们对这项工作的技能越多,他们的得分就越高:

SELECT
    u.name,
    COUNT(s.name) AS score
FROM
    users u
    INNER JOIN userSkills us
        ON u.id = us.userId
    INNER JOIN skills s
        ON us.skillId = s.id
    INNER JOIN workSkills ws
        ON s.id = ws.skillId
    INNER JOIN works w
        ON ws.workId = w.id
  WHERE
      w.name = 'Server-side developer'
  GROUP BY
      u.name
  ORDER BY
      score DESC

输出:

+------+-------+
| name | score |
+------+-------+
| Bob  | 2     | -- Bob has all four skills, but only PHP and MySQL are relevant
| Ken  | 2     | -- Ken has PHP and MySQL skills, same as this work requires
| Joe  | 1     | -- Joe has CSS, JS, and MySQL skills...only MySQL is relevant
+------+-------+

SQLFiddle example

答案 1 :(得分:1)

我建议你不要让技能ids像那样崩溃。保留5个表格。

  1. 用户(用户ID,名称)
  2. 技能(技能,技能名称)
  3. usersskills(skillid,userid)
  4. 作品(workid,name)
  5. workskills(workid,skillid)
  6. 您将拥有干净且可扩展的结构,并且易于提取数据。

    获取用户技能的SQL是

    SELECT skillid, skillname FROM Skills INNER JOIN UsersSkills ON Skills.skillid = UsersSkills.skillid WHERE UserSkills.userid = 3
    

    获取作品技巧的SQL

    SELECT skillid, skillname FROM skills INNER JOIN workskills ON skills.skillid = workskills.skillid WHERE workskills.workid = 1
    

    我们假设我们有这两个表

    usersskills              worksskills
    +--------+---------+     +--------+-------+
    |skillid | userid  |     |skillid |workid |
    +--------+---------+     +--------+-------+
    | 1      | 1       |     | 1      | 3     |
    | 2      | 1       |     | 2      | 3     |
    | 3      | 1       |     | 3      | 3     |
    | 4      | 1       |     | 4      | 3     |
    | 1      | 2       |     | 5      | 3     |
    | 2      | 2       |     +--------+--------
    +--------+---------+
    

    这里我们有2个用户,第一个有4个技能,第二个有2个技能。我们的工作(身份3)需要5种不同的技能。

    以下是此项工作的用户资格。

    +--------+-------------+
    |userid  |scorepercent |
    +--------+-------------+
    |1       |80           |
    |2       |40           |
    +--------+-------------+
    

    用户1的工作资格为80%,用户2资格为40%

    SQL(简短和干净)

    按分数排序的所有用户

    select 
        userid,
        (count(skillid) * 100 / (select count(*) from skillswork where workid = 3)) as score
    from
        skillsuser
    where
        skillid in (select skillid from skillswork where workid = 3)
    group by
        userid
    order by 
        score desc
    

    如果您不需要百分比,只需要一个简单的SQL

    select 
        userid,
        count(skillid) as score
    from
        skillsuser
    where
        skillid in (select skillid from skillswork where workid = 3)
    group by
        userid
    order by 
        score desc
    

    单个目标用户

    select 
        userid,
        (count(skillid) * 100 / (select count(*) from skillswork where workid = 3)) as score
    from
        skillsuser
    where
        skillid in (select skillid from skillswork where workid = 3)
        and
        userid = 1
    

    SQLFiddle