如何根据其他记录的值更新字段
Posted
技术标签:
【中文标题】如何根据其他记录的值更新字段【英文标题】:How to update fields based on value of other record 【发布时间】:2016-03-18 10:28:27 【问题描述】:我有一个类似于以下结构的表:
City start_date end_date
Paris 1995-01-01 00:00:00 1997-10-01 23:59:59
Paris 1997-10-02 00:00:00 0001-01-01 00:00:00
Paris 2013-01-25 00:00:00 0001-01-01 00:00:00
Paris 2015-04-25 00:00:00 0001-01-01 00:00:00
Berlin 2014-11-01 00:00:00 0001-01-01 00:00:00
Berlin 2014-06-01 00:00:00 0001-01-01 00:00:00
Berlin 2015-09-11 00:00:00 0001-01-01 00:00:00
Berlin 2015-10-01 00:00:00 0001-01-01 00:00:00
Milan 2001-01-01 00:00:00 0001-01-01 00:00:00
Milan 2005-10-02 00:00:00 2006-10-02 23:59:59
Milan 2006-10-03 00:00:00 2015-04-24 23:59:59
Milan 2015-04-25 00:00:00 0001-01-01 00:00:00
数据包含基于城市的开始和结束日期的历史视图。一个城市的最新记录应该是开始日期最长的记录,结束日期为“0001-01-01 00:00:00”,表示还没有结束日期。
我需要清理这些数据并确保每个城市的历史记录都有结束日期比下一条记录的开始日期早一秒,仅在 end_date 设置为 '0001- 的情况下01-01 00:00:00'。因此,如果 end_date 具有实际日期,则将被忽略。另外,城市的start_date最近的记录也不需要修改end_date。
结果表应如下所示:
City start_date end_date
Paris 1995-01-01 00:00:00 1997-10-01 23:59:59
Paris 1997-10-02 00:00:00 2013-01-24 23:59:59
Paris 2013-01-25 00:00:00 2015-04-24 23:59:59
Paris 2015-04-25 00:00:00 0001-01-01 00:00:00
Berlin 2014-11-01 00:00:00 2014-05-31 23:59:59
Berlin 2014-06-01 00:00:00 2015-09-10 23:59:59
Berlin 2015-09-11 00:00:00 2015-09-30 23:59:59
Berlin 2015-10-01 00:00:00 0001-01-01 23:59:59
Milan 2001-01-01 00:00:00 2005-10-01 23:59:59
Milan 2005-10-02 00:00:00 2006-10-02 23:59:59
Milan 2006-10-03 00:00:00 2015-04-24 23:59:59
Milan 2015-04-25 00:00:00 0001-01-01 00:00:00
我想了很多以编程方式实现这一点的方法,但是我希望有一个解决方案可以完全通过 SQL 查询来处理这个问题。我发现了一个类似的问题,答案是here,但是它不能处理我的特定情况。如何修改它以满足我的标准?
编辑:
我已根据以下声明尝试了以下建议的答案:
update test join
(select t.*,
(select min(start_date)
from test t2
where t2.city = t.city and
t2.start_date > t.start_date
order by t2.start_date
limit 1
) as next_start_date
from test t
) tt
on tt.city = test.city and tt.start_date = test.start_date
set test.end_date = date_sub(tt.next_start_date, interval 1 second)
where test.end_date = '0001-01-01' and
next_start_date is not null;
不幸的是,从柏林记录开始,一些 end_dates 与预期不符(例如 id 编号 5 和 6)。如下所示:
以下是可以复制的创建和插入语句:
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`city` varchar(50) DEFAULT NULL,
`start_date` datetime DEFAULT NULL,
`end_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','1995-01-01 00:00:00','1997-10-01 23:59:59');
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','1997-10-02 00:00:00','0001-01-01 00:00:00');
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','2013-01-25 00:00:00','0001-01-01 00:00:00');
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','2015-04-25 00:00:00','0001-01-01 00:00:00');
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2014-11-01 00:00:00','0001-01-01 00:00:00');
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2014-06-01 00:00:00','0001-01-01 00:00:00');
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2015-09-11 00:00:00','0001-01-01 00:00:00');
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2015-10-01 00:00:00','0001-01-01 00:00:00');
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2001-01-01 00:00:00','0001-01-01 00:00:00');
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2005-10-02 00:00:00','2006-10-02 23:59:59');
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2006-10-03 00:00:00','2015-04-24 23:59:59');
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2015-04-25 00:00:00','0001-01-01 00:00:00');
【问题讨论】:
我建议你不要存储这个“在下一条记录的开始日期前一秒”但是实际的下一条记录的开始日期。进行更新要容易得多,您必须编写的查询将具有相同的难度,最重要的是:不易出错。额外的好处是,如果您想增强数据库级别的一致性,可以添加外键约束。 【参考方案1】:你只需要lead()
函数,这在 mysql 中是不可用的。在update
中使用变量是有挑战性的,所以这里有一个带有相关子查询的方法。
获取下一个开始日期:
select t.*,
(select min(start_date)
from t t2
where t2.city = t.city and
t2.start_date > t.start_date
order by t2.start_date
limit 1
) as next_start_date
from t;
您现在可以在 update
中使用它,使用 join
:
update t join
(select t.*,
(select min(start_date)
from t t2
where t2.city = t.city and
t2.start_date > t.start_date
order by t2.start_date
limit 1
) as next_start_date
from t
) tt
on tt.city = t.city and tt.start_date = t.start_date
set t.end_date = date_sub(tt.next_start_date, interval 1 second)
where t.end_date = '0001-01-01' and
t.next_start_date is not null;
【讨论】:
感谢您的帮助。我已经尝试过了,但是结果并不像预期的那样。我已经编辑了问题以说明我的意思。 我添加了一些 SQL,以便您也能够快速复制您的架构。 这帮助我走上了正轨 - 感谢和 +1。以上是关于如何根据其他记录的值更新字段的主要内容,如果未能解决你的问题,请参考以下文章
如何根据每条记录的连续表单中 ms-access 中的其他值填充文本框上的值
jQuery X-Editable:根据其他选择字段的值更新选择字段