2016-09-13 5 views
0

Вот пример моего results MySQL таблицы:MySQL: переложить все даты вперед, максимальная дата = Теперь

enter image description here

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

/* result is 823 */ 
SELECT DATEDIFF(
    CURDATE(), 
    (SELECT MAX(r.`LastReviewed`) 
    FROM `results` r 
    WHERE r.`UserID` = 1) 
) 

Но я не знаю, как использовать эту информацию в большем запросе, который бы сдвинуть даты вперед. Я пробовал:

UPDATE `results` r 
SET r.`LastReviewed` = 
     r.`LastReviewed` + 
     INTERVAL (
      SELECT DATEDIFF(
       CURDATE(), 
       (SELECT MAX(r.`LastReviewed`) 
       FROM `results` r 
       WHERE r.`UserID` = 1) 
      ) 
     ) DAY 
WHERE r.`UserID` = 1 

Но это ошибки с:

Код ошибки 1093: Вы не можете указать целевую таблицу 'R' для обновления в предложении FROM

2 проблемы что даже если он сработает, он рискует перенести максимальную запись в будущее, если это произойдет ближе к концу дня (23:59). Я хотел бы новый максимум, чтобы быть текущим DATETIME

SQL Fiddle

+0

вы не можете сделать это один запрос. вам нужен подзапрос, чтобы получить максимальное значение, но это означает, что вы читаете из таблицы, которую вы пытаетесь обновить. сделайте это пополам: выберите max, а затем используйте это для отдельного обновления. –

+0

@MarcB Привет, Марк. У меня проблемы с логикой этого. Подзапрос не зависит от суперзапроса, так почему это имеет значение? Не первый и второй подзапрос? – BeetleJuice

+0

да, есть. у вас есть «результаты обновления ... (выберите ... из результатов)». поэтому вы выбираете из таблицы, на которую настроен таргетинг для обновления. mysql просто не позволяет этого. единственным допустимым обходным путем является использование 'join' вместо подзапроса. но поскольку вам нужно выполнять совокупные функции, это не будет работать слишком хорошо. –

ответ

2

Вы можете сделать это с двумя последовательными операторами.

SELECT @offset := DATEDIFF(
    CURDATE(), 
    (SELECT MAX(LastReviewed) 
    FROM results 
    WHERE UserID = 1) 
); 
UPDATE results 
    SET LastReviewed = LastReviewed + INTERVAL @offset DAY 
WHERE UserID = 1; 

Редактировать О, вы должны сделать это для всех, а? Давайте используем временную таблицу. (Эти парни исчезают, когда вы закончите с ними.)

CREATE TEMPORARY TABLE offsets 
SELECT DATEDIFF(CURDATE(),MAX(LastReviewed)) offset, 
     UserId 
    FROM results 
    GROUP BY UserId; 

UPDATE results 
    JOIN offsets ON results.UserId = offsets.UserId 
    SET results.LastReviewed = results.LastReviewed + INTERVAL offsets.offset DAY; 

Таблица temp содержит одну строку для каждого пользователя. Он преодолевает ограничение, в котором вы не можете сделать сводный запрос (MAX() в вашем случае) в инструкции обновления, которая обновляет таблицу.

+0

Спасибо Ollie. Во втором запросе будет ли база данных знать, к какой таблице относится 'r'? – BeetleJuice

+0

Ой, опечатка. Для второго запроса требуется имя таблицы. –

+0

+1 Я делаю почти то же самое при создании тестовых данных в наших песочницах наших разработчиков. Это должно быть сделано в два этапа. –