"Удалить" пользователя, но сохранить записи (внешние ключи)
у меня есть таблица 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 означает, что дальнейшее действие может быть выполнено этим пользователем.