在连接表上的删除时设置为null

时间:2014-02-21 01:03:42

标签: mysql sql foreign-key-relationship

我有一个用户表

CREATE TABLE User (
    UserID int AUTO_INCREMENT NOT NULL,
    UserName varchar(50) NOT NULL,
    UNIQUE INDEX UNIQ_USERNAME (UserName),
    PRIMARY KEY(UserID)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;

和内容表

CREATE TABLE Content (
    ContentID int NOT NULL AUTO_INCREMENT,
    ContentCreated datetime NOT NULL,
    PRIMARY KEY(ContentID)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;

用户和内容之间存在多对多的关系。用户可以创建多个Content对象,并且可以由多个用户创建Content对象。

当删除Content对象时,User对象不再需要对它的引用,但是当删除User时,我希望Content对象仍然记录用户(或多个用户)在某个时刻处理它。

我尝试使用一些外键进行连接表

CREATE TABLE CONTENT_AUTHOR (
    UserID int,
    ContentID int NOT NULL,
    PRIMARY KEY(UserID, ContentID)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;

ALTER TABLE CONTENT_AUTHOR ADD CONSTRAINT FK_User_To_CONTENT_AUTHOR FOREIGN KEY (UserID) REFERENCES User (UserID) ON DELETE SET NULL;
ALTER TABLE CONTENT_AUTHOR ADD CONSTRAINT FK_Content_To_CONTENT_AUTHOR FOREIGN KEY (ContentID) REFERENCES Content (ContentID) ON DELETE CASCADE;

但这不起作用,因为主键不能设置为null。我怎样才能代表这种关系呢?

2 个答案:

答案 0 :(得分:0)

当我解决这种关系时,我创建了一个具有自己id的关系表(我认为很多框架都提出了同样的建议)。

CREATE TABLE CONTENT_AUTHOR (
    id int NOT NULL AUTO_INCREMENET,
    UserID int,
    ContentID int NOT NULL,
    deleted tinyint NOT NULL DEFAULT 0,
    PRIMARY KEY(ID)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;

如果您想在某处使用内容历史记录,我建议您在实际上不删除记录但将记录状态设置为“已删除”时。(不要进行物理删除而是删除逻辑。)

CREATE TABLE User (
    UserID int AUTO_INCREMENT NOT NULL,
    UserName varchar(50) NOT NULL,
    deleted tinyint NOT NULL DEFAULT 0,
    UNIQUE INDEX UNIQ_USERNAME (UserName),
    PRIMARY KEY(UserID)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;

答案 1 :(得分:0)

您可以继续将FK_User_To_CONTENT_AUTHOR设置为ON DELETE CASCADE,然后将CONTENT_AUTHOR和User表连接到Content表吗?由于您拥有内容记录,您仍然会知道用户正在处理它:

select
  ifnull(u.UserID,0) UserID,
  ifnull(u.UserName,'Expired User') UserName,
  c.ContentCreated
from Content c
  left join CONTENT_AUTHOR ca
    on ca.ContentID = c.ContentID
  left join User u
    on u.UserID = ca.UserID

如果与内容相关的用户记录数量很大,我建议创建某种过期用户记录,并将其作为用户删除过程的一部分插入CONTENT_AUTHOR表中:

insert into CONTENT_AUTHOR(UserID,ContentID)
  select u.UserID,c.ContentID
  from User u
    inner join CONTENT_AUTHOR c
      on c.UserID = 2
  where u.UserName = 'Expired User';

delete from User where UserID = 2;

如果我们可以在FK_User_To_CONTENT_AUTHOR键上设置DEFAULT会很棒,但我认为我们不能。