What is the best way to have a table to maintain related records of another table.
Example:
mytbl
-----
id sku
1 sk1
2 sk2
3 sk3
4 sk4
5 sk5
6 sk6
7 sk7
Lets say records 1, 4 and 3 are 'related'
So I want to maintain a table that tells me that they are.
relatedTbl
----------
sku related_sku
sk1 sk3
sk1 sk4
sk3 sk4
This solution would work but, is there a better solution?
EDIT: I used skus in the relatedTbl but I know I could (better) to use ids. The question is about the structure of the table more than what foreign key to use.
You have the correct solution. As you indicated, use the ID. If sku is unique, consider using it as a natural PK.
CREATE TABLE IF NOT EXISTS `mytbl` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`sku` VARCHAR(45) NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `relatedTbl` (
`mytbl_id` INT UNSIGNED NOT NULL,
`mytbl_id1` INT UNSIGNED NOT NULL,
PRIMARY KEY (`mytbl_id`, `mytbl_id1`),
INDEX `fk_mytbl_has_mytbl_mytbl1_idx` (`mytbl_id1` ASC),
INDEX `fk_mytbl_has_mytbl_mytbl_idx` (`mytbl_id` ASC),
CONSTRAINT `fk_mytbl_has_mytbl_mytbl`
FOREIGN KEY (`mytbl_id`)
REFERENCES `mytbl` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_mytbl_has_mytbl_mytbl1`
FOREIGN KEY (`mytbl_id1`)
REFERENCES `mytbl` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
You may want to consider adding a third field to 'mytbl' in to store a unique key for common records. for instance, field 3 would be named "uniqID", and records 1, 4 and 3 are 'related' the table would then be:
mytbl
id sku uniqID
1 sk1 1
2 sk2
3 sk3 1
4 sk4 1
5 sk5
6 sk6
7 sk7
you can then use a 'WHERE uniqID=1' clause at the end of your select statement to get the common attributes
In my database, I have a table 'karmalog'. It basically is a log of actions in the system. It contains a few 100ks of rows. I'd like to retrieve the newest 36 of log items, but only those log items that match a series of log type (called 'event').
Here's the query:
SELECT id
FROM karmalog
WHERE event
IN (
'FAV_IMG_ADD', 'FOLLOW', 'COM_POST', 'IMG_VOTE', 'LIST_VOTE', 'JOIN', 'CLASS_UP', 'LIST_CREATE', 'FORUM_REPLY', 'FORUM_CREATE', 'FORUM_SUBSCRIBE', 'IMG_GEO', 'IMG_ADDSPECIE', 'SPECIE_ADDVIDEO', 'EARN_MEDAL'
)
ORDER BY id DESC
LIMIT 0 , 36
This query currently takes between 0.2 - 0.5s. I'd like to get it into the 0.00x range. As the above query retrieves a single column, a single condition, and a single sort parameter, I figured I'd just create a proper index and all will be good. No luck so far. Here's the table definition, stripped from irrelevant fields:
DROP TABLE IF EXISTS `karmalog`;
CREATE TABLE `karmalog` (
`id` int(11) NOT NULL auto_increment,
`event` enum('EDIT_PROFILE','EDIT_AVATAR','EDIT_EMAIL','EDIT_PASSWORD','FAV_IMG_ADD','FAV_IMG_ADDED','FAV_IMG_REMOVE','FAV_IMG_REMOVED','FOLLOW','FOLLOWED','UNFOLLOW','UNFOLLOWED','COM_POSTED','COM_POST','COM_VOTE','COM_VOTED','IMG_VOTED','IMG_UPLOAD','LIST_CREATE','LIST_DELETE','LIST_ADMINDELETE','LIST_VOTE','LIST_VOTED','IMG_UPD','IMG_RESTORE','IMG_UPD_LIC','IMG_UPD_MOD','IMG_UPD_MODERATED','IMG_VOTE','IMG_VOTED','TAG_FAV_ADD','CLASS_DOWN','CLASS_UP','IMG_DELETE','IMG_ADMINDELETE','IMG_ADMINDELETEFAV','SET_PASSWORD','IMG_RESTORED','IMG_VIEW','FORUM_CREATE','FORUM_DELETE','FORUM_ADMINDELETE','FORUM_REPLY','FORUM_DELETEREPLY','FORUM_ADMINDELETEREPLY','FORUM_SUBSCRIBE','FORUM_UNSUBSCRIBE','TAG_INFO_EDITED','JOIN','IMG_GEO','IMG_ADDSPECIE','IMG_REMOVESPECIE','SPECIE_ADDVIDEO','SPECIE_REMOVEVIDEO','EARN_MEDAL') NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `user_sec_id` (`user_sec_id`),
KEY `image_id` (`object_id`),
KEY `date_event` (`date_created`,`event`),
KEY `event` (`event`),
KEY `date_created` (`date_created`),
KEY `date_created_2` (`date_created`,`id`),
KEY `event_2` (`event`,`delete`),
CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL,
CONSTRAINT `user_sec_id` FOREIGN KEY (`user_sec_id`) REFERENCES `user` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
As you can see, I've tried a few indices already. Not shown in this version were two other index attempts (id, event and event, id), both to no avail. In all combinations tried so far, MySQL explain keeps saying it is using filesort.
Any ideas?
This is your query:
SELECT id
FROM karmalog
WHERE event IN ('FAV_IMG_ADD', 'FOLLOW', 'COM_POST', 'IMG_VOTE', 'LIST_VOTE', 'JOIN',
'CLASS_UP', 'LIST_CREATE', 'FORUM_REPLY', 'FORUM_CREATE', 'FORUM_SUBSCRIBE',
'IMG_GEO', 'IMG_ADDSPECIE', 'SPECIE_ADDVIDEO', 'EARN_MEDAL'
)
ORDER BY id DESC
LIMIT 0 , 36;
The first index to try is karmalog(event, id). The second is karmalog(id, event). Neither of these are in your list.
I have two tables: one and two. I have a primary key (id) in table one.
Table One:
CREATE TABLE `one` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`first_name` varchar(10) NOT NULL,
`last_name` varchar(10) NOT NULL,
`salary` int(100) NOT NULL,
`login_date_time` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1
id first_name last_name salary login_date_time
Table Two
CREATE TABLE two AS (SELECT id,salary ,CONCAT(first_name, ',', last_name) AS Name from one)
Now adding the foreign key to id as:
ALTER TABLE two
ADD CONSTRAINT `0_38775` FOREIGN KEY (id)
REFERENCES one(id) ON DELETE CASCADE ON UPDATE CASCADE
the table two comes as with the values from table one:
id salary name
Now to maintain referential integrity, how to update the values of table two when table one is updated. And also I cannot delete rows from table one and cannot insert rows to table two.
How can I update all the columns of table two when table one is updated/inserted. or insert explicitly into table two
Well, for the case of delete, when you delete the row from table 1, all the rows corresponding to that id will be deleted from table 2.
In case of update, if you want first name and last name to be updated in table 2 when they are altered in table 1 then you will have to write an update trigger for that.
I have the following table:
Create Table if not exists Categories(
category_id int (10) primary key NOT NULL AUTO_INCREMENT,
category_name varchar (20) NOT NULL,
parent_category_id int (10) NOT NULL,
FOREIGN KEY (parent_category_id) REFERENCES Categories(category_id) ON DELETE CASCADE)
The table is holding every category I have on my site - and each category have a parent category (for example 'computer' is the parent category of 'programming')
I have a few top categories which don't have any parent category => parent_category_id =0
My question is how to insert the data for the top categories.
when i'm trying to do:
INSERT INTO `databaseproject`.`categories` (`category_id` ,`category_name` ,`parent_category_id`)
VALUES (NULL , 'computers', '0')
I'm getting the error:
#1452 - Cannot add or update a child row: a foreign key constraint fails (`databaseproject`.`categories`, CONSTRAINT `categories_ibfk_1`
FOREIGN KEY (`parent_category_id`) REFERENCES `categories` (`category_id`) ON DELETE CASCADE)
what can I do to insert those categories?
Make parent_category_id nullable, and parent categories have a null parent_category_id, or add a root row with id 0.
You have two problems. First, category_id is an auto_increment field, meaning the database will create a value for you when you insert a new row, so you don't need to provide it. You certainly can't set it to null, since you have specifically said it can't be null, which is absolutely what you want for an auto-incrementing id field. Just change your insert to:
INSERT INTO 'databaseproject'.'categories' ('category_name' ,'parent_category_id')
VALUES ('computers', '0')
But you still have another problem. parent_category_id has to refer to a valid record in the categories table because of the constraint you created. You can solve this problem by allowing the field to be null (get rid of the "NOT NULL" when creating the parent_category_id), and using null instead of zero to indicate this is a top level record.
My goal in general is like that:
I have a a table with many translations - each translation have a rating - the average of all ratings from the user.
each translation have a unique Id, and in the second table I am saving for each user that ranked a translation the rating he\she gave (userId, translationId, rating)
now everytime a user rank a new translation or change his old rate I want to update the average rating of this translation
I have the following tables:
Create Table if not exists Translation
(TranslationID int (12) NOT NULL UNIQUE AUTO_INCREMENT,
UserID int (10) NOT NULL,
ImageID int (10) NOT NULL,
ChainID int (2) NOT NULL,
Translation text,
TranslationRating double Default 0 CHECK (TranslationRating>=0 AND TranslationRating<=5),
NumOfRatings int (10) Default 0,
CONSTRAINT translations PRIMARY KEY (UserID,ImageID, ChainID),
FOREIGN KEY (UserID) REFERENCES Users(UserID) ON DELETE CASCADE,
FOREIGN KEY (ImageID) REFERENCES Images(ImageID) ON DELETE CASCADE)
Create Table if not exists TranslationsRating
(UserID int (10) NOT NULL ,
TranslationID int (3) NOT NULL,
Rating double Default 0 CHECK (TranslationRating>=0 AND TranslationRating<=5),
CONSTRAINT known_lang PRIMARY KEY (UserID,TranslationID),
FOREIGN KEY (UserID) REFERENCES Users(UserID) ON DELETE CASCADE,
FOREIGN KEY (TranslationID) REFERENCES Translation(TranslationID) ON DELETE CASCAD
this means that everytime a new row is inserted into 'TranslationsRating' or I update the rating column in this table I want to take the translationId of the row that was just changed and in the 'translation' table update this translationId rating (find all rating for this Id in 'TranslationsRating' and calc the average)
I'm trying to define the following trigger:
CREATE TRIGGER UPDATE_TRANS_RATING
AFTER UPDATE ON TRANSLATIONSRATING
FOR EACH ROW
BEGIN
UPDATE TRANSLATION SET TRANSLATIONRATING = (SELECT AVG(RATING) FROM TRANSLATIONSRATING
WHERE TRANSLATIONSRATING.TRANSLATIONID = RATINGNEW.ID)
END;
and I'm getting the following error message (I'm using phpMyAdmin):
MySQL said: #1303 - Can't create a TRIGGER from within another stored routine
my question is what is this error, and if my trigger is written in a good way that will achive my goal