I'm using the following statement ALTER TABLE my_tbl ADD PRIMARY KEY (id ); to add a primary key to an existing MySQL table. In reply I'm getting the error:
Error 156 : Table 'db_name.my_tbl#1' already exists.
I checked and the table has no duplicate id entries, and if I do something like DROP TABLE my_tbl#1 then the original table (my_tbl) is deleted. It's perhaps interesting to note that my_tbl was created by Create Table my_tbl SELECT id, ... FROM tmp_tbl (where tmp_tbl is a temporary table).
Anyone has an idea what's going on here?
Update: there seems to be some kind of an orphaned table situation here. I tried the suggestions in the answers below, but in my case they did not resolve the problem. I finally used a workaround: I created a table with a different name (e.g. my_tbl_new) , copied the information to this table and added to it the primary key. I Then deleted the original table and renamed the new one back to my_tbl.
try something like this:-
ALTER TABLE my_tbl DROP PRIMARY KEY, ADD PRIMARY KEY(id,id);
or try this:-
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'PRIMARY KEY'
AND TABLE_NAME = '[my_tbl]'
AND TABLE_SCHEMA ='dbo' )
BEGIN
ALTER TABLE [dbo].[my_tbl] ADD CONSTRAINT [PK_ID] PRIMARY KEY CLUSTERED ([ID])
END
or try to flush the table like this:-
DROP TABLE IF EXISTS `my_tbl` ;
FLUSH TABLES `my_tbl` ;
CREATE TABLE `my_tbl` ...
DROP TABLE IF EXISTS `mytable` ;
FLUSH TABLES `mytable` ;
CREATE TABLE `mytable` ...
Also it might be a permission issue.
I had the same problem while trying to alter indexes, through SQLyog, when my database name contained "-" chars. So I renamed the database to not have them and then it worked just fine.
(Since there's no direct way to rename a DB, I had to copy it to a new one, with correct name)
I have this error when inserting values into an association table during transaction:
Cannot add or update a child row: a foreign key constraint fails (dev.genre, CONSTRAINT fk_Genre_EntityType1 FOREIGN KEY (idEntityType) REFERENCES entitytype (idEntityType) ON DELETE NO ACTION ON UPDATE NO ACTION)
Here is the part of the schema that describes the tables used:
and here is the create statement of the genre table:
-- -----------------------------------------------------
-- Table `dev`.`Genre`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `dev`.`Genre` (
`idGenre` INT NOT NULL ,
`Name` VARCHAR(45) NULL COMMENT 'musique, spectacle, expo' ,
`idEntityType` INT NOT NULL ,
`idStyle` INT NOT NULL ,
PRIMARY KEY (`idGenre`, `idEntityType`, `idStyle`) ,
INDEX `fk_Genre_EntityType1_idx` (`idEntityType` ASC) ,
INDEX `fk_Genre_Style1_idx` (`idStyle` ASC) ,
CONSTRAINT `fk_Genre_EntityType1`
FOREIGN KEY (`idEntityType` )
REFERENCES `dev`.`EntityType` (`idEntityType` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_Genre_Style1`
FOREIGN KEY (`idStyle` )
REFERENCES `dev`.`Style` (`idStyle` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
To resume, the Genre tables references EntityType and Style, that's all.
The error occurs when I try to create a new Style and then add an association in the Genre table.
Everything is within a transaction, and what I do is:
create the new style in the Style table
get the id of the created style
insert an association in the genre table, and that's when I get the error.
I've searched quite a while on the web, but the only thing I found was this SO post: In MySQL, can I defer referential integrity checks until commit
I'm not sure this is what it is about here, because the error happens on a table that hadn't changed during the transaction (EntityType). Or am I missing something?
Can someone explain me the reason why I have this error please? (I'm stuck here)
Also, if it really have something to do with the SO post I mentioned earlier, is there a "clean" way of doing that kind of inserts without writing my own rollback mechanism?
Thanks for your answers
EDIT
the first query to insert a new style is:
CREATE PROCEDURE `Entity_CreateStyle`
(
IN p_name varchar(45),
OUT op_idStyle int(11)
)
BEGIN
insert into Style(idParentStyle, Name, IsValidated)
values(null, p_name, 0);
SET op_idStyle = LAST_INSERT_ID();
END
the next one, that produces the error:
CREATE PROCEDURE `Entity_AssociateStyleWithEntityType`
(
IN p_idGenre int(11),
IN p_Name varchar(45),
IN p_idEntityType int(11),
IN p_idStyle int(11)
)
BEGIN
insert into Genre(idGenre, Name, idEntityType, idStyle)
values(p_idGenre, p_Name, p_idEntityType, p_idStyle);
END
both are actually stored procedures that we call from C# using MySQL.Net connector
the p_idEntityType comes from the model (MVC) and I checked it's value is correct and exists in EntityType table.
The error message is clear: entitytype is referenced by genre. This means that ALL rows in entitytype must have a match in genre, or can't be inserted. There is a match when genre.entitytype = entitytype.entitytype.
Is there a way to create a unique index across tables in a MySQL database?
By unique, I mean,
table A ids=1,2,5,7...
table B ids=3,4,6,8...
I think, it is not possible by directly creating a constraint. But there are some solutions in order for you to get unique IDs.
One suggestion would be is by using TRIGGER. Create a BEFORE INSERT trigger on both tables which checks the ID for existence during INSERT or UPDATE.
Second, is by creating a third table which contains UNIQUE numbers and the other tables: TableA and TableB will then be reference on the third one.
Like JW says, this would probably work well with using a third table. In MySQL, you can use identity fields to make this easier. A very simple example would be using these tables (simple versions of the tables with just names without knowing any further info):
CREATE TABLE a
(
`id` int,
`name` varchar(100),
PRIMARY KEY(`id`)
)
ENGINE = INNODB;
CREATE TABLE b
(
`id` int,
`name` varchar(100),
PRIMARY KEY(`id`)
)
ENGINE = INNODB;
CREATE TABLE c
(
`id` int auto_increment,
`intable` varchar(10) not null,
PRIMARY KEY(`id`)
)
ENGINE = INNODB;
Then, when you want to insert a value on either table, do (a sample inserting 'Joe' into a):
INSERT INTO c (`intable`) VALUES ('a');
INSERT INTO a (`id`, `name`)
SELECT LAST_INSERT_ID() AS id, 'Joe' AS name;
The only reason for the intable entry in c is so you know which table it was created for. Any sort of value to insert into c can be used instead.
I've searched around but didn't find if it's possible.
I've this MySQL query:
INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8)
Field id has a "unique index", so there can't be two of them. Now if the same id is already present in the database, I'd like to update it. But do I really have to specify all these field again, like:
INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8)
ON DUPLICATE KEY UPDATE a=2,b=3,c=4,d=5,e=6,f=7,g=8
Or:
INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8)
ON DUPLICATE KEY UPDATE a=VALUES(a),b=VALUES(b),c=VALUES(c),d=VALUES(d),e=VALUES(e),f=VALUES(f),g=VALUES(g)
I've specified everything already in the insert...
A extra note, I'd like to use the work around to get the ID to!
id=LAST_INSERT_ID(id)
I hope somebody can tell me what the most efficient way is.
The UPDATE statement is given so that older fields can be updated to new value. If your older values are the same as your new ones, why would you need to update it in any case?
For eg. if your columns a to g are already set as 2 to 8; there would be no need to re-update it.
Alternatively, you can use:
INSERT INTO table (id,a,b,c,d,e,f,g)
VALUES (1,2,3,4,5,6,7,8)
ON DUPLICATE KEY
UPDATE a=a, b=b, c=c, d=d, e=e, f=f, g=g;
To get the id from LAST_INSERT_ID; you need to specify the backend app you're using for the same.
For LuaSQL, a conn:getlastautoid() fetches the value.
There is a MySQL specific extension to SQL that may be what you want - REPLACE INTO
However it does not work quite the same as 'ON DUPLICATE UPDATE'
It deletes the old row that clashes with the new row and then inserts the new row. So long as you don't have a primary key on the table that would be fine, but if you do, then if any other table references that primary key
You can't reference the values in the old rows so you can't do an equivalent of
INSERT INTO mytable (id, a, b, c) values ( 1, 2, 3, 4)
ON DUPLICATE KEY UPDATE
id=1, a=2, b=3, c=c + 1;
I'd like to use the work around to get the ID to!
That should work — last_insert_id() should have the correct value so long as your primary key is auto-incrementing.
However as I said, if you actually use that primary key in other tables, REPLACE INTO probably won't be acceptable to you, as it deletes the old row that clashed via the unique key.
Someone else suggested before you can reduce some typing by doing:
INSERT INTO `tableName` (`a`,`b`,`c`) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE `a`=VALUES(`a`), `b`=VALUES(`b`), `c`=VALUES(`c`);
There is no other way, I have to specify everything twice. First for the insert, second in the update case.
Here is a solution to your problem:
I've tried to solve problem like yours & I want to suggest to test from simple aspect.
Follow these steps: Learn from simple solution.
Step 1: Create a table schema using this SQL Query:
CREATE TABLE IF NOT EXISTS `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(30) NOT NULL,
`password` varchar(32) NOT NULL,
`status` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `no_duplicate` (`username`,`password`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
Step 2: Create an index of two columns to prevent duplicate data using following SQL Query:
ALTER TABLE `user` ADD INDEX no_duplicate (`username`, `password`);
or, Create an index of two column from GUI as follows:
Step 3: Update if exist, insert if not using following queries:
INSERT INTO `user`(`username`, `password`) VALUES ('ersks','Nepal') ON DUPLICATE KEY UPDATE `username`='master',`password`='Nepal';
INSERT INTO `user`(`username`, `password`) VALUES ('master','Nepal') ON DUPLICATE KEY UPDATE `username`='ersks',`password`='Nepal';
Just in case you are able to utilize a scripting language to prepare your SQL queries, you could reuse field=value pairs by using SET instead of (a,b,c) VALUES(a,b,c).
An example with PHP:
$pairs = "a=$a,b=$b,c=$c";
$query = "INSERT INTO $table SET $pairs ON DUPLICATE KEY UPDATE $pairs";
Example table:
CREATE TABLE IF NOT EXISTS `tester` (
`a` int(11) NOT NULL,
`b` varchar(50) NOT NULL,
`c` text NOT NULL,
UNIQUE KEY `a` (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
I know it's late, but i hope someone will be helped of this answer
INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
You can read the tutorial below here :
https://mariadb.com/kb/en/library/insert-on-duplicate-key-update/
http://www.mysqltutorial.org/mysql-insert-or-update-on-duplicate-key-update/
You may want to consider using REPLACE INTO syntax, but be warned, upon duplicate PRIMARY / UNIQUE key, it DELETES the row and INSERTS a new one.
You won't need to re-specify all the fields. However, you should consider the possible performance reduction (depends on your table design).
Caveats:
If you have AUTO_INCREMENT primary key, it will be given a new one
Indexes will probably need to be updated
With MySQL v8.0.19 and above you can do this:
mysql doc
INSERT INTO mytable(fielda, fieldb, fieldc)
VALUES("2022-01-01", 97, "hello")
AS NEW(newfielda, newfieldb, newfieldc)
ON DUPLICATE KEY UPDATE
fielda=newfielda,
fieldb=newfieldb,
fieldc=newfieldc;
SIDENOTE: Also if you want a conditional in the on duplicate key update part there is a twist in MySQL. If you update fielda as the first argument and include it inside the IF clause for fieldb it will already be updated to the new value! Move it to the end or alike. Let's say fielda is a date like in the example and you want to update only if the date is newer than the previous:
INSERT INTO mytable(fielda, fieldb)
VALUES("2022-01-01", 97)
AS NEW(newfielda, newfieldb, newfieldc)
ON DUPLICATE KEY UPDATE
fielda=IF(fielda<STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfielda,fielda),
fieldb=IF(fielda<STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfieldb,fieldb);
in this case fieldb would never be updated because of the <! you need to move the update of fielda below it or check with <= or =...!
INSERT INTO mytable(fielda, fieldb)
VALUES("2022-01-01", 97)
AS NEW(newfielda, newfieldb, newfieldc)
ON DUPLICATE KEY UPDATE
fielda=IF(fielda<STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfielda,fielda),
fieldb=IF(fielda=STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfieldb,fieldb);
This works as expected with using = since fielda is already updated to its new value before reaching the if clause of fieldb... Personally i like <= the most in such a case if you ever rearrange the statement...
you can use insert ignore for such case, it will ignore if it gets duplicate records
INSERT IGNORE
... ; -- without ON DUPLICATE KEY