显示包含最新编辑版本的所有记录

时间:2013-11-03 16:38:21

标签: mysql sql group-by max

我有一个包含学生姓名的表格,自动增加了NR条记录,但是在记录的每次编辑中,都会创建一个新的,将NR复制到ID字段。 但是当我尝试在MAX(NR)时对ID记录进行分组时,它会向我显示该ID的最大数量,但是当我要求剩余的rocord时,它并没有显示该组的最后一条记录

中的ID
SELECT MAX(`NR`) AS 'mNr',`NR`,`ID`,`Name1`,`Name3`,`Gender`
  FROM `Kids`  GROUP BY `ID`

这会产生如下结果:

mNr NR  ID  Name1   Name3   Gender
252 1   1   Alice   Carper  f
179 2   2   Dorah   Fisher  f
189 3   3   Racheal King    f
173 4   4   Frank   Smith   m
192 5   5   Patrick Fay m
305 6   6   Gloria  Sing    f
299 7   7   Bridget Young   f

但正如您所看到的,查询显示最高编辑NR,但随后继续给出记录其余部分中的最低值,而不是属于该最新NR的记录详细信息... 我究竟做错了什么? 这是样本数据:

NR  ID  Name1   Name3   Gender
1   1   Alice   Achand  f
2   2   Dorah   Achieng f
3   3   Racheal Achieng f
4   4   Francisca   Adikin  f
5   5   Patrick Adilu   m
6   6   Gloria  Ajwang  f
7   7   Bridget Aketch  f
130 5   Patrick Adilu   m
129 4   Francisca   Adikin  f
128 2   Dorah   Achieng f
153 4   Francisca   Adikin  f
173 4   Francisca   Adikin  f
179 2   Dorah   Achieng f
189 3   Racheal Achieng f
192 5   Patrick Adilu   m
252 1   Alice   Wor f
299 7   Bridget Aketch  f
305 6   Gloria  Ajwang  f

2 个答案:

答案 0 :(得分:0)

也许不知道它,你正在使用MySQL的一个神秘功能。 MySQL允许您在聚合查询的select语句中包含不在聚合函数或group by子句中的列。引擎为这些列输入任意值。

正确的方式来做你想要的是一个连接:

SELECT k.*
FROM `Kids` k join
     (select id, max(nr) as maxnr
      from kids
      group by id
     ) m
     on k.id = m.id and nr = maxnr;

以下是文档中的明确说明:

  

MySQL扩展了GROUP BY的使用,以便选择列表可以引用   未在GROUP BY子句中命名的非聚合列。这意味着   前面的查询在MySQL中是合法的。您可以使用此功能   通过避免不必要的列排序来获得更好的性能   分组。但是,这主要适用于每个中的所有值   GROUP BY中未命名的非聚合列对于每个列都是相同的   组。服务器可以自由选择每个组中的任何值,所以   除非它们相同,否则所选择的值是不确定的。   此外,不能从每个组中选择值   受添加ORDER BY子句的影响。对结果集进行排序   选择值后发生,ORDER BY不影响   服务器选择的每个组中的值。

您可以更详细地阅读here

答案 1 :(得分:0)

虽然@Gordon Linoff的答案在技术上是正确的,但在大型数据集上使用sub-queries可能会更耗费资源和时间。

根据具体情况,我通常会将数据分为两个表studentsstudent_details

students的表结构是

CREATE TABLE students (
    student_id  INTEGER       NOT NULL PRIMARY KEY AUTO_INCREMENT
);

此表的想法是为学生创建一个唯一的号码,并存储您可能不想在修订版中保存的任何其他学生数据。

student_details的表结构是:

CREATE TABLE student_details (
    revision_id  INTEGER      NOT NULL PRIMARY KEY AUTO_INCREMENT,
    student_id   INTEGER      NOT NULL,
    first_name   VARCHAR(255) NOT NULL,
    last_name    VARCHAR(255) NOT NULL,
    gender       VARCHAR(1),
    is_history   BOOLEAN      NOT NULL DEFAULT false,
    CONSTRAINT FOREIGN KEY(student_id) REFERENCES students(student_id) ON DELETE RESTRICT
);

此表存储学生的实际数据。更新某个学生的数据后,您只需将is_history列更新为true以获取该学生的记录。然后,在选择学生数据时,您只需使用SELECT student_details.* FROM students LEFT JOIN student_details ON (student_details.student_id = students.student_id AND student_details.is_history = false)。这将始终返回学生详细信息的最新版本。

插入新学生

  1. 插入学生INSERT INTO students(student_id) VALUES('');
  2. 获取持续插入ID SELECT LAST_INSERT_ID();(假设为了此示例,它返回1)
  3. 插入学生详细信息
    INSERT INTO student_details(student_id, first_name, last_name, gender) VALUES('1', 'Alice', 'Carper', 'f')
  4. 更新现有学生(假设student_id = 1)

    1. 将之前的所有student_detail“修订版”设置为“历史记录”:
      UPDATE student_details SET is_history = true WHERE student_details.student_id = 1 AND is_history = false
    2. 添加新版本:
      INSERT INTO student_details(student_id, first_name, last_name, gender) VALUES('1', 'Alice', 'Achand', 'f')
    3. 获取学生及其最新学生资料

      SELECT student_details.* FROM students LEFT JOIN student_details ON (student_details.student_id = students.student_id AND student_details.is_history = false)