Reputation: 9873
I have a table with a bad design:
CREATE TABLE token (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id INT(10) UNSIGNED NOT NULL,
token VARCHAR(191) NOT NULL,
expiration TIMESTAMP NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
);
The reason I see it as bad now even though it worked well before is because now I cannot reuse that token
table if I want a token related to an email or something else. I could just add email_id
column but then I would need ugly logic to determine if the token is meant for a user or an email, respectively.
I want to normalize this design such that I can have a single token
table that isn't coupled to any user_id
or email_id
, and have user_token
and email_token
pivot tables for the relations.
But I am also using migrations so I can't just rewrite my schema. I need to modify this on the fly with data present in the database.
I need to do the following:
user_token
and email_token
tables (COMPLETE)token.id
to user_token.token_id
column, and copy token.user_id
value to user_token.user_id
column. The copying needs to be done in an INSERT
statement since the user_token
table will be brand new with no data (TODO)token.user_id
column (COMPLETE)Step 2 is the part I need help on. Any help would be appreciated to write that query.
This is what the new schema will look like if it helps to create a query for step 2:
CREATE TABLE token (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
token VARCHAR(191) NOT NULL,
expiration TIMESTAMP NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id)
);
CREATE TABLE user_token (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id INT(10) UNSIGNED NOT NULL,
token_id INT(10) UNSIGNED NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE,
FOREIGN KEY (token_id) REFERENCES token (id) ON DELETE CASCADE
);
CREATE TABLE email_token (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
email_id INT(10) UNSIGNED NOT NULL,
token_id INT(10) UNSIGNED NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
FOREIGN KEY (email_id) REFERENCES user (id) ON DELETE CASCADE,
FOREIGN KEY (token_id) REFERENCES token (id) ON DELETE CASCADE
);
Upvotes: 0
Views: 1176
Reputation: 3498
IF you haven't delete token.user_id and token.email_id columns from token table, then you can copy them by using a simple INSERT:
INSERT INTO user_token (user_id, token_id)
SELECT user_id, id
FROM token
INSERT INTO email_token (email_id, token_id)
SELECT email_id, id
FROM token
if you want to copy created_at, updated_at, and deleted_at columns along with them, you could just add them into the query:
INSERT INTO user_token (user_id, token_id, created_at, updated_at, deleted_at)
SELECT user_id, id, created_at, updated_at, deleted_at
FROM token
INSERT INTO email_token (email_id, token_id, created_at, updated_at, deleted_at)
SELECT email_id, id, created_at, updated_at, deleted_at
FROM token
this will copy them into the new tables. Then, you only need to delete user_id and email_id columns from token table by a simple ALTER :
FIRST DELETE FOREIGN KEY:
ALTER TABLE token DROP FOREIGN KEY user_id
THEN DELETE THE COLUMNS:
ALTER TABLE token DROP COLUMN user_id;
ALTER TABLE token DROP COLUMN email_id;
Upvotes: 1