正则表达式在mysql字段中提取json值

时间:2013-12-23 21:55:49

标签: mysql regex json

我有一个“用户”表,其中包含一个“赋值”字段,其中包含一个课程ID列表,然后被分配,以及它们是一个类似json的字符串中是必需的还是可选的(缺少顶级括号)< / p>

"BUS1077":{"startDate":"2013-09-16","hasPrerequisite":"","list":"required"},
"CMP1042":{"startDate":"2013-09-16","hasPrerequisite":"","list":"optional"},
"CMP1108":{"startDate":"2013-09-16","hasPrerequisite":"","list":"required"}

我还有一个名为“progress”的表,其中列出了课程ID,如BUS1078,以及它们是否已完成。

我需要一个查询来选择已完成所有必修课程的用户。

像:

SELECT userid FROM users 
where (count([ids from users.assignments where list:"required"] as courseid)
      =count([extracted ids] joined using( courseid) where "complete"=1))

所以只有两个表

users (userid,assignments)
progress (id,userid,courseid,complete)

最后我想选择每个必修课程完成的用户ID

(注意,数据库本身要复杂得多,但这代表了问题的要点)

3 个答案:

答案 0 :(得分:2)

从MySQL 5.1开始,您可以使用common_schema的内置函数来实现此目的。我自己没有使用它,但我发现了一个很好的博客,关于如何解析JSON存储的数据并做一些有用的事情。

博客:http://mechanics.flite.com/blog/2013/04/08/json-parsing-in-mysql-using-common-schema/

答案 1 :(得分:1)

我不熟悉MySQL中的RegEx实现,但这种基本方法应该有效:

SELECT userid FROM users WHERE NOT EXISTS(
     SELECT NULL FROM assignments WHERE NOT EXISTS(
        SELECT NULL FROM progress WHERE
            progress.userid = users.userid
            AND REGEXMATCH(
               assignments.assignment, 
               '(^|,)"' + progress.courseid + '":.*?"list":"required"\}') >= 0
            )
        )
     )

这应该找到所有用户尚未完成所需分配的用户。

鉴于课程ID和“必需”一词不太可能出现在上下文之外,正则表达式本身可能更加幼稚,例如:

  '"' + progress.courseid + '"[^}]+"required"'

关于相关子查询,我不知道MySQL当前的局限性,但是使用连接可以完成同样的事情。使用EXISTS应优先于COUNT,因为计数需要在整个数据集中进行聚合,而不是在发现的第一个不匹配时允许快捷方式。

答案 2 :(得分:0)

如果您的courseid长度始终为7个字符,则assignments字段中的列表最多可包含10个字符 你可以使用这个sqlFiddle

SELECT U.userId
FROM users U
WHERE NOT EXISTS
  (SELECT 1 FROM
        (SELECT users.userid,courseName,
              (Assignments REGEXP CONCAT('"',courseName,'"[^}]+(:"required"})'))as Required,
               Assignments,
               courseid,complete
         FROM
           (SELECT userid,courseName FROM
                (SELECT userid,SUBSTRING_INDEX(SUBSTRING_INDEX(assignments,'":{"startDate',course.num),'"',-1) as courseName
                 FROM users,(SELECT 1 as num 
                             UNION SELECT 2
                             UNION SELECT 3
                             UNION SELECT 4
                             UNION SELECT 5
                             UNION SELECT 6
                             UNION SELECT 7
                             UNION SELECT 8
                             UNION SELECT 9
                             UNION SELECT 10)course
                 )T WHERE LENGTH(courseName)=7
           )Courses
         INNER JOIN users ON users.userid = Courses.userid
         LEFT JOIN progress ON users.userid = progress.userid
                       AND Courses.courseName = progress.courseId
                       AND progress.complete = 1
        )AllCourses
   WHERE AllCourses.userId = U.userId
   AND AllCourses.Required = 1
   AND Complete IS NULL
   )

查询的作用是从赋值字段中获取courseName(s)并查看是否需要并设置必需的标志,然后LEFT JOIN with progress,我们有Required列,当课程不存在时,Complete为NULL正在进行或完成时不是1。 然后我们选择用户ID WHERE没有EXISTS(在他们的课程中的记录,其中Required = 1 AND Complete IS NULL)

在小提琴中,我让用户2只完成了一个选修课程。因此不会返回userId 2.

您可以运行AllCourses子查询的内部选择,查看所有用户的所有课程数据,以及他们是否完成了必修课程。