how to properly create a foreign key? - mysql

I have the below SQL
mysql-sql> create table Employees (Emp_ID int not null primary key, Emp_Name varchar(20),Hours_LoggedIn int);
Query OK, 0 rows affected (0.09 sec)
mysql-sql> insert into Employees (Emp_ID,Emp_Name,Hours_LoggedIn) values (001,'Dinesh',9);
Query OK, 1 row affected (0.03 sec)
mysql-sql> insert into Employees (Emp_ID,Emp_Name,Hours_LoggedIn) values (002,'Shruthi',8);
Query OK, 1 row affected (0.02 sec)
mysql-sql> insert into Employees (Emp_ID,Emp_Name,Hours_LoggedIn) values (003,'Sukanya',7);
Query OK, 1 row affected (0.00 sec)
mysql-sql> insert into Employees (Emp_ID,Emp_Name,Hours_LoggedIn) values (004,'Varun',6);
Query OK, 1 row affected (0.00 sec)
mysql-sql> insert into Employees (Emp_ID,Emp_Name,Hours_LoggedIn) values (005,'Karthi',5);
Query OK, 1 row affected (0.01 sec)
mysql-sql> create table Project (Project_ID int not null primary key,Project_Name varchar(20),Project_Manager varchar(20),CostPerHour int,Minimum_LoggedInHours int,foreign key(Minimum_LoggedInHours) references Employees(Hours_LoggedIn));
Am getting the below error.
ERROR: 1215 (HY000): Cannot add foreign key constraint
I need to use Hours_LoggedIn as FK. Can anyone help with the correct code?

MySQL requires any column referenced by a foreign key to be indexed. Try the following:
ALTER TABLE Employees ADD INDEX hours_logged_in_idx(Hours_LoggedIn);
before creating the project table. Note that since Hours_LoggedIn is not necessarily unique that this may cause unexpected behavior.

Related

Will MySQL lock the index row when executing a concurrent insert with same index value?

I have a table like this:
create table `sample` (
id int auto_increment,
sid int,
message varchar(100),
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_sid` (`sid`)
);
sid is not an unique index.
When I executing insert, all record will have the same value of sid. Will these insert statement lock the row by insert intention lock as they all have the same insert index?
Test it!
Window 1:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into sample set sid = 42;
Query OK, 1 row affected (0.01 sec)
Window 2:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into sample set sid = 42;
Query OK, 1 row affected (0.00 sec)
Both are able to insert. There's no contention.

MySQL ENUM to VARCHAR conversion issue

I have a table "temp_enum_test1" with data type "enum('IE','IS')". When I try to ALTER the table by changing data type into VARCHAR from 'ENUM', getting duplicate entry error. It is accepting records in ENUM type. Even when I query the table I am getting unique rows. Can anyone please help me here. Below are the schema and my approach.
mysql> CREATE TABLE temp_enum_test1 (
-> r_id int(11) NOT NULL,
-> r_type enum('IE','IS'),
-> UNIQUE KEY uk_temp_enum_test1 (r_id,r_type)
-> );
Query OK, 0 rows affected (0.38 sec)
mysql> insert into temp_enum_test1 values(1,'IE');
Query OK, 1 row affected (0.07 sec)
mysql> insert into temp_enum_test1 values(1,'IS');
Query OK, 1 row affected (0.05 sec)
mysql> select * from temp_enum_test1;
+------+--------+
| r_id | r_type |
+------+--------+
| 1 | IE |
| 1 | IS |
+------+--------+
2 rows in set (0.00 sec)
mysql> alter table temp_enum_test1 change column r_type r_type varchar(30);
ERROR 1062 (23000): Duplicate entry '1-I' for key 'uk_temp_enum_test1'
mysql>
The problem seems to be with the create table query. The table has been created with 'UNIQUE KEY' that is causing the error while altering the table. If you can use
PRIMARY KEY (`r_id`)
instead of ...
UNIQUE KEY uk_temp_enum_test1 (r_id,r_type)
Complete CREATE command as below;
CREATE TABLE IF NOT EXISTS temp_enum_test1 (
`r_id` int(11) NOT NULL AUTO_INCREMENT,
`r_type` enum('IE','IS') NOT NULL,
PRIMARY KEY (`r_id`)
)

How to implement the multiple NULL check transaction in mysql

I want to implement the NULL check logic in the MYSQL. Here is the code:
mysql> create table temp
(
id int,
des varchar(100),
primary key (id)
);
mysql> SELECT ##tx_isolation;
+-----------------+
| ##tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
mysql> start transcation;
mysql> select * from temp where id=0;
Empty set (0.03 sec)
mysql> insert temp (id,des) values(0,'0');
Query OK, 1 row affected (0.11 sec)
mysql> commit;
Query OK, 0 rows affected (0.02 sec)
It seems well.
However, there is the possibility of multiple NULL check transaction at the same time for my situation.
Trans 1: Trans 2:
mysql> start transaction; mysql> start transaction;
mysql> select * from temp where id=0;
Empty set (0.03 sec)
mysql> select * from temp where id=0;
Empty set (0.03 sec)
mysql> insert temp (id,des) values(0,'0');
Query OK, 1 row affected (0.11 sec)
mysql> insert temp (id,des) values(0,'0');
mysql> commit;
Query OK, 0 rows affected (0.02 sec)
--block and waiting for the Trans 1 commit;
ERROR 1062 (23000): Duplicate entry '0' for key 'PRIMARY'
Trans 2 will report the ERROR 1062 when Trans 1 commit. I want to avoid the Error and I think it is a universal phenomenon of NULL check in the application.
How to implement the multiple NULL check transaction in mysql in the correct way? Are there any ways to block each other when using the "select" sql in the multiple transcation?
Thank you.
update 2016.07.12
I just simplify the situation I meet with above. In fact, the table I have is similar to
mysql> create table temp
(
id int NOT NULL AUTO_INCREMENT,
des varchar(100),
unique_id int,
primary key (id),
UNIQUE (unique_id)
);
And my transactions are
Trans 1: Trans 2:
mysql> start transaction; mysql> start transaction;
mysql> select * from temp where unique_id=0;
Empty set (0.06 sec)
mysql> select * from temp where unique_id=0;
Empty set (0.02 sec)
mysql> insert temp(des,unique_id) values('0',0);
Query OK, 1 row affected (0.20 sec)
mysql> insert temp(des,unique_id) values('0',0);
mysql> commit;
Query OK, 0 rows affected (0.02 sec)
--block and waiting for the Trans 1 commit;
ERROR 1062 (23000): Duplicate entry '0' for key 'unique_id'
So the PRIMARY KEY is AUTO_INCREMENT in my real case.
If you insist on inserting the primary key yourself, as opposed to having it autoincrement, then this is exactly the expected and desired behaviour that transactions were designed to create.
If you would like Trans 2 to commit, then you need to either not specify the primary key, or handle the primary key allocation in your application.

MySql silently ignores "references" keyword on table creation

mysql> create database test;
Query OK, 1 row affected (0.01 sec)
mysql> use test;
Database changed
mysql> create table one (id int not null primary key);
Query OK, 0 rows affected (0.03 sec)
mysql> -- here is the problem
mysql> create table two (oneid int not null references one(id));
Query OK, 0 rows affected (0.02 sec)
mysql> -- here are the first signs of issues!!!!
mysql> show create table two;
+-------+----------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+----------------------------------------------------------------------------------------+
| two | CREATE TABLE `two` (
`oneid` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+----------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> -- here is the issue: an insert with no reference
mysql> insert into two values (-12);
Query OK, 1 row affected (0.01 sec)
mysql> select * from two;
+-------+
| oneid |
+-------+
| -12 |
+-------+
1 row in set (0.00 sec)
mysql> -- if you want to know:
mysql> SHOW Variables WHERE Variable_name='foreign_key_checks';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| foreign_key_checks | ON |
+--------------------+-------+
1 row in set (0.00 sec)
After my research, the only question here is: why MySql do not reject table two creation because of its not valid syntax and instead it silently create the table without the foreign key reference?
Just for completeness here is the correct syntax for MySql.
mysql> create table three(oneid int not null, CONSTRAINT whatEverName FOREIGN KEY (oneid) REFERENCES one(id));
Query OK, 0 rows affected (0.04 sec)
MySQL parses but ignores “inline REFERENCES specifications” (as defined in the SQL standard) where the references are defined as part of the column specification. MySQL accepts REFERENCES clauses only when specified as part of a separate FOREIGN KEY specification.
You can go here and read more yourself...

mysql: Duplicate entry '0' for key 'PRIMARY' and bizarre ID behavior

See log below. (Snipped just for brevity; unsnipped # http://pastebin.com/k9sCM6Ee)
In short: somehow rows are getting assigned ID 0. When this happens, it blocks inserts, even when those inserts aren't actually conflicting with ID 0 (although that really shouldn't happen in the first place).
Although it is heavily read and very heavily inserted (up to ~300k rows/min), this table is never updated. The only method that inserts is the one that results in the INSERT INTO queries like below. There are no foreign keys or the like.
a) WTF?
b) How do I fix it?
Thanks!
$ mysql --version
mysql Ver 14.14 Distrib 5.1.30, for apple-darwin9.4.0 (i386) using readline 5.1
$ mysql
mysql> SHOW CREATE TABLE visitations \G
*************************** 1. row ***************************
Table: visitations
Create Table: CREATE TABLE `visitations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`scraping_id` int(11) NOT NULL,
`site_id` int(11) NOT NULL,
`visited` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `index_visitations_on_scraping_id_and_site_id` (`scraping_id`,`site_id`),
KEY `index_visitations_on_site_id` (`site_id`)
) ENGINE=InnoDB AUTO_INCREMENT=23525407 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> show triggers;
Empty set (0.04 sec)
mysql> INSERT INTO `visitations` (`scraping_id`,`site_id`,`visited`) VALUES (647,196,0),(647,51679,0),(647,13689,0),(647,85739,1),(647,4388,0),(647,100346,0),(647,1245,0),[snip];
ERROR 1062 (23000): Duplicate entry '0' for key 'PRIMARY'
mysql> SELECT * FROM `visitations` WHERE (`scraping_id`,`site_id`,`visited`) IN ((647,196,0),(647,51679,0),(647,13689,0),(647,85739,1),(647,4388,0),(647,100346,0),(647,1245,0),[snip]);
Empty set (1 min 27.43 sec)
mysql> select * from visitations where id = 0;
+----+-------------+---------+---------+
| id | scraping_id | site_id | visited |
+----+-------------+---------+---------+
| 0 | 645 | 46177 | 0 |
+----+-------------+---------+---------+
1 row in set (0.00 sec)
mysql> delete from visitations where id < 363;
Query OK, 363 rows affected (0.11 sec)
mysql> select * from visitations where id = 0;
Empty set (0.00 sec)
mysql> INSERT INTO `visitations` (`scraping_id`,`site_id`,`visited`) VALUES (647,196,0),(647,51679,0),(647,13689,0),(647,85739,1),(647,4388,0),(647,100346,0),(647,1245,0),[snip];
Query OK, 500 rows affected (0.23 sec)
Records: 500 Duplicates: 0 Warnings: 0
mysql> select * from visitations where id = 0;
Empty set (0.00 sec)
mysql> INSERT INTO `visitations` (`scraping_id`,`site_id`,`visited`) VALUES (647,196,0),(647,51679,0),(647,13689,0),(647,85739,1),(647,4388,0),(647,100346,0),(647,1245,0),[snip];
ERROR 1062 (23000): Duplicate entry '647-196' for key 'index_visitations_on_scraping_id_and_site_id'
You have probably hit a bug like:
auto increment does not work properly with InnoDB after update
You need to track the change history from the release you are using to identify whether fixed bugs can affect you and whether you should upgrade.
MySQL 5.1 Change History