具有MAX日期字段的GROUP BY - 不稳定的结果

时间:2014-03-28 19:54:06

标签: mysql sql group-by aggregate-functions

拥有包含表单数据的表格。每行包含section_idfield_id。每个部分有50个不同的字段。当用户更新现有字段时,会插入一个带有更新date_modified的新行。这样可以保存变更的滚动存档。

问题在于,当拉动要在页面上显示的最新字段集时,我的结果会变得不稳定。

我已经将问题缩小到几个字段,并在SQLFiddle上重新创建了有问题的表的一部分。

架构:

CREATE TABLE IF NOT EXISTS `cTable` (
  `section_id` int(5) NOT NULL,
  `field_id` int(5) DEFAULT NULL,
  `content` text,
  `user_id` int(11) NOT NULL,
  `date_modified` datetime NOT NULL,
  KEY `section_id` (`section_id`),
  KEY `field_id` (`field_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

This query显示了field_id 39以前编辑过的所有行。返回了五行:

SELECT cT.* 
FROM cTable cT 
WHERE 
 cT.section_id = 123 AND
 cT.field_id=39;

以下是我要为field_id 39 提取the most recent row的内容。没有返回任何行:

SELECT cT.* 
FROM cTable cT 
INNER JOIN (
  SELECT field_id, MAX(date_modified) AS date_modified
  FROM cTable GROUP BY field_id
) AS max USING (field_id, date_modified)
WHERE 
 cT.section_id = 123 AND
 cT.field_id=39;

Record Count: 0; 

如果我在其他field_id上尝试相同的查询,请说 54 I get the correct result

SELECT cT.* 
FROM cTable cT 
INNER JOIN (
  SELECT field_id, MAX(date_modified) AS date_modified
  FROM cTable GROUP BY field_id
) AS max USING (field_id, date_modified)
WHERE 
 cT.section_id = 123 AND
 cT.field_id=54;

Record Count: 1; 

为什么同一个查询在一个field_id上工作,而另一个不在另一个上?

2 个答案:

答案 0 :(得分:1)

您正在寻找每个field_id的max(date_modified)。但是你应该在section_id为123的情况下查找每个field_id的max(date_modified)。否则你可能会找到一个你以后找不到匹配的日期。

SELECT cT.* 
FROM cTable cT 
INNER JOIN (
  SELECT field_id, MAX(date_modified) AS date_modified
  FROM cTable 
  WHERE section_id = 123 
  GROUP BY field_id
) AS max USING (field_id, date_modified)
WHERE 
 cT.section_id = 123 AND
 cT.field_id=39;

这是SQL小提琴:http://www.sqlfiddle.com/#!2/0cefd8/19

答案 1 :(得分:1)

在您获得最大值的子查询中,您需要GROUP BY section_id,field_id仅使用GROUP BY field_id跳过要应用过滤器的部分ID

SELECT cT.* 
FROM cTable cT 
INNER JOIN (
  SELECT section_id,field_id, MAX(date_modified) AS date_modified
  FROM cTable GROUP BY section_id,field_id
) AS max 
ON(max.field_id =cT.field_id 
   AND max.date_modified=cT.date_modified
 AND max.section_id=cT.section_id
  )
WHERE 
cT.section_id = 123 AND
 cT.field_id=39;

See Fiddle Demo