MySQL - Unique foreign key - mysql

I have to make one of the foreign keys unique. The problem is, I am getting the following message from the phpMyAdmin:
The following indexes appear to be equal and one of them should be removed: consignmentnumber_id_UNIQUE, fk_consignments_consignmentnumbers2
So my question is this: should I be bothered? Is it really important not to have such indexes?

Every column with an key (primary, foreign) needs an index. Same with column being unique. You probably created two indexes (one when creating FK and one on Unique constraint). If this is the case just drop one of those indexes.
It is overhead for the DB to maintain two equivalent indexes.

mysql > create unique index index_bar_id on foos(bar_id);
mysql > alter table foos add constraint index_bar_id foreign key (bar_id) references bars (id);
Read more at http://sixarm.com/about/mysql-create-indexes-foreign-keys-constraints.html

For the future, if you want to make your foreign key unique, you can simply modify your foreign key column like this:
ALTER TABLE your_table
MODIFY COLUMN your_fk_column [INT, VARCHAR etc.][NOT NULL] UNIQUE;

Just so you know, it seems like you can also have UNIQUE foreign keys:
CREATE TABLE user(
uid INT NOT NULL AUTO_INCREMENT,
username VARCHAR(16) NOT NULL UNIQUE,
email_id INT NOT NULL UNIQUE,
FOREIGN KEY (email_id) REFERENCES email(uid)
ON DELETE CASCADE
ON UPDATE CASCADE,
PRIMARY KEY (uid));

Related

MySQL table foreign key indexes on primary index columns

I've created a table for accounts/users with a primary key (UsersID, AccountsID) like below. Should I add the index for the Users table?
create table AccountsUsers
(
AccountsID int unsigned not null,
UsersID int unsigned not null,
Roles bigint unsigned null,
primary key (UsersID, AccountsID),
constraint AccountsUsers_Accounts_ID_fk
foreign key (AccountsID) references Accounts (ID)
on update cascade on delete cascade,
constraint AccountsUsers_Users_ID_fk
foreign key (UsersID) references Users (ID)
on update cascade on delete cascade
)
engine=InnoDB
;
create index AccountsUsers_Accounts_ID_fk
on AccountsUsers (AccountsID)
;
MySQL will create the necessary indexes for the foreign key automatically, if necessary.
In the case of your foreign key on UsersId, it can use the left column of your primary key. It doesn't need to create a new index for that foreign key.
In the case of your foreign key on AccountsId, MySQL will create a new index automatically. It can't use the fact that AccountsId is part of your primary key, because it isn't the left-most column.
After you do the CREATE TABLE, run SHOW CREATE TABLE AccountsUsers and you should see the new index it created for AccountsId.
From the documentation
MySQL requires indexes on foreign keys and referenced keys so that
foreign key checks can be fast and not require a table scan. In the
referencing table, there must be an index where the foreign key
columns are listed as the first columns in the same order. Such an
index is created on the referencing table automatically if it does not
exist. This index might be silently dropped later, if you create
another index that can be used to enforce the foreign key constraint.
index_name, if given, is used as described previously.
In other words, if you don't already have the required indexes on the columns of your referencing table (AccountsUsers), MySQL will create them for you.
If the columns in the referenced tables (Accounts and Users) are not indexed you will get an error. Your's look like they will be Primary Keys on their respective tables, so you should be fine.

Can I add Primary Key with many condition

I've first table name "mustahik_perorangan" and the second name "data_mustahik"
mustahik perorangan have 4 primary key and foreign key in another table
like this condition
PRIMARY KEY (`mustahik_nik`,`ins_provinces_code`,`ins_cities_code`,`ins_institution_types_code`,`ins_institution_serial_no`),
KEY `fk_reference_6` (`ins_provinces_code`,`ins_cities_code`,`ins_institution_types_code`,`ins_institution_serial_no`),
CONSTRAINT `FK_ins_musper` FOREIGN KEY (`ins_provinces_code`, `ins_cities_code`, `ins_institution_types_code`, `ins_institution_serial_no`) REFERENCES `baznasgo_s_organization`.`institutions` (`provinces_code`, `cities_code`, `institution_types_code`, `institution_serial_no`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
and i want to add primary to table mustahik_perorangan, so mustahik perorangan have 5 primary key ?
but i can't do it because it condition..
ALTER TABLE mustahik_perorangan ADD idc INT UNSIGNED NOT NULL AUTO_INCREMENT,ADD PRIMARY KEY (`idc`);
May you know to do it ?
A table can have at most one primary key constraint.
The primary key constraint can contain multiple columns. We refer to that as a composite key.
It is possible to add a new column.
It's also possible to add a UNIQUE constraint on the column and specify AUTO_INCREMENT attribute on the column.
As an example:
ALTER TABLE mustahik_perorangan
ADD idc INT UNSIGNED NOT NULL AUTO_INCREMENT
, ADD UNIQUE KEY (`idc`)
It's also possible to a sixth column to the existing composite primary key. But I don't think this is what you really want.
As a demonstration of how to add a column to an existing composite primary key, I'll provide an example.
Note that the primary key must be dropped and re-added. And a UNIQUE key must be added for the AUTO_INCREMENT column.
Assuming there are no foreign keys referencing the primary key of this table.
ALTER TABLE mustahik_perorangan
DROP PRIMARY KEY
, ADD idc INT UNSIGNED NOT NULL AUTO_INCREMENT
, ADD UNIQUE KEY (`idc`)
, ADD PRIMARY KEY
(`mustahik_nik`
,`ins_provinces_code`
,`ins_cities_code`
,`ins_institution_types_code`
,`ins_institution_serial_no`
,`idc`
)
If there are foreign keys referencing the table, the change is a little more involved. (Did you want an additional column added to the foreign keys in the referencing tables?)
It's not entirely clear what you are attempting to achieve.
Yes, you can add the primary key, but in your case, you need to drop pk and then add new pk, otherwise the engine interpretes as you are trying to add multiple pks, the multiple pks are different from composite pk, you can add composite pk, but you can't add multiple pks
alter table xx drop primary key, add primary key(k1, k2, k3);

Drop just one column constraint from a composite primary key constraint

I have a Mysql table having the following structure:
As you can see there is a composite primary key constraint between the fields: word_id and preposition_id.
I want to remove the Primary Key constraint from word_id without touching the preposition_id field, and without losing data from the linked tables (Foreign Key tables). How can I do it?
Regards.
There is no syntax available to modify a constraint and drop only "a half" of the primary key.
You must drop the whole primary key, and then recreate it from scrach.
Just:
ALTER TABLE tablename DROP PRIMARY KEY;
and then:
ALTER TABLE tablename ADD PRIMARY KEY ( preposition_id );
You need first to drop all foreign keys thar reference the primary key in this table.
Data in tables will be preserved.

How do I reference a composite primary key with a foreign key using MySQL

I'm attempting to setup a foreign key in table cell_lines that will reference the topographic_region column of the composite primary key in table topographic_regions.
Each time I run the last three lines of code trying to add the foreign key, I receive Error Code 1215: cannot add foreign key constraint.
Now, the foreign key column name (topographic_region) in cell_lines only matches one of the composite primary key column names in topographic_regions, the other composite primary key column name being topographic_region_id. Do I usually need to address both components of a composite primary key when creating a foreign key?
A follow up problem is that I've actually already tried addressing both components of a composite primary key using a composite foreign key constraint, and I was still presented with an Error Code 1215: cannot add foreign key constraint.
What can I do to solve this problem, and is there anymore information you would like me to provide in order to do so? I'm happy to respond.
Thanks for reading. I'm very new to mySQL.
create table topographic_regions(
topographic_regions_id int not null auto_increment,
topographic_region int(10),
karyotypes varchar(255),
constraint pk_topographicID primary key (topographic_regions_id, topographic_region)
);
create table cell_lines(
cell_lines_id int not null auto_increment,
cell_line varchar(50),
topographic_region int(10),
constraint pk_cellID primary key (cell_lines_id, cell_line)
);
alter table cell_lines
add foreign key (topographic_region)
references topographic_regions(topographic_region);
This is the problem with composite PKs. In fact, your autonumber topographic_region_id will be unique and you should use that for the PK, and the FK. topographic_region sounds like it is also unique so you should add a unique index to it.
A foreign key is some columns whose subrow values have to appear as subrow values in another table where they are a candidate key. If you really had a foreign key from cell_lines to topographic_regions then cell_lines would have a topographic_region_name column and you would need:
alter table cell_lines
add foreign key (topographic_regions_id, topographic_region)
references topographic_regions(topographic_regions_id, topographic_region);
I suspect that (topographic_regions_id, topographic_region) is not a candidate key of topographic_regions and that topographic_regions_id is enough to identify a region just because you decided cell_lines doesn't have a topographic_region column. Although it may be that a cell line doesn't identify a particular topographic region. But then topographic_regions_id is not a foreign key in cell_lines, since it isn't a key in topographic_regions. (There is no easy way in SQL to constrain that some columns' subrow values have to appear as subrow values in another table where they are not a superset of a candidate key.)
If topographic_regions_id is unique in topographic_regions then it is a candidate key and should be declared UNIQUE NOT NULL. If topographic_region_name is unique in topographic_regions then it is a candidate key and should be declared UNIQUE NOT NULL. If either is a candidate key then (topographic_regions_id, topographic_region) is not a candidate key. You can pick one candidate key to be declared PRIMARY KEY which just means UNIQUE NOT NULL. Ditto for cell_line. Since your _id columns are auto_increment, I suspect they are unique, in which case neither table has a composite candidate key.
(All this assuming none of your columns can be NULL.)

adding a primary key when a foreign key already exists

I need to add a primary key on a table "usernames"
I have 3 columns in it :
userid int(10)
username char(20)
user char(50)
and the primary key is set on 'username' field and i used it as a foreign key to link it to another table. Now i need to add primary key on 'userid' field also... so i tried out :
alter table `usernames` drop primary key, add primary key(userid,username);
and i get an error saying
ERROR 1553 (HY000): Cannot drop index 'PRIMARY":needed in a foreign key constraint
is there any possible way to do this ??
There is:
Drop the FK constraint
Drop PK Constraint
Create New PK
Add Unique Constraint on the name column
Recreate FK
Raj
I assume you use MySql (despite you tag your question as Sql Server).
You can decide to:
Disable all check and try to remove primary key but the new must have the same name
or
Drop foreign key constraints referred to your primary key and then remove your primary key and finally re-add foreign keys
You have to drop the foreign key in order to modify the primary key
As implied by the name, a table can only have at most one PRIMARY key. Whilst it can have other UNIQUE keys, which have a similar effect, they really ought not be used for foreign-key relations.
So, you have two choices:
Retain your existing schema (perhaps username is a perfectly good natural key such that you need not bother with a synthetic one, in which case you can consider dropping the userid column altogether); or
Making userid your PRIMARY key, in which case username should not be used for foreign key relations. I outline below a method for doing this "offline" (where the database is guaranteed not to be altered by any other process during the transition); should you be working "online", you will need to add further steps to ensure integrity is preserved:
Add a new userid column for the foreign key in all child tables and drop the existing foreign key constraint:
ALTER TABLE foo
ADD COLUMN userid INT(10),
DROP FOREIGN KEY fk_name;
Change the primary key in your usernames tables (should you wish for the database to enforce a uniqueness constraint over username, you can define a UNIQUE key instead):
ALTER TABLE usernames
DROP PRIMARY KEY,
ADD PRIMARY KEY (userid),
ADD UNIQUE KEY (username); -- optional
Update the child tables to contain the relevant userid from the parent:
UPDATE foo JOIN usernames USING (username)
SET foo.userid = usernames.userid;
Add the new foreign key constraints and drop the old username columns from the child tables:
ALTER TABLE foo
ADD FOREIGN KEY (userid) REFERENCES usernames (userid),
DROP COLUMN username;