我有一个“用户”表,其中包含一个“赋值”字段,其中包含一个课程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
(注意,数据库本身要复杂得多,但这代表了问题的要点)
答案 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
子查询的内部选择,查看所有用户的所有课程数据,以及他们是否完成了必修课程。