Как ОБНОВИТЬ только «самую последнюю» запись при объединении нескольких таблиц в MySQL

Этот вопрос задавался на этом сайте несколькими способами, но я не могу понять, как реализовать обновление в этом конкретном случае. Как правило, я пытаюсь обновить самые последние ContactNote для каждого Contact, который принадлежит TeamId и имеет определенные Categories. Это довольно простая установка БД (см. диаграмму ниже).

Я успешно создал «предложение выбора», которое возвращает все записи, которые я хотел бы обновить, но когда я добавляю язык UPDATE, MySQL выдает ошибку: Error Code: 1093. You can't specify target table 'cn1' for update in FROM clause

Любое руководство приветствуется.

Рабочий оператор SELECT

SELECT cn1.* from ContactNote cn1
    INNER JOIN Contact contact on contact.ContactId = cn1.ContactId
    INNER JOIN ContactCategory contactCategory on contactCategory.ContactId = contact.ContactId
    INNER JOIN Category category on category.CategoryId = contactCategory.CategoryId
    INNER JOIN ContactNote contactNote
        ON contactNote.ContactNoteId =
        (SELECT cn2.ContactNoteId
            FROM ContactNote cn2
            WHERE contact.ContactId = cn2.ContactId
            ORDER BY cn2.NoteDateTime DESC
            LIMIT 1
        )
where contact.TeamId = 1
    and contact.SpouseLastName = 'Rhodes'
    and category.`Name` in ('Sphere')
;

Неработающий пункт UPDATE

update ContactNote cn1
    INNER JOIN Contact contact on contact.ContactId = cn1.ContactId
    INNER JOIN ContactCategory contactCategory on contactCategory.ContactId = contact.ContactId
    INNER JOIN Category category on category.CategoryId = contactCategory.CategoryId
    INNER JOIN ContactNote contactNote
        ON contactNote.ContactNoteId =
        (SELECT cn2.ContactNoteId
            FROM ContactNote cn2
            WHERE contact.ContactId = cn2.ContactId
            ORDER BY cn2.NoteDateTime DESC
            LIMIT 1
        )
SET cn1.IsProspecting = b'1' 
where contact.TeamId = 1
    and contact.SpouseLastName = 'Rhodes'
    and category.`Name` in ('Sphere')
;

Как ОБНОВИТЬ только «самую последнюю» запись при объединении нескольких таблиц в MySQL

Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
0
25
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

MySQL обычно не любит, когда вы выбираете из таблицы в подзапросе и пытаетесь ОБНОВИТЬ его в том же операторе.

Обходной путь — присоединиться к таблице вместо выбора в подзапросе. Мы ищем случаи, когда нет соответствующей строки с большей датой:

update ContactNote cn
    INNER JOIN Contact contact on contact.ContactId = cn.ContactId
    INNER JOIN ContactCategory contactCategory on contactCategory.ContactId = contact.ContactId
    INNER JOIN Category category on category.CategoryId = contactCategory.CategoryId
    LEFT OUTER JOIN ContactNote gt
        ON gt.ContactId = cn.ContactId AND gt.NodeDateTime > cn.NodeDateTime
SET cn.IsProspecting = b'1' 
WHERE contact.TeamId = 1
    AND contact.SpouseLastName = 'Rhodes'
    AND category.`Name` IN ('Sphere')
    AND gt.ContactId IS NULL -- meaning there is no note with a greater datetime
;

LEFT OUTER JOIN возвращает NULL для всех столбцов объединенной таблицы, если не найдена соответствующая строка. Если условие пытается найти заметки с большим значением NodeDateTime, но ничего не найдено, то NodeDateTime в строке cn должен быть заметкой с самой большой (самой последней) датой и временем для соответствующего контакта.

У этого есть один недостаток: что, если есть несколько заметок, привязанных к последним? Он обновит все те, для которых нет заметки, с большей датой и временем, что может обновить несколько заметок. Это то, что вы хотите?

Другие вопросы по теме