How to drop a column with foreign key in MySQL? - mysql

Let's say I used the following structure to create a table:
CREATE TABLE staff (
sid INT AUTO_INCREMENT,
sfname VARCHAR(30) NOT NULL,
slname VARCHAR(30) NOT NULL,
uid int UNIQUE,
bid int NOT NULL,
PRIMARY KEY (sid),
FOREIGN KEY (uid) REFERENCES sajilo_user(uid),
FOREIGN KEY (bid) REFERENCES branch(bid)
);
Now I want to add DELETE CASCADE for the foreign key and I found that I can achieve it by dropping the column(column with foreign key) and adding it again with DELETE CASCADE property on alter table statement.
But when I tried:
ALTER TABLE staff DROP column uid;
I got error: #1553 - Cannot drop index 'u_user': needed in a foreign key constraint.
So I need to remove foreign key constraint first with:
ALTER TABLE staff DROP FOREIGN KEY foreign_key_constraint_name;
As you saw above table was created without giving the name for constraint. I am having trouble to drop it. So what should be done ?
I need the way of dropping the column along with foreign key constraint:)

Finally, I found the solution, We can use information_schema to retrieve the name of a foreign key and can use the name event constraint name is not set explicitly as shown above.
As of MySQL docs:
INFORMATION_SCHEMA provides access to database metadata, information about the MySQL server such as the name of a database or table, the data type of a column, or access privileges. Other terms that are sometimes used for this information are data dictionary and system catalog.
For more information visit: https://dev.mysql.com/doc/refman/8.0/en/information-schema.html
So we can do something like:
USE information_schema;
SELECT * FROM `INNODB_SYS_FOREIGN_COLS`;
Where INNODB denotes a storage engine, for more information visit:
https://dev.mysql.com/doc/refman/8.0/en/storage-engines.html
After executing the query we can get the result something like:
ID FOR_COL_NAME REF_COL_NAME POS
---------------------------------- ------------ ------------ --------
acdb/takes_ibfk_1 sid sid 0
acdb/takes_ibfk_2 cid cid 0
sajilo_courier/admin_branch_ibfk_1 aid aid 0
sajilo_courier/admin_branch_ibfk_2 bid bid 0
sajilo_courier/admin_ibfk_1 uid uid 0
sajilo_courier/admin_staff_ibfk_1 aid aid 0
sajilo_courier/admin_staff_ibfk_2 sid sid 0
sajilo_courier/staff_ibfk_1 uid uid 0
As we can see in the ID contains the name of database/foreign key name so finally we can do something like
ALTER TABLE staff DROP FOREIGN KEY staff_ibfk_1 ;
From last row and finally we can drop the column easily :)

Related

Can there be a 1 to 1 relationship for keys with multiple fields?

I am creating web-app for database management. Database can be created using diagrams ER.
Here is screen from my app:
As you can see this pseudo example shows 4x types of cases:
1) Primary key --> Primary key (1:1)
2) Unique key --> Unique key (1:1)
3) Primary key consisting of two fields --> Primary key consisting of two fields (1:1)
4) Unique key consisting of two fields --> Unique key consisting of two fields (1:1)
And here is my question:
Is it all true? I wonder about these double keys... Is this really a 1 to 1 relation?
Generally, I wonder about these first 2 cases too. Are there also true?
MySQL Workbench shows it is not true:
I dont know why but you can see MySQL Workbench shows this is one to many relation...
Oracle Sql Developer:
Can anyone tell me when 1 to 1 relationship actually is?
Documentation shows i have right:
https://docs.oracle.com/cd/E26180_01/Platform.94/RepositoryGuide/html/s1204onetoonewithauxiliarytable01.html
but diagrams ER in MySQL Workbench and Sql Developer shows something different...
SQL code from that tables:
CREATE USER "Student" IDENTIFIED BY "null";
CREATE TABLE "Student".Table1 (
PK_FK NUMBER NOT NULL
);
CREATE TABLE "Student".Table2 (
PK NUMBER NOT NULL
);
CREATE TABLE "Student".Table3 (
PK NUMBER NOT NULL,
UK_FK NUMBER
);
CREATE TABLE "Student".Table4 (
PK NUMBER NOT NULL,
UK NUMBER
);
CREATE TABLE "Student".Table5 (
PK_1_FK NUMBER NOT NULL,
PK_2_FK NUMBER NOT NULL
);
CREATE TABLE "Student".Table6 (
PK_1 NUMBER NOT NULL,
PK_2 NUMBER NOT NULL
);
CREATE TABLE "Student".Table7 (
UK_1_FK NUMBER,
UK_2_FK NUMBER
);
CREATE TABLE "Student".Table8 (
UK_1 NUMBER,
UK_2 NUMBER
);
ALTER TABLE "Student".Table1 ADD CONSTRAINT Table1_PK PRIMARY KEY (PK_FK);
ALTER TABLE "Student".Table2 ADD CONSTRAINT Table2_PK PRIMARY KEY (PK);
ALTER TABLE "Student".Table3 ADD CONSTRAINT Table3_PK PRIMARY KEY (PK);
ALTER TABLE "Student".Table4 ADD CONSTRAINT Table4_PK PRIMARY KEY (PK);
ALTER TABLE "Student".Table5 ADD CONSTRAINT Table5_PK PRIMARY KEY (PK_1_FK, PK_2_FK);
ALTER TABLE "Student".Table6 ADD CONSTRAINT Table6_PK PRIMARY KEY (PK_1, PK_2);
ALTER TABLE "Student".Table3 ADD CONSTRAINT Table3_UK1 UNIQUE (UK_FK);
ALTER TABLE "Student".Table4 ADD CONSTRAINT Table4_UK2 UNIQUE (UK);
ALTER TABLE "Student".Table7 ADD CONSTRAINT Table7_UK3 UNIQUE (UK_1_FK, UK_2_FK);
ALTER TABLE "Student".Table8 ADD CONSTRAINT Table8_UK4 UNIQUE (UK_1, UK_2);
ALTER TABLE "Student".Table1 ADD CONSTRAINT Table1_FK1 FOREIGN KEY (PK_FK)
REFERENCES "Student".Table2 (PK);
ALTER TABLE "Student".Table3 ADD CONSTRAINT Table3_FK2 FOREIGN KEY (UK_FK)
REFERENCES "Student".Table4 (UK);
ALTER TABLE "Student".Table5 ADD CONSTRAINT Table5_FK3 FOREIGN KEY (PK_1_FK, PK_2_FK)
REFERENCES "Student".Table6 (PK_1, PK_2);
ALTER TABLE "Student".Table7 ADD CONSTRAINT Table7_FK4 FOREIGN KEY (UK_1_FK, UK_2_FK)
REFERENCES "Student".Table8 (UK_1, UK_2);
That's perfectly possible. Here's an example for PostgreSQL:
create table t1 (
a int not null,
b int not null,
constraint uq1 (a, b),
constraint fk1 foreign key (a, b) references t2 (a, b)
deferrable initially deferred
);
create table t2 (
a int not null,
b int not null,
constraint uq2 (a, b),
constraint fk2 foreign key (a, b) references t1 (a, b)
deferrable initially deferred
);
In this case t1 (a,b) is unique and references t2 (a, b) that is also unique. That's a 1:1 relationship using "composite keys".
Note: This example uses "circular references" that is a standard part of SQL, but is only implemented [to my knowledge] by PostgreSQL and Oracle. It won't run in MySQL.
A one-to-one relationship is still a master-detail relationship. One table is the owner of the identifier and the other table references it through a foreign key. This is the relationship show in the MySQL Workbench and SQL Developer pictures.
Documentation shows i have right:
You link to Oracle's documentation for ATG Repository, which is a specialist tool for representing data generically, but even there we can see from the SQL that USER_TBL is the primary table and "owns" the ID column and JOB_TBL is the auxiliary table and references the ID.
CREATE TABLE usr_tbl (
id VARCHAR(32) not null,
nam_col VARCHAR(32) null,
age_col INTEGER null,
primary key(id)
);
CREATE TABLE job_tbl (
id VARCHAR(32) not null references usr_tbl(id),
function VARCHAR(32) null,
title VARCHAR(32) null,
primary key(id)
In other words, we can have a USER without a JOB but we can't have a JOB without a USER. But a USER can have only one JOB and one JOB belongs only to ONE user.
Your diagram is wrong because it renders TABLE7 and TABLE8 as peers. But foreign keys don't work like that. One table defer to the other. When I look at your notation I can't see whether TABLE8 owns TABLE7 or TABLE7 owns TABLE8. Whereas, it's quite clear in the MySQL and Oracle diagrams. The purpose of a data model is to clarify the database design not obfuscate it.
Note, it is perfectly possible to define two tables which have foreign keys that reference each other's primary key. The trick is insert data into them. This requires deferring the foreign key constraints. I view deferred constraints as a red flag, a sign of a broken data model.

how to use sql foreign keys

After googling about foreign keys, this is the way i understood them.
If i need to save the phone-no of people in a table with address, it will create multiple records for a single person as he can have multiple numbers. that will also store redundant address values in each repeated row. so using the user-id as foreign key, i can phone-no to another table and save the address from being repeated. So my question is if a user is deleted from the user table with address, will it also automatically remove all associated values in phone table? Or that has to be specified at the time of creating the table that deleting this will delete that? also what happens if user-id is changed only in first table and when it is changed in only 2nd table.
If i have 2 tables
table: user
+-----------------------------+
|user-id | username | address |
+-----------------------------+
table: phone-no
+--------------------------+
| pid | phone-no | user-id |
+---------------------------
Also, if it is not too much, can you show me the query for creating both of this with foreign keys.
User-id from table user would be the primary key, and user-id in the table phone-no would be the foregin key referencing user-id in user table.
create table user(
userid int identity(1,1) not null primary key,
username varchar(50) not null,
adress varchar(200) not null,
);
create table phone-no(
pid int identity(1,1) not null primary key,
phone-no int not null,
user-id int not null foreign key (userid) references user(userid) on delete cascade,
);
On delete cascade option is optional, hope you understand what i meant by that.
Your design is correct. Here's MySQL documentation for foreign key syntax, for your table, it will look something like this:
CONSTRAINT fk_user_id FOREIGN KEY (user-id)
REFERENCES user(user-id)
ON DELETE CASCADE
Here, ON DELETE CASCADE will make sure the phone record gets deleted when user is deleted. If you want to perform a different action, (e.g. set user-id to null and don't delete record), you can use SET NULL. Have a look at Referential Actions section of the above documentation.

MYSQL: foreign key error

I am getting some foreign key error while adding one. I have:
CREATE TABLE PRODUCT_1( PROD_ID NUMERIC(5) NOT NULL PRIMARY KEY,
PROD_NAME CHAR(20),
PROD_DESC CHAR(20),
PROD_PRICE NUMERIC(20),
SIZE_ID NUMERIC(5) NOT NULL,
PROD_CAT_ID CHAR(5));
CREATE TABLE SIZE(
SIZE_ID NUMERIC(5) NOT NULL PRIMARY KEY,
SIZE_SMALL CHAR(2),
SIZE_MEDIUM CHAR(2),
SIZE_LARGE CHAR(2));
I am trying to add foreign key using:
alter table SIZE
add foreign key(SIZE_ID) references PRODUCT_1(SIZE_ID)
BUT I get the following errors:
ERROR 1005 (HY000): Can't create table './mmmm/#sql-842_33e1.frm' (errno: 150)
However, If I go the other way round like:
alter table PRODUCT_1
add foreign key(SIZE_ID) references SIZE(SIZE_ID)
This works fine, I am unable to add any data to it where it gives me error like "cannot update child table".
Any help is appreciated!
That is correct. SIZE_ID is a "foreign key" in PRODUCT_1, because it is the "primary key" of the SIZE table. Trying to add a foreign key constraint to SIZE does not make any sense.
If you run SHOW INNODB STATUS you'll get some information indicating that you don't have the required index, however, logically, there is no reason to try and create that constraint.
You do however want to create the constraint on PRODUCT_1. At that point, you will only be able to enter SIZE_ID values in PRODUCT_1 that already exist in SIZE, as that is a typical "lookup table" design.
PRODUCT_1.SIZE_ID is in this example the foreign key, as it references the primary key of the other table, SIZE.
Therefore, the second ALTER TABLE statement is correct as it is a property of the PRODUCT_1 table.
Now, before you insert any rows into PRODUCT_1 table, you should make sure that table SIZE already has a record with the SIZE_ID referenced in your new row. If the database finds that you are trying to insert a row with a SIZE_ID that does not exist in the SIZE table, you violate the FOREIGN KEY constraint, and it will disallow you.

Working with foreign keys - cannot insert

Doing my first tryouts with foreign keys in a mySQL database and are trying to do a insert, that fails for this reason: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails
Does this mean that foreign keys restrict INSERTS as well as DELETES and/or UPDATES on each table that is enforced with foreign keys relations?
Thanks!
Updated description:
Products
----------------------------
id | type
----------------------------
0 | 0
1 | 3
ProductsToCategories
----------------------------
productid | categoryid
----------------------------
0 | 0
1 | 1
Product table has following structure
CREATE TABLE IF NOT EXISTS `alpha`.`products` (
`id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT ,
`type` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 ,
PRIMARY KEY (`id`) ,
CONSTRAINT `funkyfunky`
FOREIGN KEY (`id` )
REFERENCES `alpha`.`ProductsToCategories` (`productid` )
ON DELETE CASCADE,
ON UPDATE CASCADE)
ENGINE = InnoDB;
Your insert is failing because the foreign key in the row you are inserting doesn't match a valid key in the constraint table. For example:
Assume you've got these two tables:
Employees
----------------------------
EmpID | Name
----------------------------
0 | John
1 | Jane
OfficeAssignments
----------------------------
OfficeID | EmpID
----------------------------
0 | 0
1 | 1
If you have a foreign key constraint on OfficeAssignments.EmpID -> Employees.EmpID, and you try to execute:
INSERT INTO OfficeAssignments (OfficeID, EmpID) VALUES (2,2)
The statement will fail because there is no entry in the Employees table with an EmpID of 2.
Constraints are designed to ensure that your dependent table always has valid data with regard to the parent table -- in this example, you will never have an office which is listed as assigned to an employee who doesn't exist in the system, either because they never existed (as in this case) or because they've been deleted (because the constraint will prevent the employee record from being deleted until the office assignment record has been deleted first).
Edit: Now that you've posted the constraint, it indeed looks like it might be set up backwards. By placing the constraint in the definition of the Products table, you are making it the child, and ProductsToCategories the parent. The constraint you've written can be read as, "a Product must be assigned to a category before it can be created". I suspect what you meant is the other way around: "a Product must be created before it can be assigned to a category." To get that result, you need to place the constraint on the ProductsToCategories table, setting the foreign key to productid and referencing Products.id.
You cannot delete a row from the parent table while there is a foreign key reference to it from a child table. Also you cannot insert/update in the child table with invalid id's in the foreign key column.
Edit: The "CONSTRAINT funkyfunky FOREIGN KEY (id)" must be declared in the "ProductsToCategories" table not in the "Products" table, because "ProductsToCategories" is referencing "Products" not the opposite as you have did.
Your products table is slightly wrong, as you don't need to reference anything from it. References go in the "other" tables, and point to the main, e.g:
create table products (
id int auto_increment,
type int,
primary key (id)
);
create table categories (
id int auto_increment,
name varchar(128),
primary key (id)
)
create table products_to_categories (
product_id int references products,
category_id int references categories
);
A foreign key enforces a valid relation between the rows in two tables. In order to be able to insert a row into a table containing a foreign key, there must be a row in the referenced table containing that key or the insert will fail. The same with delete, you can't delete the row in the referenced table while there are still rows in the table with the foreign key that still reference it. The prevents ending up with rows in the dependent table that have data, but don't have associated rows in the referenced table, i.e., a violation of referential integrity.

mysql ( innodb )foreign key constraints problems

I am running into a couple of issues while trying to generate foreign keys for my tables in MySql(Innodb). Can you please help me with them ?
Referenced tables :
*create table entity
{
PID INT(20) auto inc not null,
ENTITYID INT(20) not null,
details VARCHAR(100) not null,
primary key(PID,ENTITYID)
}
create table user
{
USERID int(20) auto inc not null,
NAME VARCHAR(45) not null,
joindate DATETIME not null,
location VARCHAR(100) not null,
primary key(USERID,NAME) not null
}*
Referencing table:
*create table C
{
ENTITYID INT(20) not null,
NAME VARCHAR(45) not null,
foreign key ENTITYID_C constraint ENTITYID references entity(ENTITYID) on delete cascade,
foreign key name_C constraint NAME references user(NAME) on delete cascade,
primary key(ENTITYID,NAME)
}*
I need 2 foreign keys in table C because the entry in C must be deleted when either the corresponding entity or corresponding user is deleted.
When i try to create table C I run into a error: ERROR 1005: Can't create table (errno: 150) . I suspect this is because I am not adhering to rules laid down in the mysql spec.
http://dev.mysql.com/doc/refman/5.4/en/innodb-foreign-key-constraints.html
What does the below portion/rule of the spec mean ?
"InnoDB 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."
Does it mean that the foreign keys in table C need to correspond to primary keys in entity and user tables such that the ENTITYID in entity table must be the first in the primary key and NAME in user table must be first in the primary key.
In other words should my primary key declarations be rewritten as below ?
entity table --> primary key(ENTITYID,PID) ,
user table --> primary key(NAME,USERID)
If so , when i attempt to reorder the key declarations as above I run into error 1075.
"Incorrect table definition, there can be only one auto column and it must be defined as a key."
How can I make the auto incremented key ( the surrogate key ) to be second in the index order list so that I am in accordance with the spec ?
Thank you !
I don't think your primary keys for entity and user are correct. I believe you have primary key and indexes mixed up.
You have auto increment columns for both tables. I think those should be the primary keys - PID for ENTITY, USERID for USER. If you query for ENTITY using ENTITYID, or USER using NAME, by all means create indexes for both.
Now table C defines a many-to-many relationship between ENTITY and USER. There are two columns in C that point to PID and USERID, with foreign keys for each. The primary key on C is just the combination of the two.
Like this:
create table entity
{
pid int(20) auto inc not null,
primary key(pid)
};
create table user
{
userid int(20) auto inc not null,
primary key(userid)
};
create table user_entity
{
entity_id int(20) not null,
user_id int(20) not null,
primary key(entity_id, user_id)
foreign key entity_id references entity(pid) on delete cascade,
foreign key user_id references user(userid) on delete cascade
};
Ollie Saunders is correct.
Before you drop/create InnoDB tables, drop all the constraints first.
ALTER TABLE tbl_name
ADD [CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (index_col_name, ...)
REFERENCES tbl_name (index_col_name,...)
[ON DELETE reference_option]
[ON UPDATE reference_option]
source: Alter table syntax
Whenever I did this I definitely, definitely found that it's better to define all the tables first and then apply the constrains with separate ALTER queries later. You avoid so many "I need this table to exist first" problems and the like.