Pregunta

I have a User table

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;

and a Content table

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;

There is a many to many relationship between Users and Content. A User can create multiple Content objects, and a Content object can be created by multiple users.

When a Content object is deleted the User object no longer needs a reference to it, but when a User is deleted I want the Content object to still record that at some point a user (or users) worked on it.

I tried doing a join table with some foreign keys

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;

But that doesn't work because primary keys can't be set null. How can I represent this relationship?

¿Fue útil?

Solución

Can you go ahead and set the FK_User_To_CONTENT_AUTHOR to ON DELETE CASCADE and then just left join the CONTENT_AUTHOR and User tables to the Content table? Since you have the Content record, you will still know that a User worked on it:

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

If the number of User records related to the Content is significant, I suggest creating an Expired User record of some sort and inserting it into the CONTENT_AUTHOR table as part of the User deletion process:

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;

It would be great if we could SET DEFAULT on that FK_User_To_CONTENT_AUTHOR key, but I don't think we can.

Otros consejos

When I solve this kind of relation, I create a relation table with its own id(and I think many frameworks suggest the same thing).

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;

If you want to use the content history somewhere, I suggest that when you don't actually delete the record but set the record status to 'deleted'.(Don't do physical delete but logical delete.)

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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top