"Удалить" пользователя, но сохранить записи (внешние ключи)

у меня есть таблица users с учетными записями пользователей (user_id, username,...). User_id связан с несколькими другими таблицами-например, таблицей с его последними действиями, деталями профиля, его продуктами, его интересами и т. д.

иногда пользователь хочет быть удаленным, а затем я устанавливаю поле "удалено" в 1. Записи в большинстве таблиц должны быть удалены, но записи в 2 таблицы (reports и messages) следует сохранить ссылку на пользователя. Причина: например, партнер сообщения все еще хочет увидеть имя пользователя учетной записи, с которой он недавно разговаривал. Как лучше всего это сделать?

1) в PHP храните идентификаторы записей в reports и messages это должно храниться в массиве. Затем удалите пользователя. Автоматически все таблицы, связанные с users удалить свои записи со ссылкой на удаленный аккаунт. Ссылка в reports и messages должно быть: ON UPDATE SET NULL таким образом, их записи все еще существуют после удаления пользователя. База данных очистите сейчас, затем повторно вставьте пользователя с тем же user_id с полем "удалено" в 1. Затем обновите данные в массиве до user_id, чтобы ссылка была установлена снова.

2) удалить ссылки на пользователя в reports и messages (таким образом, нет внешних ключей).

3) ... (есть ли лучший вариант?)

спасибо!

5 ответов


1) я бы никогда подумайте, чтобы удалить запись пользователя и оставить другие таблицы, содержащие пользовательские данные без существующего user_id в пользовательской таблице. Как вы упомянули, есть много причин, по которым вы должны сохранить учетную запись пользователя.

  And you only need 1 simple UPDATE status query.

(поэтому я бы сохранил внешний ключ, и в этой таблице не было бы случая удаления).

2) в некоторых случаях вам придется удалить эти данные из вашей базы данных (например, юридические вопросы, миллионы удаленный пользователь.) Альтернативой этому было бы создать таблицу deleted_users, С user_id и username и создайте функцию, чтобы проверить, удален ли пользователь.

но я думаю, что этот метод в среде производственного уровня будет подвержен ошибкам, и я бы не рекомендовал его вообще. В этом случае внешний ключ не держал

You need 2 queries (INSERT, DELETE) and 1 query (SELECT) every time you have to check whether a user is deleted.

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

PS: Если вы находитесь в стадии разработки, и вы хотите удалить некоторых пользователей из многих таблиц, вы можете просто создать функцию удаления и цикл с таблицами. Sth как это:

$tables=array('table1','table2','table40');

function delete_user_from_table($table,$user_id){
    //connection db
    //delete query
    $deleteQuery=$db->query("DELETE FROM {$table} WHERE user_id='{$user_id}");
if($deleteQuery){echo $user_id.' deleted from table '.$table;}
    }

//delete loop   
foreach ($tables as $table){
    delete_user_from_table($table,'23');
}   

но в этом случае я бы не создавал внешний ключ только для удобства использования уровня разработки.


причина использования ограничения внешнего ключа для таблиц отчетов и сообщений заключается в обеспечении ссылочной целостности; обычно это хорошо, но в этом случае это источник вашей проблемы, потому что вы действительно хотите нарушить ссылочную целостность, чтобы сохранить след аудита после удаления записи пользователя. Я предлагаю вам удалить ограничение внешнего ключа для столбцов user_id в таблицах отчетов и сообщений. Это позволит вам удалить пользователя, не затрагивая данные в таблицах отчеты или сообщения. К сожалению, user_id не полезен без соответствующего имени пользователя, поэтому вместо хранения user_id вам будет лучше хранить имя пользователя непосредственно в таблицах отчетов и сообщений. В этом случае я предлагаю вам изменить схему базы данных следующим образом (это псевдокод и может потребоваться адаптация для синтаксиса MySQL):

ALTER TABLE reports ADD COLUMN username VARCHAR;
UPDATE reports FROM users SET reports.username = users.username
    WHERE reports.user_id = users.user_id;
ALTER TABLE reports DROP COLUMN user_id;

ALTER TABLE messages ADD COLUMN username VARCHAR;
UPDATE messages FROM users SET messages.username = users.username 
    WHERE messages.user_id = users.user_id;
ALTER TABLE messages DROP COLUMN user_id;

обратите внимание,что новые столбцы username не являются внешними ключами в таблице user.

для причины производительности можно также добавить индексы к столбцам username в этих таблицах, если будут выполняться инструкции select, включающие имя пользователя в предложение where.

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


Да, есть лучший вариант.

Если вам нужен пользователь по какой-либо причине, не удаляйте его, основное правило. Выполните обновление deleted=1 и удалите все данные в таблицах, которые необходимо удалить. Сохраняйте ссылочную целостность в том виде, в каком она у вас есть сейчас, это предупредит вас, если вы попытаетесь удалить больше, чем намеревались. Несколько удалить из table_name, где id_user = XXX избавит вас от многих проблем сейчас и в будущем. У вас есть эти внешние ключи не просто так. Доверие мне.

конечно, вам нужна политика резервного копирования на месте на случай, если вы ошиблись в предложении "больше не нужно".


если вы хотите, чтобы все обрабатывались с уровня базы данных, вы можете использовать триггер для выполнения этой работы. Для хранения данных в reports и messages данные, даже если пользователь удален = 1 означает эти данные будет там для другой ссылки и при добавлении новых сведений о пользователе с тем же user id все будет быть сброшен. Процесс больше похож на CRM-приложение, где данные никогда не удаляются даже пользователями, только его значение deleted=1 Когда новый пользователь вводится для этой удаленной записи, другие данные likned которые автоматически присваиваются пользователю.

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

delimiter //

create trigger user_update after update on user
for each row
begin
  if old.deleted <> new.deleted then 
    if new.deleted = 1 then
      delete from last_actions where user_id = new.user_id ;
      delete from profile_details where user_id = new.user_id ;
      -- all the delete queries where you want to delete
    elseif  new.deleted = 0 then
      delete from reports where user_id = new.user_id ;
      delete from messages where user_id = new.user_id ;
    end if ;
  end if;
end;//

delimiter ;

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

Решение 1 Пожалуйста, удалите ограничение на обоих reports и messages таблица, сделав это, ссылочный пользователь удаляется из таблицы пользователя никакое действие не будет выполняться на этой таблице

решение 2 сделайте столбец status в таблице users, чтобы вместо удаления строки установить его false, и это false означает, что дальнейшее действие может быть выполнено этим пользователем.