MYSQL根据where子句和Join更新值

时间:2014-08-19 15:20:10

标签: mysql join

我是MYSQL的新手,需要知道如何根据平均数据更新表格,以及另一个表格中的数据。

我有10个学生的成绩列表

user | score | average grade | Band
-----------------------------------
 1   |   4   |      3.5      |
 2   |   2   |      2        |
 4   |   9   |      9        |
 1   |   3   |      3        |
 1   |  3.5  |               |
 2   |   2   |               |

我想更新乐队和A,B或C的音阶以表示他们的平均分数是0-3,3,6或6-10。

Band A = 0-4 
Band B = 4-7
Band C = 7-10

有时注册测试的用户与输入的分数之间存在延迟(如第5行的情况)我希望乐队可见。所以这是最终的目标结果。

 user | score | average grade | Band
 ------------------------------------
  1   |   4   |      3.5      |  A  
  2   |   2   |      2        |
  4   |   9   |      9        |  C
  1   |   3   |      3        |  A
  2   |  NULL |      3.5      |  A
  2   |  NULL |      2        |

另外,如果用户付费,我希望乐队只更新,所以我有一个单独的表格,包含这些数据。

User | Paid
-----------
1    |  1
2    |  0
3    |  0
4    |  1

因此,如果用户尚未付款,则会更新平均成绩,但乐队仍然为空(如果已填充则保持不变)

目前我有一个分数表和一个用户表。用户表是计算平均成绩的视图

我可以想到在没有视图的情况下执行此操作的唯一方法是拥有一个每10分钟运行一次的cron作业,将乐队和平均成绩插入成绩表。

1 个答案:

答案 0 :(得分:0)

首先,绝对没有理由将此平均成绩或乐队存储在此表中。

您可以随时根据需要进行计算,或者如果您需要对其进行缓存,则可以将其存储在每个用户只有一个条目的单独表中。就目前而言,您在许多记录中重复相同的信息。所以实际上你根本不需要更新,只需删除这两列并使用更好的select语句。

为了让事情变得更容易,你可以添加一个乐队表来跟踪乐队。

CREATE TABLE bands (
   band varchar(2),
   maxval int,
   minval int
);

INSERT INTO bands (band,minval,maxval)
VALUES
('A',0,3),
('B',4,6),
('C',7,10);

你应该索引它,但它太小了可能无关紧要。它可以让你在未来修改乐队。当然,您可以不使用该表并使用if语句,但我喜欢这种方式,因为您可以这样做:

SELECT sub.user,sub.average_score,bands.band
FROM (
    SELECT u.user, avg(u.score) as average_score
    FROM user_tests as u
    GROUP BY u.user ) as sub
LEFT JOIN user_paid ON user_paid.user = sub.user
LEFT JOIN bands 
ON  sub.average_score >= bands.minval
AND sub.average_score <= bands.maxval
AND user_paid.paid = 1

Fiddle

每当你需要平均分数和乐队时。

或者,如果要将这些值保存在某处,请将列添加到用户付费表(将其设置为user_info或其他内容)并使用此语句(实际上只是将先前的语句包装在更新中)

UPDATE user_info
INNER JOIN  (
   SELECT sub.user,sub.average_score,bands.band
   FROM (
      SELECT u.user, avg(u.score) as average_score
      FROM user_tests as u
      GROUP BY u.user ) as sub
   LEFT JOIN user_info ON user_info.user = sub.user
   LEFT JOIN bands 
   ON  sub.average_score >= bands.minval
   AND sub.average_score <= bands.maxval
   AND user_info.paid = 1 
) as upselect ON upselect.user = user_info.user
SET user_info.average_score = upselect.average_score,
user_info.band = upselect.band 

Fiddle