使用 SQL Union 执行依赖于越来越宽松的条件的复杂报表查询
Using SQL Union to perform complex report query that depends on increasingly more relaxed conditions
我有以下架构(与问题相关的部分):
# schema
- table
* table field
# schema
- mods
* Id
* Title
* Affiliation
* Attended
- modusergrades
* ModId
* UserId
* QuestionValues
* Grade
* Accepted
* Comments
- users
* Id
* Projects
* Location
* Grade
* TermId
- all
* Email
* FirstName
* LastName
* UserId
* ModId
* TermId
一旦 mods
注册了一个活动,他们就可以参加一个活动(如果在特定时间登录,Attended
将被设置为 1)。在那里,他们能够对一定数量的 users
进行评分,比如 maxUsers
。如果他们的评分 (QuestionValues != null && Grade != null
) 小于 maxUsers
,我们说他们有 started 评分,如果他们的评分恰好 maxUsers
我们说他们已经完成评分了。
现在,我希望能够区分以下 mods
的 类:
mods
已注册但未参加(即 Attended
= 0)
mods
参加了 Attended
活动但尚未开始评分(Attended = 1
但 QuestionValues == null && Grade == null
)
mods
已开始评分但未完成(因此,他们的上述两个字段的非空值小于 maxUsers
)
mods
已完成评分的人 (== maxUsers
).
我希望能够得到一个 SQL 查询,将所有这些信息放在一个地方。
首先,UNION 运算符是否适合此任务?如果没有,我该如何解决这个问题?
其次,如果上一个问题的答案是是,这是我目前所获得的 mods
成功 graded
].这是正确的方法吗?
SELECT m.Id, m.Title, m.Attended, a.FirstName, a.LastName, a.Email, a.TermId
FROM all a
INNER JOIN mods m ON m.Id = a.ModId
WHERE m.Id = a.ModId
AND Attended = 1
AND (SELECT COUNT(*) FROM modusergrade mug
WHERE m.Id = mug.ModId
AND QuestionValues IS NOT NULL
AND Grade IS NOT NULL
AND Accepted = 1) > 5
UNION
SELECT m.Id, m.Title, 'Graded' AS Attended, a.FirstName, a.LastName, a.Email, a.TermId
FROM all a
INNER JOIN mods m ON m.Id = a.ModId
WHERE m.Id = a.ModId
AND Attended = 1
编辑:为了让问题更清楚,我的目标是:
Graded
将是 Started Grading
的子集,Started Grading
是 Attended
的子集,Registered
是 Registered
的子集。使用集合表示法:
Graded ⊆ Started Grading ⊆ Attended ⊆ Registered
.
是否可以创建一个 SQL UNION 查询来捕获此行为?我还需要其他东西吗?
"Inner join" 就是您要找的。
基本上,您对每个 table 执行 select 查询,满足您在 table 中寻找的内容。 (即 select 来自 mods 的 id,其中 attended=0)并加入他们以找到匹配的 id。
Here is an answered question with some code for you.
您不需要为此进行 union
查询。您只需要一个 case
语句,它具有您正在寻找的层次逻辑。这需要来自 all
和 mug
表格的信息以及来自 modusergrades
.
的汇总信息
我在表中没有看到最大问题值,所以我假设它是某种参数。
你想要的查询是这样的:
SELECT m.Id, m.Title, m.Attended, a.FirstName, a.LastName, a.Email, a.TermId,
(CASE WHEN m.Attended = 0 THEN 'Registered'
WHEN mug.modid IS NULL THEN 'Attended'
WHEN mug.numgraded < $maxcnt THEN 'Started'
WHEN mug.numgraded = $maxcnt THEN 'Finished'
END) as status
FROM all a INNER JOIN
mods m
ON m.Id = a.ModId LEFT JOIN
(SELECT modid, COUNT(*) as numgraded
FROM modusergrades mug
WHERE QuestionValues is not null AND Grade is not null
GROUP BY modid
) mug
ON mug.modid = m.id
我有以下架构(与问题相关的部分):
# schema
- table
* table field
# schema
- mods
* Id
* Title
* Affiliation
* Attended
- modusergrades
* ModId
* UserId
* QuestionValues
* Grade
* Accepted
* Comments
- users
* Id
* Projects
* Location
* Grade
* TermId
- all
* Email
* FirstName
* LastName
* UserId
* ModId
* TermId
一旦 mods
注册了一个活动,他们就可以参加一个活动(如果在特定时间登录,Attended
将被设置为 1)。在那里,他们能够对一定数量的 users
进行评分,比如 maxUsers
。如果他们的评分 (QuestionValues != null && Grade != null
) 小于 maxUsers
,我们说他们有 started 评分,如果他们的评分恰好 maxUsers
我们说他们已经完成评分了。
现在,我希望能够区分以下 mods
的 类:
mods
已注册但未参加(即Attended
= 0)mods
参加了Attended
活动但尚未开始评分(Attended = 1
但QuestionValues == null && Grade == null
)mods
已开始评分但未完成(因此,他们的上述两个字段的非空值小于maxUsers
)mods
已完成评分的人 (==maxUsers
).
我希望能够得到一个 SQL 查询,将所有这些信息放在一个地方。
首先,UNION 运算符是否适合此任务?如果没有,我该如何解决这个问题?
其次,如果上一个问题的答案是是,这是我目前所获得的 mods
成功 graded
].这是正确的方法吗?
SELECT m.Id, m.Title, m.Attended, a.FirstName, a.LastName, a.Email, a.TermId
FROM all a
INNER JOIN mods m ON m.Id = a.ModId
WHERE m.Id = a.ModId
AND Attended = 1
AND (SELECT COUNT(*) FROM modusergrade mug
WHERE m.Id = mug.ModId
AND QuestionValues IS NOT NULL
AND Grade IS NOT NULL
AND Accepted = 1) > 5
UNION
SELECT m.Id, m.Title, 'Graded' AS Attended, a.FirstName, a.LastName, a.Email, a.TermId
FROM all a
INNER JOIN mods m ON m.Id = a.ModId
WHERE m.Id = a.ModId
AND Attended = 1
编辑:为了让问题更清楚,我的目标是:
Graded
将是 Started Grading
的子集,Started Grading
是 Attended
的子集,Registered
是 Registered
的子集。使用集合表示法:
Graded ⊆ Started Grading ⊆ Attended ⊆ Registered
.
是否可以创建一个 SQL UNION 查询来捕获此行为?我还需要其他东西吗?
"Inner join" 就是您要找的。
基本上,您对每个 table 执行 select 查询,满足您在 table 中寻找的内容。 (即 select 来自 mods 的 id,其中 attended=0)并加入他们以找到匹配的 id。
Here is an answered question with some code for you.
您不需要为此进行 union
查询。您只需要一个 case
语句,它具有您正在寻找的层次逻辑。这需要来自 all
和 mug
表格的信息以及来自 modusergrades
.
我在表中没有看到最大问题值,所以我假设它是某种参数。
你想要的查询是这样的:
SELECT m.Id, m.Title, m.Attended, a.FirstName, a.LastName, a.Email, a.TermId,
(CASE WHEN m.Attended = 0 THEN 'Registered'
WHEN mug.modid IS NULL THEN 'Attended'
WHEN mug.numgraded < $maxcnt THEN 'Started'
WHEN mug.numgraded = $maxcnt THEN 'Finished'
END) as status
FROM all a INNER JOIN
mods m
ON m.Id = a.ModId LEFT JOIN
(SELECT modid, COUNT(*) as numgraded
FROM modusergrades mug
WHERE QuestionValues is not null AND Grade is not null
GROUP BY modid
) mug
ON mug.modid = m.id