I have a mysql table with a compound primary key. The table definition looks like(some column omitted):
CREATE TABLE `wasteitem` (
`categoryid` char(4) NOT NULL,
`classid` char(4) NOT NULL,
`LIflag` int(11) NOT NULL,
PRIMARY KEY (`categoryid`,`classid`)
);
And I want to determine if any of known keys have been used.
If the table have only a simple primary key I can use query like this:
select categoryid from wasteitem where categoryid in ('key1','key2','key3','key4')
Things to be concerned:
The primary key is a compound key.
The known keys in the list might be very long.
This table is very big(26GB)
You could put the keys you're interested in in another (temporary) table, and join.
use it, to look for keys
DESCRIBE wasteitem
that would be something similar:
mysql> describe wasteitem;
+------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+-------+
| categoryid | char(4) | NO | PRI | NULL | |
| classid | char(4) | NO | PRI | NULL | |
| LIflag | int(11) | NO | | NULL | |
+------------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
Related
I'm learning from an online course MySQL using the WampServer and editing code in MySQL Workbench.
Trying to create a table with the following code, the column nome appears to be the primary key from the table, but i'm only using the unique constraint.
When i don't use the unique constraint, the code runs normally and don't give me a primary key.
create table if not exists cursos (
nome varchar(30) not null unique,
descricao text,
carga int unsigned,
totalaulas int unsigned,
ano year default '2016'
) default charset utf8mb4;
Second to this question, when i was trying to drop the constraint primary key i was getting the error Error Code: 1091. Can't DROP 'PRIMARY';
alter table cursos
drop primary key;
So, in resume, i'm trying to use the unique constraint without setting a column has a primary key, and then i'm trying to drop the primary key constraint.
Edit:
When i call describe table i get this, the column nome is defined has primary key whithout i using the constraint.
+------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+-------------+------+-----+---------+----------------+
| idcurso | int | YES | | NULL | |
| nome | varchar(30) | NO | PRI | NULL | |
+------------------+-------------+------+-----+---------+----------------+
What i'm trying to do is drop the primary key from nome and put on idcurso, but when i use the code
alter table cursos
add primary key idcurso;
I get the error Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line
I tried this on mysql command-line client connected to a MySQL Server 5.5.2. Here is what happens:
mysql> create table if not exists cursos (
-> nome varchar(30) not null unique,
-> descricao text,
-> carga int unsigned,
-> totalaulas int unsigned,
-> ano year default '2016'
-> ) default charset utf8mb4;
Query OK, 0 rows affected (0.08 sec)
mysql>
mysql> desc cursos;
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| nome | varchar(30) | NO | PRI | NULL | |
| descricao | text | YES | | NULL | |
| carga | int(10) unsigned | YES | | NULL | |
| totalaulas | int(10) unsigned | YES | | NULL | |
| ano | year(4) | YES | | 2016 | |
+------------+------------------+------+-----+---------+-------+
5 rows in set (0.05 sec)
Note that the field nome has a Key as PRI. But, it is only a description and not a fact. If you try to DROP the primary key you will see an error like below:
mysql> alter table cursos drop primary key;
ERROR 1091 (42000): Can't DROP 'PRIMARY'; check that column/key exists
Add a new column and make it a primary key. Note the DESCRIPTION after that.
mysql> alter table cursos add idcurso int primary key;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc cursos;
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| nome | varchar(30) | NO | UNI | NULL | |
| descricao | text | YES | | NULL | |
| carga | int(10) unsigned | YES | | NULL | |
| totalaulas | int(10) unsigned | YES | | NULL | |
| ano | year(4) | YES | | 2016 | |
| idcurso | int(11) | NO | PRI | NULL | |
+------------+------------------+------+-----+---------+-------+
6 rows in set (0.05 sec)
At this point, you can drop the primary key using the syntax: alter table cursos drop primary key;. This will drop the primary key constraint only (but, not the column definition).
If you create yet another column, perhaps guid,
that has a UNIQUE constraint,
then you will be able to do what you wish.
(Not sure why you wish it. Whatever.)
A table can have multiple UNIQUE constraints.
Each table should have a PRIMARY KEY (which will of course be UNIQUE).
It affects physical layout of the rows on disk,
which affects retrieval speed and how the query planner behaves.
If you do not use the PRIMARY keyword, then the first UNIQUE column
will effectively be the primary key.
Put another way, to ALTER the table as you wish,
the backend DB will need to be able to promote
some candidate column so it becomes the new PRIMARY KEY.
i have this table
CREATE TABLE IF NOT EXISTS `transaction` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`amount` bigint(20) NOT NULL,
`req_id` int(11) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `transactions_873a2484` (`req_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci AUTO_INCREMENT=914 ;
i want to change this forign key transactions_873a2484 to a unque forign key
basically i want to change it to
UNIQUE KEY `transactions_req_id_de2b5683_uniq` (`req_id`),
i already have lots of data in my table otherwise i would have just remake this table .... is there anyway to do this withouth harming the data ?
I will improve this as I go. MySQL will honor your wishes, even allow you to shoot yourself in the foot as you go:
create table t9
(
id int auto_increment primary key,
thing varchar(20) not null,
key(thing),
unique key (thing),
unique key `yet_another` (thing)
);
-- warning 1831 dupe index
show create table t9;
CREATE TABLE `t9` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`thing` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `thing_2` (`thing`),
UNIQUE KEY `yet_another` (`thing`),
KEY `thing` (`thing`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
So look at all the baggage it you have to carry around with your upserts (read: slow extra unnecessary indexes).
So if you want it as lean as possible, as I mentioned in comments, unwind things first by dropping the FK's in the child tables, the referencing first. See This Answer.
Then drop the current non-unique parent key:
DROP INDEX index_name ON tbl_name;
Then add the unique key in the parent. This is the new referenced:
CREATE UNIQUE INDEX idxName ON tbl_name (colName);
Then add the FK's in the children (the referencing)
CREATE INDEX idxName ON child_tbl_name (colName);
You can get the key names by show create table theTableName or by SHOW INDEX. Use fresh names for the new ones, it doesn't matter.
Such as:
mysql> show index from t9;
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| t9 | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| t9 | 0 | thing_2 | 1 | thing | A | 0 | NULL | NULL | | BTREE | | |
| t9 | 0 | yet_another | 1 | thing | A | 0 | NULL | NULL | | BTREE | | |
| t9 | 1 | thing | 1 | thing | A | 0 | NULL | NULL | | BTREE | | |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
ALTER TABLE `transaction`
DROP INDEX `transactions_873a2484`,
ADD UNIQUE(req_id);
You cannot turn a non-unique into UNIQUE, but the above should do the equivalent. The data will be unharmed.
Edit: Not sure why this is marked as a duplicate. The error I am getting is different
I am trying to remove a primary key definition but am receiving an error for some reason.
mysql> ALTER TABLE `aux_sponsors` DROP PRIMARY KEY;
ERROR 1091 (42000): Can't DROP 'PRIMARY'; check that column/key exists
mysql> desc aux_sponsors;
+-------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| unit | varchar(8) | NO | | MF | |
| code | varchar(32) | NO | PRI | NULL | |
| userid | varchar(32) | NO | | | |
| fullName | varchar(64) | NO | | | |
| department | varchar(255) | NO | | | |
| description | varchar(255) | NO | | NULL | |
+-------------+--------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
Am I doing something wrong here? I simply want no more primary key in this table.
mysql> SHOW CREATE TABLE aux_sponsors;
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| aux_sponsors | CREATE TABLE `aux_sponsors` (
`unit` varchar(8) NOT NULL DEFAULT 'MF',
`code` varchar(32) NOT NULL,
`userid` varchar(32) NOT NULL DEFAULT '',
`fullName` varchar(64) NOT NULL DEFAULT '',
`department` varchar(255) NOT NULL DEFAULT '',
`description` varchar(255) NOT NULL,
UNIQUE KEY `code` (`code`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
You don't have a PRIMARY KEY; you have a UNIQUE key. So, you can't do this:
ALTER TABLE `aux_sponsors` DROP PRIMARY KEY
Instead, just do
ALTER TABLE `aux_sponsors` DROP KEY `code`
DESC (a/k/a DESCRIBE) is not a true MySQL feature; according to the docs, "The DESCRIBE statement is provided for compatibility with Oracle."
More from the documentation:
A UNIQUE index may be displayed as PRI if it cannot contain NULL values and there is no PRIMARY KEY in the table. A UNIQUE index may display as MUL if several columns form a composite UNIQUE index; although the combination of the columns is unique, each column can still hold multiple occurrences of a given value.
In your case, the column code is NOT NULL and is the only column in a UNIQUE key, so DESC is showing it as PRI. Because of this type of problem, it's better to use SHOW INDEX to find out the types of keys on a table.
I have found that MySQL (Win 7 64, 5.6.14) does not use index properly if I specify table output for IN statement. USER table contains 900k records.
If I use IN (_SOME_TABLE_OUTPUT_) syntax - I get fullscan for all 900k users. Query runs forever.
If I use IN ('CONCRETE','VALUES') syntax - I get a correct index usage.
How can I make MySQL finally USE the index?
1st case:
explain SELECT gu.id FROM USER gu WHERE gu.uuid in
(select '11b6a540-0dc5-44e0-877d-b3b83f331231' union
select '11b6a540-0dc5-44e0-877d-b3b83f331232');
+----+--------------------+------------+-------+---------------+------+---------+------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+------------+-------+---------------+------+---------+------+--------+--------------------------+
| 1 | PRIMARY | gu | index | NULL | uuid | 257 | NULL | 829930 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 3 | DEPENDENT UNION | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| NULL | UNION RESULT | <union2,3> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------------+------------+-------+---------------+------+---------+------+--------+--------------------------+
2nd case:
explain SELECT gu.id FROM USER gu WHERE gu.uuid in
('11b6a540-0dc5-44e0-877d-b3b83f331231');
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
| 1 | SIMPLE | gu | ref | uuid | uuid | 257 | const | 1 | Using where; Using index |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
Table structure:
CREATE TABLE `USER` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`version` bigint(20) NOT NULL,
`email` varchar(255) DEFAULT NULL,
`uuid` varchar(255) NOT NULL,
`partner_id` bigint(20) NOT NULL,
`password` varchar(255) DEFAULT NULL,
`date_created` datetime DEFAULT NULL,
`last_updated` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique-email` (`partner_id`,`email`),
KEY `uuid` (`uuid`),
CONSTRAINT `fk_USER_partner` FOREIGN KEY (`partner_id`) REFERENCES `partner` (`id`) ON DELETE CASCADE,
CONSTRAINT `FKB2D9FEBE725C505E` FOREIGN KEY (`partner_id`) REFERENCES `partner` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3315452 DEFAULT CHARSET=latin1
FORCE INDEX and USE INDEX statements don't change anything.
Demonstration SQLfiddle: http://sqlfiddle.com/#!2/c607e1/2
In fact I faced such problem before and it happened that I had one table that had a single column set as UTF-8 and the other tables where latin1. It did not matter what I did, MySQL insisted on using no indexes. The problem is quite well described on this blog post Slow queries in MySQL due to collation problems. Once you manage to fix the character set, I believe any of the queries will work.
An inner join on your virtual table might give you better performance. Try something along these lines.
SELECT gu.id
FROM USER gu
INNER JOIN (
select '11b6a540-0dc5-44e0-877d-b3b83f331231' uuid
union all
select '11b6a540-0dc5-44e0-877d-b3b83f331232') ids
on gu.uuid = ids.uuid;
I am trying to change an existing column in a table I have to allow for null values and then set the default value to null. I tried running the following but it does not seem to be updating the table:
mysql> ALTER TABLE answers_form MODIFY sub_id int unsigned NULL DEFAULT NULL;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc answers_form;
+--------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+-------+
| answer_id | int(10) unsigned | NO | PRI | 0 | |
| sub_id | int(10) unsigned | NO | PRI | 0 | |
| form_id | int(10) unsigned | NO | PRI | NULL | |
| value | varchar(255) | NO | | NULL | |
| non_response | bit(1) | YES | | b'0' | |
+--------------+------------------+------+-----+---------+-------+
5 rows in set (0.01 sec)
Can anyone see what I am doing wrong here?
its a primary key , mysql doesn't allow any part of the primary key to be null, which does make the fact that it allows a default value of null for the form_id odd, however the docs at
http://dev.mysql.com/doc/refman/5.5/en/optimizing-primary-keys.html
say "Query performance benefits from the NOT NULL optimization, because it cannot include any NULL values".
Just out of curiosity, does it actually allow you to put in null values in the form_id field?
You have 2 non-nullable columns with the default value of null. This shouldn't be allowed by your database engine. If it is, it is rather far from a best practice.
sub_id is listed as a primary key
From the MySQL docs (5.7, but other versions say the same thing):
A PRIMARY KEY is a unique index where all key columns must be defined
as NOT NULL. If they are not explicitly declared as NOT NULL, MySQL
declares them so implicitly (and silently).
As to the discussion about the Non-null columns having a Default of NULL...
The NULL value in the Default column means that there is no default, not that the default is NULL.
Fiddle: http://sqlfiddle.com/#!2/c718d/1
If I create a simple table like so:
CREATE TABLE name_num(
Number INT PRIMARY KEY,
Name TEXT NOT NULL
);
And then do desc name_num, I get:
| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA |
---------------------------------------------------
| Number | int(11) | NO | PRI | (null) | |
| Name | text | NO | | (null) | |
Again, from the MySQL docs:
If the column cannot take NULL as the value, MySQL defines the column with no explicit DEFAULT clause. Exception: If the column is defined as part of a PRIMARY KEY but not explicitly as NOT NULL, MySQL creates it as a NOT NULL column (because PRIMARY KEY columns must be NOT NULL), but also assigns it a DEFAULT clause using the implicit default value. To prevent this, include an explicit NOT NULL in the definition of any PRIMARY KEY column.