0

我有一个包含学生姓名的表格,自动增加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 姓名 1 姓名 3 性别
252 1 1 爱丽丝·卡珀
179 2 2 多拉费舍尔
189 3 3 雷切尔·金
173 4 4 弗兰克·史密斯
192 5 5 帕特里克·费伊
305 6 6 格洛丽亚·辛
299 7 7 布里奇特杨

但是正如您所看到的,查询显示最高的编辑 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
4

2 回答 2

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 不会影响服务器选择每个组中的哪些值。

您可以在此处更详细地阅读。

于 2013-11-03T16:47:37.493 回答
0

尽管@Gordon Linoff 的回答在技术上是正确的,但在大型数据集上使用子查询可能会耗费更多资源和时间。

根据情况,我通常会将数据分成两个表students,并student_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')

更新现有学生(假设 student_id = 1)

  1. 将所有以前的 student_detail "revisions" 设置为 "history":
    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')

获取学生及其最新的学生详细信息

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

于 2013-11-03T18:03:47.110 回答