Как в PostgreSQL одновременно удалить строки и получить их прежние значения?
В PostgreSQL для этого используется предложение RETURNING у оператора DELETE. Оно возвращает по одной результирующей строке для каждой фактически удалённой строки, поэтому отдельный предварительный SELECT не нужен.
Обычная последовательность «сначала выбрать строки, затем удалить их» создаёт промежуток между двумя операторами. За это время другой сеанс может изменить данные, а приложение может получить неполный результат или удалить не совсем те строки, которые были выбраны.
RETURNING решает задачу получения затронутых строк в рамках одного DML-оператора. Это удобно для журналирования, передачи идентификаторов удалённых объектов и синхронизации с прикладным кодом.
После удаления приложению часто нужны идентификаторы, владельцы или другие значения удалённых строк. Предварительный SELECT усложняет код и может привести к рассогласованию между прочитанными и фактически удалёнными данными.
Нужно учитывать, что возвращаются только строки, действительно затронутые оператором. Если условие не совпало ни с одной строкой, результат будет пустым.
RETURNING вычисляется для строк, обработанных DELETE, и позволяет указать как отдельные столбцы, так и выражения над их значениями.
Если строка с таким идентификатором существует и удаление разрешено, запрос вернёт её значения. Если строка отсутствует или удаление ограничено условием, соответствующей строки в результате не будет.
Это не отдельный SELECT и не предварительная проверка: удаление и получение результата выполняются одним оператором. Поэтому приложение может использовать возвращённые данные, например, для записи события аудита.
Поведение ограничений и триггеров зависит от их определения. В частности, внешний ключ может запретить удаление или вызвать каскадное удаление, а триггеры могут изменить итоговое поведение операции. RETURNING также не делает операцию автоматически независимой от транзакции: фиксация результата для других сеансов определяется COMMIT.
Предложение RETURNING не является одинаково доступным во всех СУБД. В PostgreSQL это штатный механизм; в других системах могут применяться аналоги, например OUTPUT в Microsoft SQL Server, либо отдельные запросы.
Сервис удаляет пользовательскую сессию и должен сразу отправить в журнал её идентификатор и владельца. Вариант с предварительным SELECT требует двух операторов и аккуратной обработки конкурирующих изменений. Вариант с удалением, за которым следует SELECT, уже не сможет надёжно прочитать удалённую строку.
Использование DELETE с RETURNING выполняет обе задачи атомарно: строка удаляется, а её данные возвращаются приложению из результата того же оператора. Это уменьшает число обращений к базе данных и исключает рассогласование между выборкой и удалением. Если аудит должен быть гарантированным, его обычно выполняют в той же транзакции или передают данные в надёжный механизм журналирования.
Он вернёт пустой результирующий набор, а не NULL и не специальную строку. Приложение должно отдельно учитывать количество возвращённых строк, особенно если ожидалось удаление ровно одной записи.
Нет. Предложение возвращает результат выполненной операции, но видимость изменений для других транзакций определяется уровнем изоляции и фиксацией транзакции. До COMMIT удаление может быть невидимым другим сеансам, а при ROLLBACK оно будет отменено.
Не полностью. Он передаёт удалённые значения вызывающему коду, но сам по себе не сохраняет их в журнале и не гарантирует доставку события во внешнюю систему. Для надёжного аудита нужны запись в таблицу в той же транзакции, триггер или другой специально выбранный механизм.