【问题标题】:SQL Grouping calculationsSQL 分组计算
【发布时间】:2016-03-08 20:59:57
【问题描述】:

我有这个似乎无法弄清楚的分组问题。任何建议将不胜感激!假设我有一张这样的表:

Name     Passed?     PlanID      Plan
-----------------------------------------
Tom         1          1         Math
Tom         1          1         Reading
Tom         0          2         Math
Tom         0          2         Reading 
Tom         0          3         Math
Tom         0          3         Reading
Bobby       1          1         Math
Bobby       0          1         Reading
Bobby       1          2         Math
Bobby       1          2         Reading
Bobby       0          3         Math
Bobby       0          3         Reading
Linda       0          1         Math
Linda       1          1         Reading
Linda       0          2         Math
Linda       1          2         Reading
Linda       1          3         Math
Linda       1          3         Reading

我想要完成的是这样的:

Name     Passed?     PlanID
---------------------------
Tom         1          1
Bobby       1          2
Linda       1          3

所以基本上,如果第一个 planID 没有通过,请查看第二个。如果那一项还没有通过,请看第三项。我遇到的问题是所有 PlanID 将是 3 或 1,或者 Passed 列中的所有值都是 0。

我试过这样的查询:

CASE
    WHEN MIN(Passed?) = 1
    THEN MIN(PlanID)
    ELSE MAX(PlanID)
    END

我知道 max 和 min 只会产生 3 或 1,但我不知道该怎么做。谢谢!

编辑:抱歉,忘了提及如果一个人通过了 planID,那么其余的 planID 应该读作通过。所以既然鲍比第一次没有通过这两个计划,他必须再次接受。既然他通过了第二次,他就不必参加第三次了。一个人必须通过两个计划才能算作通过,如果这有意义的话。我添加了几行,希望能更好地传达我的想法。我可能也让这对我自己来说有点太混乱了。

【问题讨论】:

  • 一个可以传递多个plan ID吗?
  • 没通过的怎么处理?
  • 为什么不SELECT * FROM Table WHERE Passed = '1'
  • @hashbrown 希望我的编辑增加了清晰度。如果该人之前已通过,则该人应保持已通过。
  • @lrb 如果要创建一个新的 planID,那些从未通过的将延续到下一个 planID。所以如果他们仍然没有通过,他们必须参加下一个概述的课程

标签: sql group-by case


【解决方案1】:

如果我们可能会看到多个同名通行证,而您只想选择第一个通行证,请使用以下查询:

select pass.name, pass.passed, pass.planID
from 
(Select name, passed, planID
from table
where passed = 1) pass, 
(Select name, min(planID) planId
from table
where passed = 1) min
where pass.planID= min.planID and pass.name = min.name

如果只有一张pass,你可以直接选择pass:

select * from table where Passed = 1

【讨论】:

  • 这是帮助我澄清我需要做的事情,谢谢!
【解决方案2】:

如果返回刚刚通过? = 1

select * from table where Passed? = 1

根据需要返回

【讨论】:

  • 虽然它适用于我上面的示例,但它不适用于我的查询。抱歉,我应该在开始时添加更多信息,但是有了 WHERE 子句,我相信它会引入多个 PlanID
【解决方案3】:

您可以使用exists 子查询来检查此Name 是否存在较小的planID

 SELECT *
 FROM YourTable T1
 WHERE Passed = 1 
   AND NOT EXISTS (SELECT 1
                   FROM YourTable T2
                   WHERE T1.Name = T2.Name
                     AND T1.planID > T2.planID
                     AND T2.Passed  = 1 )

【讨论】:

    【解决方案4】:
    select *, count(Passed?) as passedTotal from table where Passed? = 1 and passedTotal=2 group by Name
    

    【讨论】:

      【解决方案5】:

      这个有点棘手,因为给出的信息很少,我考虑并假设了以下边缘情况:

      1. 学生可以不通过跳过计划(不通过计划 7,通过计划 8)
      2. 学生可以跳过计划(参加计划 5 但不能参加计划 4、3、2、1)--> 不连续
      3. 学生可以不通过任何计划(尝试计划 1 次,同时仍然包含在输出中)
      4. 学生可以放置在中间点(从计划 6 开始)
      5. 学生可以向前和向后跳跃

      此外,这是假设最新作品按“自然顺序”排在最后(插入记录时,而不是 PlanID)。

      以下应该适用于所有给定的情况。

      SELECT
          Name,
          Passed=MAX(Passed),
          PlanID=MAX(PlanID)
      FROM
      (
          SELECT
              Flag=DENSE_RANK() OVER(PARTITION BY Name ORDER BY Name,Passed DESC) ,
              Name,
              Passed,
              PlanID  
          FROM
          (
              SELECT
                  Name,   
                  PlanID,
                  Passed
              FROM
                  Table
          )AS X
      )AS Y
      WHERE 
          Flag=1
      GROUP BY 
          Name
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-16
        • 2021-12-18
        相关资源
        最近更新 更多