2016-03-18 2 views
0

У меня есть таблица, напоминающая следующая структура:Как обновить поля на основе значения другой записи

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, однако он не обрабатывает мои особые условия. Как я могу изменить его, чтобы удовлетворить мои критерии?

EDIT:

Я попробовал предложенный ответ ниже, на основании этого заявления:

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 не по назначению (например, идентификационный номер 5 и 6), начиная с берлинских записей. Это показано ниже:

enter image description here

Вот создания и вставки заявления, чтобы иметь возможность повторить:

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'); 
+0

Я предлагаю вам ** не ** магазин это ***» за одну секунду до даты начала следующей записи "***, но фактическая дата начала следующей записи **. Гораздо проще делать обновления, запросы, которые вам придется писать, будут одинаковыми с точки зрения сложности и наиболее важными: менее подвержены ошибкам. Дополнительное преимущество, вы можете добавить ограничения внешнего ключа, если вы хотите повысить согласованность на уровне базы данных. –

ответ

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; 
+0

Спасибо за помощь. Я пробовал это, однако результаты не так, как предполагалось. Я редактировал вопрос, чтобы показать, что я имею в виду. –

+0

Я добавил некоторый SQL, чтобы вы могли быстро реплицировать схему на вашем конце. –

+0

Это помогло мне на правильном пути - спасибо и +1. –

Смежные вопросы