使用 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 的 类:

我希望能够得到一个 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 GradingAttended 的子集,RegisteredRegistered 的子集。使用集合表示法:

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 语句,它具有您正在寻找的层次逻辑。这需要来自 allmug 表格的信息以及来自 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