'Delete' 用户但保留记录(外键)

'Delete' user but keep records (foreign keys)

我有一个 table users 和用户帐户(user_id、用户名...)。 user_id 与其他多个 table 相关 - 例如a table 包括他最近的操作、个人资料详细信息、他的产品、他的兴趣等

有时候一个用户要删除,然后我设置一个字段'deleted'为1,大部分table中的记录应该删除,但是2[=]中的记录47=]s(reportsmessages)应该保留对用户的引用。原因:比如消息伙伴还想看他最近通话的账号的用户名。最好的方法是什么?

1) 在 PHP 中存储记录的 id 在 reportsmessages 中应该保存在一个数组中。然后删除用户。与 users 相关的所有 table 都会自动删除他们的记录,并引用已删除的帐户。 reportsmessages 中的引用应该是: ON UPDATE SET NULL 所以他们的记录在用户删除后仍然存在。现在数据库是干净的,然后重新插入具有相同user_id的用户,字段'deleted'为1。然后将数组中的数据更新为user_id,这样引用就设置好了再次.

2) 删除 reportsmessages 中对用户的引用(因此没有外键)。

3) ...(有更好的选择吗?)

谢谢!

reportsmessages table 上使用外键约束的原因是为了强制参照完整性;通常这是一件好事,但在这种情况下,这是问题的根源,因为您实际上想要违反参照完整性,以便在删除 users 记录后维护审计线索。我建议您删除 reportsmessages table 中 user_id 列的外键约束。这将允许您在不影响报告或消息 table 中的数据的情况下删除用户。不幸的是,如果没有相应的用户名,user_id 是没有用的,因此与其存储 user_id,不如将用户名直接存储在报告和消息 table 中。在这种情况下,我建议您按如下方式更改数据库模式(这是伪代码,可能需要针对 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 列不是 users table 上的外键。

出于性能原因,您可能还想将索引添加到这些 table 中的 username 列,如果您要 运行 select 包含 username 在 where 子句中。

顺便说一下,根据我的经验,从用户 table 中完全删除 id 列并使用户名成为 users table,假设 username 值都是唯一的。

1) 我 从不 考虑删除用户记录并留下其他 table 包含用户数据的其他 user_id 在用户中不存在table。正如您所提到的,您必须保留用户帐户的原因有很多。

  And you only need 1 simple UPDATE status query.

(所以我会保留外键并且在这个 table 上不会有 DELETE 情况)。

2) 在某些情况下,您必须从数据库中删除此数据(例如法律问题、数百万被删除的用户)。另一种方法是 创建一个 deleted_users table,使用 user_id 和用户名,并创建一个函数来检查用户是否被删除。

但我认为,这种方法在生产级别的环境中容易出错,我根本不推荐它。在这种情况下 外键 不保留

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

综上所述:选项1(状态:已删除)是最佳选择。这样你也可以在用户改变主意时恢复数据。

PS:如果您处于开发阶段,并且想从很多 table 中删除一些用户,您可以创建一个删除功能,然后带有 table 的循环。像这样:

$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');
}   

但是,在这种情况下,我不会仅仅为了开发级别的可用性而创建外键。

如果您希望所有操作都从数据库级别进行处理,那么您可以使用触发器来完成这项工作。 即使删除了用户,也要保留 reportsmessages 数据中的数据 = 1 表示这些数据 将在那里供其他参考,当您添加具有相同 user id 的新用户详细信息时,一切都会 被重置。这个过程看起来更像是一个 CRM 应用程序,其中的数据甚至用户都不会被删除,只是将其设置为 deleted=1 当为该已删除记录引入新用户时,其他关联数据会自动分配给该用户。

但是在您的情况下,您仍然想要删除一些数据。所以使用下面的触发器就可以完成。 请注意,您不是在删除用户,而是在更新用户。

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 ;

我给出了两个选项,第一个是停止从 reportsmessage table 中删除的行,但我认为这不会解决您的问题,因为如果从中删除行用户 table 您无法获取他的姓名电子邮件或其他任何信息。

解决方案 1 请删除对 reportsmessages table 的约束,方法是从用户中删除引用的用户 table 不会对这些执行任何操作 table

解决方案 2 在用户 table 中创建状态列,因此不要删除该行,而是将其设置为 false,此 false 意味着该用户可以进一步执行 activity。

是的,有更好的选择。

如果您出于任何原因需要该用户,请不要删除它,这是基本规则。执行 deleted=1 更新并删除表中需要删除的所有数据。保持您现在拥有的引用完整性,如果您尝试删除的内容超出您的预期,这将提醒您。从 table_name where id_user = XXX 中删除一些,现在和将来都会为您省去很多麻烦。您拥有这些外键是有原因的。相信我。

当然,您需要制定备份策略,以防万一您对 "wont need it anymore" 句子有误。