This question has been asked before, but they all referenced to single and not composite keys, and the solutions don't seem to work for me. Basically, please consider the following table:
CREATE TABLE IF NOT EXISTS `my_answers` (
`id` int(11) NOT NULL auto_increment,
`question_id` int(11) NOT NULL default 0,
`user_id` int(11) NOT NULL default 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`question_id`, `user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
How do I remove the unique key made of question_id and user_id in this case? I have tried the following:
ALTER TABLE my_answers DROP INDEX `UNIQUE`;
and
DROP INDEX UNIQUE ON my_answers;
Both of which didn't work, throwing the following error "#1091 - Can't DROP 'UNIQUE'; check that column/key exists"
Any help is greatly appreciated, thanks!
If you do not specify a name of the unique key in case of composite key then by default the first column name is used as the name.
Here is the example
mysql> CREATE TABLE IF NOT EXISTS `my_answers` (
-> `id` int(11) NOT NULL auto_increment,
-> `question_id` int(11) NOT NULL default 0,
-> `user_id` int(11) NOT NULL default 0,
-> PRIMARY KEY (`id`),
-> UNIQUE KEY (`question_id`, `user_id`)
-> ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.08 sec)
If you now run show create table you can see something as
mysql> show create table my_answers ;
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| my_answers | CREATE TABLE `my_answers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`question_id` int(11) NOT NULL DEFAULT '0',
`user_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `question_id` (`question_id`,`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
Here you can see that the key name is the first column in the composite key which is question_id and you can drop it as
mysql> alter table `my_answers` drop INDEX question_id ;
Query OK, 0 rows affected (0.09 sec)
Try the following command:
show index from `my_answers`;
then inspect the key name of your index and drop it by its name.
I have found the answer, turns out it was ridiculously simple. Simply remove one of the field as index key:
ALTER TABLE my_answers DROP INDEX user_id
Turns out this will dismantle the composite key.
Related
MySql: AUTO_INCREMENT is missing from some tables after running for about one month.
Initially: (show create table Foo)
CREATE TABLE `Foo` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL,
`type` tinyint(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8
After one month:
CREATE TABLE `Foo` (
`id` bigint(20) NOT NULL,
`name` varchar(10) NOT NULL,
`type` tinyint(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
AUTO_INCREMENT is missing. What is the cause?
Mysql Server version: 5.6.25, Linux
Someone must have changed it. This change does not happen spontaneously.
I can reproduce this change myself:
CREATE TABLE Foo ( id BIGINT AUTO_INCREMENT, ...
ALTER TABLE Foo MODIFY COLUMN id BIGINT;
SHOW CREATE TABLE Foo\G
*************************** 1. row ***************************
Table: foo
Create Table: CREATE TABLE `foo` (
`id` bigint(20) NOT NULL,
`name` varchar(10) NOT NULL,
`type` tinyint(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Now the column shows it is BIGINT but not AUTO_INCREMENT.
Every time you MODIFY COLUMN or CHANGE COLUMN, you must repeat all the column options like NOT NULL and AUTO_INCREMENT and DEFAULT, or else it will revert to defaults (i.e. not auto-increment).
So I would interpret this shows that someone did an ALTER TABLE and didn't remember to include the AUTO_INCREMENT column option.
Just a thought.
If you have binary logs, you may see the alter query on the logs and when it was run. :)
Check if the binary log is enabled by
show variable like 'log_bin';
If binary log is enabled, find the likely period that the query could have been executed and then use mysqlbinlog to help you find it.
If binary log is not enabled, bad luck - as the previous post by Bill Karwin has suggested mysql does not change it on its own - someone must have changed it.
I have the following InnoDB tables:
CREATE TABLE `vehicle` (
`ID` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(50) DEFAULT NULL,
`Model` varchar(100) DEFAULT NULL,
`Engine_Type` varchar(70) DEFAULT NULL,
`Construction_From` date DEFAULT NULL,
`Construction_To` date DEFAULT NULL,
`Engine_Power_KW` mediumint(8) unsigned DEFAULT NULL,
`Engine_Power_HP` mediumint(8) unsigned DEFAULT NULL,
`CC` mediumint(8) unsigned DEFAULT NULL,
`TTC_TYP_ID` int(11) unsigned DEFAULT NULL,
`Vehicle_Type` tinyint(1) DEFAULT NULL,
`ID_Body_Type` tinyint(3) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=49407 DEFAULT CHARSET=utf8;
CREATE TABLE `part` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`ID_Brand` smallint(5) unsigned DEFAULT NULL,
`Code_Full` varchar(50) DEFAULT NULL,
`Code_Condensed` varchar(50) DEFAULT NULL,
`Ean` varchar(50) DEFAULT NULL COMMENT 'The part barcode.',
`TTC_ART_ID` int(11) unsigned DEFAULT NULL COMMENT 'TecDoc ID.',
`ID_Product_Status` tinyint(3) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `TTC_ART_ID_UNIQUE` (`TTC_ART_ID`),
UNIQUE KEY `ID_Brand_Code_Full_UNIQUE` (`ID_Brand`,`Code_Full`)
) ENGINE=InnoDB AUTO_INCREMENT=3732260 DEFAULT CHARSET=utf8;
CREATE TABLE `vehicle_part` (
`ID_Vehicle` mediumint(8) unsigned NOT NULL,
`ID_Part` int(11) unsigned NOT NULL,
PRIMARY KEY (`ID_Vehicle`,`ID_Part`),
KEY `fk_vehicle_part_vehicle_id_vehicle_idx` (`ID_Vehicle`),
KEY `fk_vehicle_part_part_id_part_idx` (`ID_Part`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Table vehicle has about 45.000 records, table part has about 3.500.000 records and table vehicle_part has approximately 100.000.000 records.
Creating the secondary indexes for vehicle_part did not take too long, about 30 min for both.
What I cannot do though is create the foreign key constraints: for example
ALTER TABLE `vehicle_part`
ADD CONSTRAINT `fk_vehicle_part_vehicle_id_vehicle`
FOREIGN KEY (`ID_Vehicle`)
REFERENCES `vehicle` (`ID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
takes ages to complete. I understand the table is rebuilt since it consumes a lot of disk space. What can I do to improve the performance?
If I create the table with the fk constraints and then add the records the insert process in vehicle_part also takes ages (about 3 days).
I am using a laptop with 4GB RAM.
EDIT 12/01/2016
The answer given by Drew helped a lot in improving the performance dramatically. I changed every script using SELECT ... INTO outfile and then LOAD DATA INFILE from the exported csv file. Also sometimes before LOAD DATA INFILE dropping the indexes and recreating them after the load proccess saves even more time. There is no need to drop the fk constraints just the secondary indexes.
If you know your data is pristine from an FK perspective, then establish your structure without secondary indexes as suggested in comments, but with the FK in the schema yet with FK checks temporarily disabled.
Load your data. If external data, certainly do it with LOAD DATA INFILE.
After your data is loaded, turn on FK checks. And establish secondary indexes with Alter Table.
Again, going with the assumption that your data is clean. There are other ways of proving that after-the-fact for the risk-adverse.
create table student
( id int auto_increment primary key,
sName varchar(100) not null
-- secondary indexes to be added later
);
create table booksAssigned
( id int auto_increment primary key,
studentId int not null,
isbn varchar(20) not null,
constraint foreign key `fk_b_s` (studentId) references student(id)
-- secondary indexes to be added later
);
insert booksAssigned(studentId,isbn) values (1,'asdf'); -- Error 1452 as expected
set FOREIGN_KEY_CHECKS=0; -- turn FK checks of temporarily
insert booksAssigned(studentId,isbn) values (1,'asdf'); -- Error 1452 as expected
set FOREIGN_KEY_CHECKS=1; -- succeeds despite faulty data
insert booksAssigned(studentId,isbn) values (2,'38383-asdf'); -- Error 1452 as expected
As per op comments, how to drop auto-generated index in referencing table after initial schema creation:
mysql> show create table booksAssigned;
| booksAssigned | CREATE TABLE `booksassigned` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`studentId` int(11) NOT NULL,
`isbn` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_b_s` (`studentId`),
CONSTRAINT `booksassigned_ibfk_1` FOREIGN KEY (`studentId`) REFERENCES `student` (`id`)
) ENGINE=InnoDB |
mysql> set FOREIGN_KEY_CHECKS=0;
Query OK, 0 rows affected (0.00 sec)
mysql> drop index `fk_b_s` on booksAssigned;
Query OK, 0 rows affected (0.49 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table booksAssigned;
| booksAssigned | CREATE TABLE `booksassigned` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`studentId` int(11) NOT NULL,
`isbn` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `booksassigned_ibfk_1` FOREIGN KEY (`studentId`) REFERENCES `student` (`id`)
) ENGINE=InnoDB |
Further links
Temporarily disable foreign keys
A Rolando Answer
I am trying to add a foreign key to a table in Sequel Pro (using the UI).
I have two tables: "titles" and "categories" as below:
CREATE TABLE `titles` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` tinytext NOT NULL,
`category` varchar(256) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `category` (
`key` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(256) NOT NULL DEFAULT '',
PRIMARY KEY (`key`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
I want to create a foreign key, but nothing I try works.
The category table should be a simple lookup table. I want to assign each title a category from about 6 - 8 different choices.
Originally I had the category fields as tinytext, but I would get the error:
"MySQL Error 1170 (42000): BLOB/TEXT Column Used in Key Specification Without a Key Length".
Searched here and discovered you can't use text field that way, so I switched to Varchar and added a length of 256. Now I get:
MySQL said: Can't create table 'lit.#sql-2bf3_2' (errno: 150).
How can I create a foreign key for my table?
In Access this is pretty easily done. Somehow Access associates the unique key in the table with the lookup, but then hides the key and shows you the text field instead. How can I get a similar result with Sequel Pro and MySQL?
EDIT:
So, to clarify this is where I'm at right now. I've added an index on the category field in the titles table (first picture).
I've changed the "key" field in the category table to CategoryID (second picture).
However, I still can't seem to create the relationship between the two tables. I get the same error
As category will be your lookup table off of titles, you'd need to create an index on category which would refer to the foreign key. They would both need to be the same datatype (usually an INT, though sometimes you could use a CHAR(2) variable in some cases, but usually not necessary). Since you only expect 6-8 categories, I'd make it INT(1) (or may be INT(2) to be safe).
In this case, you would need to create something like categoryId which would first need to be indexed, then connect to the foreign key on categorywhich does not appear to exist; I'm not sure you want to use a term like key. Why not just make categoryId the primary key on category? this way when you create the foreign key on titles with the same name, it should link up fine.
Edit:
To clarify a little, after you've created categoryID on category you can do this under titles
ALTER TABLE Orders
ADD CONSTRAINT fk_categoryID
FOREIGN KEY (`categoryId`) REFERENCES `category`(`categoryId`)
Edit:
Here's a modification using your original layout. this should work for you:
CREATE TABLE IF NOT EXISTS `category` (
`key` int(2) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(256) NOT NULL DEFAULT '',
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
CREATE TABLE IF NOT EXISTS `titles` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` tinytext NOT NULL,
`categoryID` int(2) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `categoryID` (`categoryID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
ALTER TABLE `titles`
ADD CONSTRAINT `titles_ibfk_1` FOREIGN KEY (`categoryID`) REFERENCES `category` (`key`);
I have the following table:
mysql> show create table keyword_links\G
*************************** 1. row ***************************
Table: keyword_links
Create Table: CREATE TABLE `keyword_links` (
`keyword_id` int(11) NOT NULL AUTO_INCREMENT,
`keyword` tinytext NOT NULL,
`link` tinytext,
`weight` smallint(6) NOT NULL DEFAULT '0',
`class_id` smallint(6) NOT NULL DEFAULT '0',
`category_id` smallint(6) NOT NULL DEFAULT '0',
`timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`keyword_id`),
KEY `class_id` (`class_id`),
KEY `category_id` (`category_id`),
KEY `idx_keyword` (`keyword`(333))
) ENGINE=MyISAM AUTO_INCREMENT=5082 DEFAULT CHARSET=utf8
to which I am trying to add a new column, which is failing:
mysql> ALTER TABLE keyword_links ADD COLUMN list_id INT UNSIGNED NOT NULL DEFAULT 0;
ERROR 1170 (42000): BLOB/TEXT column 'keyword' used in key specification without a key length
The index on keyword column does have a key length of 333, so why is it failing and how to fix it?
UPDATE
I tried reducing the size of the index on the keyword column from 333 to 255 and now I am able to add the new column successfully:
ALTER TABLE keyword_links DROP INDEX idx_keyword;
CREATE INDEX index_keyword ON keyword_links (keyword(255));
ALTER TABLE keyword_links ADD COLUMN list_id INT UNSIGNED NOT NULL DEFAULT 0;
But I would still like to know what's going on.
This is because of myisam's index's length limit of 1000 bytes (see this link)
Please note that this is all about bytes, and that a character might take 2, 3 or even 4 bytes depending on your encoding, and also that an INT will always be 4 bytes.
Index key will allow only 255 i assume.
Assuming this table with nearly 5 000 000 rows
CREATE TABLE `author2book` (
`author_id` int(11) NOT NULL,
`book_id` int(11) NOT NULL,
KEY `author_id_INDEX` (`author_id`),
KEY `paper_id_INDEX` (`book_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
is it possible to add a primary index column id with autoincrement as first place? I expect something like this:
CREATE TABLE `author2book` (
`id` int(11) NOT NULL AUTO_INCREMENT, <<<< This is what I try to achieve!
`author_id` int(11) NOT NULL,
`book_id` int(11) NOT NULL,
KEY `author_id_INDEX` (`author_id`),
KEY `paper_id_INDEX` (`book_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Is this possible?
Edit: I should mention, that I'd like the added column to be populated.
You can use ALTER TABLE to add the column and index in one command. i.e.:
ALTER TABLE author2book ADD id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY (id);
See the MySQL docs for ALTER TABLE for more info.
Create a new table with the structure you want and the auto-incrementing key, and then insert all of the records from this table into that new table... then drop (or rename) the original table, and rename the new table to the original name.
insert into newTable (author_id, book_id)
select * from author2book
newTable will then contain your desired output.
ALTER TABLE author2book
ADD COLUMN `id` int(11) NOT NULL FIRST;
Populate the id field manually (by a script maybe?), then:
ALTER TABLE author2book
MODIFY COLUMN `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY;