【问题标题】:SQL sum with condition field='x'条件字段 ='x' 的 SQL 总和
【发布时间】:2014-11-02 20:16:45
【问题描述】:

我有两张表要注册TESTSGRADES

TEST (id_test, id_person, retry)

GRADE (id_grade, id_test, id_question, grade)

有人可能会进行第二次测试,在这种情况下,重试将是 char 'Y'(表示是) 现在我需要总结按人分组的所有成绩。

问题是,当我按人分组时,总和来自测试重试'N' 和重试'Y'

但是如果一个人有重试,我只想总结这个。

例子

如果TEST (id_test, id_person, retry) 有值

(1,1,'N')
(2,1,'Y')
(3,2,'N')

GRADE (id_grade, id_test, id_question, grade) 有值

(1, 1, 1, 4)
(2, 1, 2, 4)
(3, 1, 3, 4)
(4, 2, 1, 5)
(5, 2, 2, 5)
(6, 2, 3, 5)
(7, 3, 1, 7)
(8, 3, 2, 7)
(9, 3, 3, 7)

我希望人 #1 的总和是 15 (5+5+5) 而不是 27 ( (5+5+5) + (4+4+4) )。而对于没有重试的人#2,总和是 21。我怎样才能得到一个人的名单和它的 sql 等级?

【问题讨论】:

  • 可以放where子句。
  • 如果你有一个重试值来标识所有要求和的测试......或者如果重试列是整数(那么你可以 MAX 它)。但是,您将如何识别要计数的测试?测试只能重试一次吗?如果您有多次重试,重试列中的值是多少?最后一次重试是哪个?
  • 你从哪里得到值 15 和 27?
  • 请添加详细信息。您使用的是什么 RDBMS?可以使用什么逻辑来识别要求和的测试?具有最高 id 或基于重试列的东西。
  • 甲骨文。 sql 应该返回所有人员的列表及其成绩的总和。但是因为它是按人列出的。如果一个人有一个重试,总和应该只得到这一个的成绩。还需要考虑有些人没有进行第二次测试。

标签: sql sum conditional-statements


【解决方案1】:
select id_person,sum(b.grade) from 
    (
        select id_person,max(id_test) testid  from test
        group by id_person

    )a
inner join GRADE as b on a.testid = b.id_test
group by id_person

Working Example

【讨论】:

  • 如果没有怎么办?即测试在第一次尝试时通过并且从未重试
  • hmmmm,希望用户想要你所问的。
  • 是的,一个测试只能重试一次。但是我不能在Where中使用这个子句,因为还有其他人没有重试。
  • 快到了。我更详细地编辑了我的问题。也许如果我在 select 中使用 case 子句会起作用?
  • 您可以获取用户的最新尝试,然后他们会去获取它的总和等级。我已经更新了答案和演示。
【解决方案2】:
select sum(g.grade) 
  from 
      TEST t,GRADE g 
  where 
      t.id_test = g.id_test 
  and 
       t.id_person = 1 ...

【讨论】:

  • 这将使总和为 27 而不是 15,这就是我想要的
【解决方案3】:

问题是你不能真正按人分组。您必须按测试计算总和分组(这很容易),并决定保留哪些测试以及丢弃哪些测试(这是困难的部分,特别是因为您的规格不是很清楚)。

这个查询的依据是:

SELECT t.id_test, t.id_person, t.retry, SUM(g.grade) AS sum_grade
FROM test  t
JOIN grade g ON g.id_test=t.id_test
HAVING <some_filter_condition>

这里的情况很大程度上取决于你没有告诉我们的一些事情。

如果你想要每个人的最后一次测试,那么你可以使用这个:

SELECT t.id_test, t.id_person, t.retry, SUM(g.grade) AS sum_grade
FROM test  t
JOIN grade g ON g.id_test=t.id_test
HAVING t.id_test=(
  SELECT MAX(t2.id_test)
  FROM test t2
  WHERE t2.id_person=t.id_person)

【讨论】:

    【解决方案4】:

    我认为有很多方法可以解决这个问题。我可以为您提供一个想法。
    1. 得到 retry=Y => 结果 A 的人的总和
    2. 获取结果 A 中不存在 id_person 的人的总和
    3. 一起加入
    4. 完成

    【讨论】:

    • 这更像是评论而不是答案;)
    • 有时候,思考过程比完整的源代码更有用。
    • 是的...我同意...所以 cmets 的用途是什么 ;)
    【解决方案5】:
    ;WITH MyCTE AS
    (
       SELECT *,ROW_NUMBER()OVER(PARTITION BY id_person ORDER BY retry DESC) AS rn
       FROM   TEST 
    )
    SELECT SUM(grade) AS Total
    FROM   MyCTE T
           JOIN GRADE G
               ON T.id_test = G.id_test
    WHERE rn = 1
    

    SQL Fiddle

    【讨论】:

      【解决方案6】:

      选择 SUM(grade),id_person,id_question from

      TEST自然加入GRADE

      按 id_test 分组

      其中 id_test=2;

      【讨论】:

        【解决方案7】:

        忽略这些点,我会选择所有重试测试和所有没有重试的测试。

        第一个是直截了当的:

        SELECT id_test FROM test WHERE retry = 'Y';
        

        第二个也没那么复杂:

        SELECT id_test FROM test t1 WHERE retry = 'N' and NOT EXISTS(SELECT * FROM test t2 WHERE t1.id_person=t2.id_person AND t2.retry='Y');
        

        与 UNION 结合,您可以获得所有测试 ID:

        SELECT id_test FROM test WHERE retry = 'Y'
        UNION
        SELECT id_test FROM test t1 WHERE retry = 'N' and NOT EXISTS(SELECT * FROM test t2 WHERE t1.id_person=t2.id_person AND t2.retry='Y')
        

        它为您提供 ids 2 和 3。从那里计算总和可以很简单:

        SELECT id_test, SUM(grade) FROM grade WHERE id_test IN (
            SELECT id_test FROM test WHERE retry = 'Y'
            UNION
            SELECT id_test FROM test t1 WHERE retry = 'N' and NOT EXISTS(SELECT * FROM test t2 WHERE t1.id_person=t2.id_person AND t2.retry='Y')
        ) GROUP BY id_test;
        

        编辑: 为完整起见,查询 id_person, SUM(grade):

        SELECT id_person, SUM(grade) FROM grade g JOIN (
            SELECT id_test, id_person FROM test WHERE retry = 'Y'
            UNION
            SELECT id_test, id_person FROM test t1 WHERE retry = 'N' and NOT EXISTS(
                SELECT * FROM test t2 WHERE t1.id_person=t2.id_person AND t2.retry='Y'
            )
        ) t ON t.id_test = g.id_test
        GROUP BY id_person; 
        

        【讨论】:

        • 顺便说一句,不要忘记索引。猜一猜(重试,id_person)应该会降低查询成本。
        • 感谢您的回答。帮了大忙!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多