I have a database with three tables.
The table Authentication contains the following:
+----------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-----------------+------+-----+---------+----------------+
| id | int(6) unsigned | NO | PRI | NULL | auto_increment |
| userid | varchar(30) | NO | | NULL | |
| password | varchar(30) | NO | | NULL | |
| role | varchar(20) | NO | | NULL | |
| email | varchar(50) | YES | | NULL | |
+----------+-----------------+------+-----+---------+----------------+
Login contains the following:
+--------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------+------+-----+---------+----------------+
| id | int(6) unsigned | NO | PRI | NULL | auto_increment |
| TimeLoggedIn | text | NO | | NULL | |
| sessionid | varchar(255) | NO | | NULL | |
+--------------+-----------------+------+-----+---------+----------------+
And Activity:
+----------+-----------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-----------------+------+-----+---------+-------+
| id | int(6) unsigned | NO | PRI | NULL | |
| Torrents | mediumtext | NO | | NULL | |
+----------+-----------------+------+-----+---------+-------+
There is a relation between the id fields of Authentication to id in the other tables.
I need to add multiple rows in Activity, with several values for Torrents for each id. Unfortunately, when I try adding a new row with duplicated id value with:
INSERT INTO `Activity` (`id`, `Torrents`) VALUES ('1', 'dssfsdffdsffs');
it gives me the error: #1062 - Duplicate entry '1' for key 'PRIMARY'
How do I solve it? How did I create the table wrong?
I've read the following apparently duplicate questions:
#1062 - Duplicate entry for key 'PRIMARY'
But though it says to remove it as my primary key, mysql didnt allow me to create a relationship unless I made it a primary key.
You cannot initiate one-to-many relation by referring primary key to primary key. That'll be a one-to-one relationship.
In both your Login and Activity tables you need to have a foreign key to refer back to Authentication's ID. Example:
CONSTRAINT `FK_Login` FOREIGN KEY (`AuthenticationID`) REFERENCES `Authentication` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE
Related
I have two databases test & test2. Both have the same tables(employees & salaries) and both have the same records. test2 database uses a foreign key and test database doesn't.
test structure
test.employees
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| emp_id | int(11) | NO | PRI | NULL | |
| name | varchar(30) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
test.salaries
+--------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| salary | int(11) | YES | | NULL | |
| emp_id | int(11) | NO | | NULL | |
+--------+---------+------+-----+---------+----------------+
test2 structure
test2.employees
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| emp_id | int(11) | NO | PRI | NULL | |
| name | varchar(30) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
test2.salaries
+--------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| salary | int(11) | YES | | NULL | |
| emp_id | int(11) | NO | MUL | NULL | |
+--------+---------+------+-----+---------+----------------+
I run the same join query on both databases
select * from employees inner join salaries on employees.emp_id=salaries.emp_id;
This is the output i get from test database which doesn't contain a foreign key
2844047 rows in set (3.25 sec)
This is the output i get from test2 database which contains a foreign key
2844047 rows in set (17.21 sec)
So does the foreign key slow down the join query?
Your empirical evidence suggests that in at least one case it does. So, if we believe your numbers, the answer is clearly "yes" -- and I assume you have ruled out other potential causes such as locks on the table or resource competition (actually the difference is pretty big). I presume that you want to know why.
In most databases, declaring a foreign key is about relational integrity. It would have no effect on the optimization of queries. The join conditions in the query would redundantly cover the same information.
However, MySQL does a bit more when a foreign key is declared. A foreign key declaration automatically creates an index on the columns being used. This is not standard behavior -- I'm not even sure if any other database does this.
Normally, an index would benefit performance. In this case, the optimizer has more choices on how to approach the query. For whatever reason, it is using a substandard execution plan.
You should be able to look at the explain plans and see a difference. The issue is that the optimizer has chosen the wrong plan. I would say that this is uncommon and should not dissuade you from using proper foreign key declarations in your databases.
I find myself stack to this problem. I've got the following 3 tables, which I can't modify (it'd be so nice):
Person
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| SSN | varchar(50) | NO | PRI | NULL | |
| name | varchar(50) | YES | UNI | NULL | |
| birthday | date | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
Employee
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| SSN | varchar(50) | NO | PRI | NULL | |
| department | varchar(50) | YES | | NULL | |
| salary | varchar(50) | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
Employer
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| name | varchar(50) | NO | PRI | NULL | |
| department | varchar(50) | YES | | NULL | |
| salary | varchar(50) | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
Contract
+----------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+-------------+------+-----+---------+-------+
| employer_name | varchar(50) | NO | PRI | NULL | |
| employee_name | varchar(50) | YES | PRI | NULL | |
+----------------+-------------+------+-----+---------+-------+
I know that:
employee(sin) is foreign key to person(sin),
employer(name) is foreign key to person(name),
contract(employer_name) is a foreign key to employer(name)
And I should insert another foreign key for contract(employee_name), though employee table has only the SSN. Is there a way to reference the foreign key to person.name, passing through employee table, something like
CONSTRAINTS FOREIGN KEY contract(employee_name) REFERENCES TO person(name) WHERE person(sin)=employee(sin);
?
Thank you very much for any help!
An SQL FK constraint says its referencing column list subrow values, if all non-NULL, have to appear as subrow values for its referenced column list, which must be declared UNIQUE/PK in a base table.
Your constraint is not an SQL FK constraint.
If we could use a query in the place of the referenced base table name in an SQL FK constraint then the constraint you would want would be:
Contract(person_name) REFERENCES
(SELECT name FROM Person p JOIN Employee e ON p.name = e.name)(name)
(It can be shown that name is UNIQUE in that table.) But we can't.
If MySQL supported CREATE ASSERTION then you could CHECK that every Contract person_name was IN (SELECT name FROM Person p JOIN Employee e ON p.name = e.name). But it doesn't.
So this is an example of a constraint that, if you can't redesign your tables, you would enforce by appropriate triggers when the tables involved change.
Is there a way to reference the foreign key to person.name, passing through employee table, something like
If you want to figure out situations like this then you have to forego the cop-outs of using precise terms like "foreign key" just because you are somehow reminded of the things they refer to but that aren't there, or using the poetic "passing through", or using the vague "something like". You have to actually write out the conditions that you want your tables to satisfy.
I have two tables in MySql Workbench; Categories and Products. I created a third table which contains PK's from the first two tables. How do I sort out which product falls under which category. Do I need to create a fourth table? Also, it is obvious that one category has many products. How do I put this data into the table?
The way I use it in my company is I have a Category table just as you have, a Brands table and a Products table (this is the basic setup, I have more tables for price history, product history, etc).
The Products table is the primary one, containing a foreign key to each of Categories and Brands.
Table tbl_category and tbl_brand has the same structure:
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(100) | YES | | NULL | |
+-------+--------------+------+-----+---------+----------------+
Table tbl_product:
+-----------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| category | int(11) | YES | MUL | NULL | |
| brand | int(11) | YES | MUL | NULL | |
| spec | varchar(100) | YES | | NULL | |
| descript | varchar(1000) | YES | | NULL | |
| unit | varchar(10) | YES | | PÇ | |
| cost | decimal(16,2) | YES | | NULL | |
| ..................................................................|
| |
+-----------+---------------+------+-----+---------+----------------+
And I have the following foreign keys:
KEY `product_category_fk` (`category`),
KEY `product_brand_fk` (`brand`),
CONSTRAINT `product_brand_fk` FOREIGN KEY (`brand`) REFERENCES `tbl_brand` (`id`) ON UPDATE CASCADE,
CONSTRAINT `product_category_fk` FOREIGN KEY (`category`) REFERENCES `tbl_category` (`id`) ON UPDATE CASCADE
The reasoning I used is: any given product has only one category and one brand, so I can put that information in the product record itself.
This is a good example starting point (Taken from here)
I'm making a database in MySQL in class and I'm having trouble adding foreign keys to my tables. I already added most of the foreign keys to my tables when I created the tables but obviously I couldn't add all of them in the creation process. I'm trying to add the remaining foreign keys with the below method.
ALTER TABLE ORDERS
ADD FOREIGN KEY (customer_sid) REFERENCES CUSTOMER(SID);
For some reason the error message listed in the title keeps popping up. The code is below. I can see the tables are coming out a bit funny but if you read them from left to right you can see what it says. What do you think?
mysql> show columns from games;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| gameID | int(11) | NO | PRI | NULL | auto_increment |
| videoGames | varchar(30) | NO | | NULL | |
| year | int(11) | NO | | NULL | |
| genreID | int(11) | NO | MUL | NULL | |
| companyID | int(11) | NO | MUL | NULL | |
| directorID | int(11) | NO | MUL | NULL | |
+------------+-------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)
mysql> show columns from consoles;
+--------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+----------------+
| consoleID | int(11) | NO | PRI | NULL | auto_increment |
| console | varchar(20) | NO | | NULL | |
| yearReleased | int(11) | NO | | NULL | |
+--------------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> alter table games
-> add foreign key(consoleID) references consoles(consoleID);
ERROR 1072 (42000): Key column 'consoleID' doesn't exist in table
There is no field consoleID in your table games. You need to create it before trying to add a constraint on it. This will add consoleID and create the constraint:
ALTER TABLE games ADD COLUMN consoleID INTEGER NOT NULL;
ALTER TABLE games ADD FOREIGN KEY (consoleID) REFERENCES consoles(consoleID);
You should think about adding a third table where you associate consoles with games because some games are multiplateform. :)
I have the tables Players and PlayerMeta
mysql> DESCRIBE Players;
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| ID | int(5) | NO | PRI | NULL | auto_increment |
| PlayerName | varchar(20) | NO | PRI | NULL | |
| Birthdate | date | YES | | NULL | |
| Location | varchar(20) | YES | | NULL | |
| FirstName | varchar(15) | YES | | NULL | |
| Whitelisted | tinyint(1) | NO | | 1 | |
+-------------+-------------+------+-----+---------+----------------+
mysql> DESCRIBE PlayerMeta;
+----------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------+------+-----+---------+-------+
| ID | int(5) | NO | PRI | NULL | |
| JoinDate | date | YES | | NULL | |
| BuildQuota | int(2) | NO | | 2 | |
| RegisteredDate | date | YES | | NULL | |
| HideBirthdate | tinyint(1) | NO | | 0 | |
+----------------+------------+------+-----+---------+-------+
I am trying to execute this command, and it returns Query OK:
ALTER TABLE PlayerMeta
ADD CONSTRAINT fk_PlayerID
FOREIGN KEY (ID)
REFERENCES Players(ID)
ON UPDATE CASCADE
ON DELETE CASCADE;
Yet, when I run SHOW CREATE TABLE PlayerMeta, it does not show the constraint, nor is it in INFORMATION_SCHEMA
Any thoughts? Thanks.
EDIT: Here is SHOW CREATE TABLE PlayerMeta:
mysql> SHOW CREATE TABLE PlayerMeta;
... a bunch of lines ...
| PlayerMeta | CREATE TABLE `PlayerMeta` (
`ID` int(5) NOT NULL,
`JoinDate` date DEFAULT NULL,
`BuildQuota` int(2) NOT NULL DEFAULT '2',
`RegisteredDate` date DEFAULT NULL,
`HideBirthdate` tinyint(1) NOT NULL DEFAULT '0',
UNIQUE KEY `ID` (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
EDIT(2): The problem was ID in PlayerMeta was already a primary key and a foreign key would not apply in conjunction with it.
You cannot create foreign keys for MyISAM.
Only InnoDB supports them.
So the solution for you is to change the storage engine for both tables.
ALTER TABLE Players ENGINE=InnoDB;
ALTER TABLE PlayerMeta ENGINE=InnoDB;
Then re-apply your ALTER with adding a FK constraint.
MySQL will not permit you to create a FOREIGN KEY constraint on a column which is itself a PRIMARY KEY. If your design is such that the two tables share a one-to-one relationship and both hold information about a Player, it may not make sense to separate them and instead combine both tables into one.
In any case, if you wish to keep them separate and enforce a FOREIGN KEY relationship on them, you need to remove the PRIMARY KEY on PlayerMeta.ID. You may still have a UNIQUE, non primary key index on it.