我有一个mySQL表,它包含我的项目配置,每个配置更改都会创建一个新条目,这样我就可以记录所有更改,以及更改了哪些更改。
CREATE TABLE `configurations` (
`name` varchar(255) NOT NULL,
`value` text NOT NULL,
`lastChange` datetime NOT NULL,
`changedBy` bigint(32) NOT NULL,
KEY `lastChange` (`lastChange`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `configurations` (`name`, `value`, `lastChange`, `changedBy`) VALUES
('activePageLimit', 'activePageLimit-old-value', '2016-01-06 12:25:05', 1096775260340178),
('activePageLimit', 'activePageLimit-new-value', '2016-01-06 12:27:57', 1096775260340178),
('customerLogo', 'customerLogo-old-value', '2016-02-06 00:00:00', 1096775260340178),
('customerLogo', 'customerLogo-new-value', '2016-01-07 00:00:00', 1096775260340178);
现在我的select查询有问题,应该返回所有名称及其最新值(按lastChange
排序)。
| name | value | lastChange |
|-----------------|---------------------------|---------------------------|
| customerLogo | customerLogo-new-value | January, 07 2016 00:00:00 |
| activePageLimit | activePageLimit-new-value | January, 06 2016 12:27:57 |
我目前的查询是:
SELECT `name`, `value`, `lastChange`
FROM (
SELECT `name`, `value`, `lastChange`
FROM `configurations`
ORDER BY `lastChange` ASC
) AS `c`
GROUP BY `name` DESC
但不幸的是,这并不总是返回正确的值,我不喜欢使用子查询,必须有一个更清洁,更快的方法来做到这一点。
我还为你创建了一个SQL-Fiddle:http://sqlfiddle.com/#!9/f1dc9/1/0
我错过了其他任何聪明的解决方案吗?
答案 0 :(得分:1)
记录您的方法以返回不确定的结果(因为select
中的列不在group by
中)。
以下是三种选择。第一种是标准SQL,使用显式聚合来获取最新的更改。
SELECT c.*
FROM configurations c JOIN
(SELECT `name`, MAX(`lastChange`) as maxlc
FROM `configurations`
GROUP BY name
) mc
ON c.name = mc.name and c.lasthange = mc.maxlc ;
第二个也是标准SQL,使用not exists
:
select c.*
from configurations c
where not exists (select 1
from configurations c2
where c2.name = c.name and c2.lastchange > c.lastchange
);
第三个使用MySQL中可用的hack(它假定该版本中没有任何逗号,并且不会太长):
select name, max(lastchange),
substring_index(group_concat(value order by lastchange desc), ',', 1) as value
from configurations
order by name;
请谨慎使用此版本,因为它容易出错(例如,中间group_concat()
结果可能超过MySQL参数,然后必须重新设置)。
还有其他方法 - 例如使用变量。但这三个应该足以让你考虑你的选择。
答案 1 :(得分:0)
如果我们想避免SUBQUERY,唯一的另一个选择是JOIN
SELECT cc.name, cc.value, cc.lastChange FROM configurations cc
JOIN (
SELECT name, value, lastChange
FROM configurations
ORDER BY lastChange ASC
) c on c.value = cc.value
GROUP BY cc.name DESC
答案 2 :(得分:0)
您有两个要求:历史记录和“状态”。将它们保存在两个不同的表中,尽管提供了冗余信息。
也就是说,有一张表忠实地记录了谁在什么时候改变了什么。
有另一个表忠实地指定配置的当前状态。
计划A:INSERT
进入Log
和UPDATE
状态。
B计划:UPDATE
State
并使用TRIGGER
写信给Log
。