I am trying to use ON DELETE CASCADE for a database I'm working on. Didn't seem to work so I tested it out on a simple example with no success.
CREATE TABLE foo (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data VARCHAR(10),
PRIMARY KEY (id)
)ENGINE=InnoDB;
CREATE TABLE foo2 (
id INT UNSIGNED NOT NULL,
data2 VARCHAR(10),
PRIMARY KEY (id),
CONSTRAINT fk_foo2_id FOREIGN KEY (id) REFERENCES foo(id) ON DELETE CASCADE
)ENGINE=InnoDB;
INSERT INTO foo (data) VALUE ('hello'),('world'),('mysql');
INSERT INTO foo2 (data2) VALUE ('hello2'),('world2'),('mysql2');
SELECT * FROM foo;
+----+-------+
| id | data |
+----+-------+
| 1 | hello |
| 2 | world |
| 3 | mysql |
+----+-------+
3 rows in set (0.00 sec)
SELECT * FROM foo2;
+----+--------+
| id | data2 |
+----+--------+
| 1 | hello2 |
| 2 | world2 |
| 3 | mysql2 |
+----+--------+
3 rows in set (0.00 sec)
DELETE FROM foo WHERE id=2;
SELECT * FROM foo;
+----+-------+
| id | data |
+----+-------+
| 1 | hello |
| 3 | mysql |
+----+-------+
2 rows in set (0.00 sec)
SELECT * FROM foo2;
+----+--------+
| id | data2 |
+----+--------+
| 1 | hello2 |
| 2 | world2 |
| 3 | mysql2 |
+----+--------+
3 rows in set (0.00 sec)
I can't for the life of me figure out why this isn't working. I looked at similar questions and answers on here and I did exactly what they said and it still didn't work. Most of them just said to change to ENGINE=InnoDb, but I tried it and no success.
There must be something I'm missing here, and it's probably very obvious.. Monday mornings.
If anyone can shed some light on this little noob problem of mine, I would greatly appreciate it!
Edit: removed the auto_increment from id in foo2 as it did not belong there
The first thing that pops to mind is to check the setting of the foreign_key_checks variable. If that's set to 0 (FALSE), then foreign key constraints are NOT enforced.
SHOW VARIABLES LIKE 'foreign_key_checks'
To enable foeign key constraints, set to the variable to 1
SET foreign_key_checks = 1;
NOTE: this affects only the current session. New sessions inherit the GLOBAL setting.
Also, verify that your tables are actually using the InnoDB engine, and that the foreign keys are defined. Easiest way is to get the output from:
SHOW CREATE TABLE foo;
SHOW CREATE TABLE foo2;
FOLLOWUP
This is something that we expect NOT to be broken in MySQL 5.1.61.
As a workaround, try defining the foreign key constraint as a separate ALTER TABLE statement.
ALTER TABLE foo2
ADD CONSTRAINT fk_foo2_id FOREIGN KEY (id) REFERENCES foo(id) ON DELETE CASCADE ;
I don't see much use in a foreign key constraint between two columns that are both defined with "auto_increment". In your example, you could easily create several rows in table "foo" (without a counterpart in "foo2"), and from then onwards you could not control whether "id" values in both tables match.
I admit I didn't check the documentation, but it would not surprise me if MySQL silently ignored a foreign key constraint for an auto-generated column.
IMNSHO, your table "foo2" should use "id" values which are set explicitly and reference specific rows in "foo", because then it would make sense that deleting such "foo" rows should cascade onto "foo2".
Related
Is there any option (or even DB client) to require a confirmation when deleting a row for CASCADE deletes. For example:
DELETE FROM catalogs WHERE id=1
Warning: this will also DELETE CASCADE 92,358 products and 142 catalog_histories. Are you sure? (If so, temporarily turn on ALLOW_CASCADE_DELETES or add WITH CASCADES to query)
I will prefer a solution that doesn't require following particular rules in db schema and works with MySQL. (Alternatively if there is a way to force FK deletes while leaving CASCADE off schema in general then this will also be a good option.)
You can't do that in mysql
i tried it a bit https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=b6575f084b486025a66f6d52a4df9893
but the foreign key restaont has to be enable before you start to delete the row like in the example
So you must run two codes one with SET FOREIGN_KEY_CHECKS
CREATE TABLE catalogs(id int PRIMARY KEY);
INSERT INTO catalogs VALUES (1),(2);
CREATE TABLE catalogs_sub(id int, cat_id int,
FOREIGN KEY (cat_id)
REFERENCES catalogs( id)
ON DELETE CASCADE
)
INSERT INTO catalogs_sub VALUES (1,1),(2,1),(3,2),(4,2)
SELECT * FROM catalogs_sub
id | cat_id
-: | -----:
1 | 1
2 | 1
3 | 2
4 | 2
SET FOREIGN_KEY_CHECKS=0;
DELETE FROM catalogs WHERE id=1;
SET FOREIGN_KEY_CHECKS=1;
SELECT * FROM catalogs
| id |
| -: |
| 2 |
SELECT * FROM catalogs_sub
id | cat_id
-: | -----:
1 | 1
2 | 1
3 | 2
4 | 2
DELETE FROM catalogs WHERE id=2;
SELECT * FROM catalogs
| id |
| -: |
SELECT * FROM catalogs_sub
id | cat_id
-: | -----:
1 | 1
2 | 1
db<>fiddle here
I have a many-to-many table with UserId and TaskId
When I add data to the table I can add the same UserId and TaskId more than once.
I use the following query to add the data:
Create table if not exists user_task(UserId INT, FOREIGN KEY (UserId)
REFERENCES USERS(id), TaskId INT, FOREIGN KEY (TaskId) REFERENCES TASKS(id));
How can I prevent adding duplicates of those in the table?
+-----------------+
| UserId | TaskId |
+-----------------+
| 1 | 1 |
| 2 | 1 |
| 1 | 1 |
+---------+-------+
I know I can put DISTINCT in the SELECT query to get the data without duplicates but it doesn't prevent from being added to the table.
You can use Unique Index Constraint
Basically it will check for duplicates (upon one column or groups of columns) and stops insert/update operations if constraint would break.
If you're interested in how to deal with this, check out the manual
ALL,
igor#IgorDellGentoo ~ $ isql myodbc-5.2-test root wasqra
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL> use draft;
SQLRowCount returns 0
SQL> ALTER TABLE owners ADD FOREIGN KEY id REFERENCES leagues(id);
[ISQL]ERROR: Could not SQLExecute
SQL>
What am I doing wrong?
Also, for some reason I can't create a foreign key thru the mySQL-Workbench when creating the table.
There is no "Add" button or "+" sign to add this constraint. And there is no reaction on the right click.
Could someone please point me to the right direction?
I have Workbench version 6.3.4.0 on Gentoo Linux.
SQL> show tables;
+-----------------------------------------------------------------+
| Tables_in_draft |
+-----------------------------------------------------------------+
| leagues |
| owners |
+-----------------------------------------------------------------+
SQLRowCount returns 2
2 rows fetched
SQL> SELECT * FROM leagues;
+-----------+-----------------------------------------------------------------------------------------------------+-----------+------------+-----------+-----------+-----------+-------------+
| id | name | drafttype | scoringtype| roundvalue| leaguetype| salary | benchplayers|
+-----------+-----------------------------------------------------------------------------------------------------+-----------+------------+-----------+-----------+-----------+-------------+
+-----------+-----------------------------------------------------------------------------------------------------+-----------+------------+-----------+-----------+-----------+-------------+
seems you are using id as a foreign key use proper column instead
ALTER TABLE owners
ADD COLUMN FOREIGNID INT NOT NULL;
ALTER TABLE owners
ADD FOREIGN KEY (FOREIGNID) REFERENCES leagues(ID);
Suppose a table contains data like
MariaDB [c]> select * from t2;
+-----+
| abc |
+-----+
| 1 |
| 3 |
| 5 |
+-----+
Suppose my update command is
MariaDB [c]> update t2 set abc = abc+2;
It give following error
ERROR 1062 (23000): Duplicate entry '3' for key 'PRIMARY'
While the above command works fine in oracle 10g, Is it some kind of bug or what?
The following is just an illustration and trivial.
create table t2
( id int auto_increment primary key,
abc int not null,
unique key(abc)
);
insert t2(abc) values (1),(3),(5); -- 3 rows added
update t2 set abc = abc+2; -- Error Code 1062: Duplicate entry '3' for key 'abc'
The above error occurred because the update marched in the order of the primary key, also the physical ordering, and changing the 1 to a 3 violated the 3 that was already in place via the unique key. The fact that the end state would make every thing OK, ideally, doesn't keep it from failing at that moment.
To illustrate this working in this highly rigged example knowing there is no other data:
truncate table t2; -- the data wasn't modified but for the paranoid, clear and re-insert
insert t2(abc) values (1),(3),(5); -- 3 rows added
Try it bottom up (so that the Unique constraint is not violated):
update t2 set abc = abc+2 order by abc desc;
select * from t2;
+----+-----+
| id | abc |
+----+-----+
| 1 | 3 |
| 2 | 5 |
| 3 | 7 |
+----+-----+
It leverages the ability to have an order by in an update statement.
So it comes down to knowing your data and what you can get away with. Saying it worked on Oracle as you did in comments is on another db platform and with some other schema. So that is mute.
I have just started working with MySQL and have a quick question. I would like to create a table "My_Table" that has a field "SEX". I would also like to create a table "SEX_Values" which has fields "CODE" and "VALUE" with 0 = male, 1 = female. so that it looks like this.
My_Table SEX_Values
+--------+ +--------+--------+
| SEX | | CODE | VALUE |
+--------+ +--------+--------+
| | | 0 | male |
+--------+ +--------+--------+
| 1 | female |
+--------+--------+
I would like to somehow put a constraint on the SEX field in My_Table so that the data that is inserted/imported into it must match one of the codes in the SEX_Values table and if it doesn't I would like to throw a warning, something like this.
My_Table SEX_Values
+--------+ +--------+--------+
| SEX |<reference>| CODE | VALUE |
+--------+ +--------+--------+
| 1 | >OK | 0 | male |
+--------+ +--------+--------+
| 0 | >OK | 1 | female |
+--------+ +--------+--------+
| 0 | >OK
+--------+
| 3 | >Throws Warning
+--------+
Any help would be greatly appreciated as I have not used SQL much before.
What you describe is known as a FOREIGN KEY.
Essentially, it ensures referential integrity - in other words, you can't insert anything that doesn't exist in the referenced table, nor can you delete anything from the referenced table that still exists in the main one.
So, in your case you couldn't insert Hermaphrodite into My_Table without it being present in SEX_Values, nor could you remove male from SEX_Values, if there were still a male in My_Table.
CREATE TABLE SEX_Values
(
`CODE` INT NOT NULL,
`VALUES` VARCHAR(10),
PRIMARY KEY (`CODE`) -- !!
);
CREATE TABLE My_Table
(
SEX INT,
FOREIGN KEY (SEX) REFERENCES SEX_VALUES(`CODE`) -- !!
);
Why not use an enum type?
You can create the table with
CREATE TABLE my_table(
sex enum("male", "female") NOT NULL
);
That way you can insert like so:
INSERT INTO my_table(`sex`) VALUES("male")
You have the syntactical advantage of using strings (I think this is a lot more clear than using numeric codes), MySQL will optimize the database as if you were using the codes, and it will enfor.
A very simple solution is to set the datatype of the sex column to bit, that accepts only 0, 1 or null values (MSDN ref.).
Set also the NOT NULL constraint in the filed definition, in order to exclude NULL values as well.