delete in adjacency table - php

I have an adjacency table with parent and child elements and when I delete my parent element I would like to delete all his child.
My table:
id name parent
1 Name1 null
2 SubName1 1
When I'm trying to delete row with id=1 I would like to delete and id=2
How can I do this?
My table:
CREATE TABLE IF NOT EXISTS `cats` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`parent` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `parent` (`parent`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

Foreign keys could be the solution.
How you create them is dependent on your used Database.
At foreign keys there is a primary key defined which is like a "parent", if the parent gets deleted the childs get deleted to if you define it.

Related

Generating a select query from a generalized and specialized tables

So I have a generalised table called beneficiaries which gives the specialised table parent and child. So parent and child table reference a beneficiary id. However, child table references a parent beneficiary id. Now my struggle is I want to write a query which returns the name of the child from the beneficiary and the name of the parent from the beneficiary while showing which parent a child belongs to. I wrote this query:
select * from beneficiaries
inner join child on beneficiaries.bene_id = child.ParentBene_id
inner join parent on beneficiaries.bene_id = parent.parentBene_id;
But the results I get is just the parent name and the id for the child.
Structure of Tables
Beneficiaries table
Child Table
Parent Table
Your query looks great. I created some tables with sample data and this is my result.
Maybe you forgot to declare the foreigns keys when creating the tables?
Here is the commands I used to create your tables in MySQL:
Beneficiaries table:
CREATE TABLE `beneficiaries` (
`bene_id` int(11) NOT NULL,
`kayacare_id` int(11) DEFAULT NULL,
`fname` tinytext,
`mname` tinytext,
`lname` tinytext,
`location` tinytext,
`dob` tinytext,
`sex` varchar(1) DEFAULT NULL,
PRIMARY KEY (`bene_id`)
)
Child table:
CREATE TABLE `child` (
`bene_id` int(11) DEFAULT NULL,
`parentBene_id` int(11) DEFAULT NULL,
`healthWorker_id` int(11) DEFAULT NULL,
`careGiver_id` int(11) DEFAULT NULL,
KEY `parentBene_id` (`parentBene_id`),
FOREIGN KEY (parentBene_id) REFERENCES beneficiaries(bene_id)
)
Parents table:
CREATE TABLE `parent` (
`parentBene_id` int(11) DEFAULT NULL,
`phone` int(11) DEFAULT NULL,
KEY `parentBene_id` (`parentBene_id`),
FOREIGN KEY (parentBene_id) REFERENCES beneficiaries(bene_id)
)
Here you can see how to edit a foreign key in MySQL.
To get the results I wanted I used this query:
select * from child
right join beneficiaries on child.bene_id = beneficiaries.bene_id
inner join (select parentBene_id,fname as pfname, mname as pmname, lname as plname, phone from
parent inner join beneficiaries on parent.parentBene_id = beneficiaries.bene_id)
parent on child.parentBene_id = parent.parentBene_id;

One to many relationship in SQL - foreign key error

I am trying to create a campus structure. So buildings have floors, floors have rooms. I am trying to create a relational database such that multiple rooms relate to one floor and multiple floors relate to their building.
Here is my structure for the building and floor tables:
CREATE TABLE `building` (
`id` int(11) NOT NULL,
`name` varchar(128) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE TABLE `floor` (
`id` int(11) NOT NULL,
`building_id` int(11) DEFAULT NULL,
`level` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `floor_building_id__fk` (`building_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
I want to insert more than one floor in the floor table relating to the same building_id using:
INSERT INTO `floor` SET id=3, `number` = 420, building_id=(SELECT id FROM building WHERE id=2);
However I keep getting the following error:
Error Code: 1452. Cannot add or update a child row: a foreign key constraint fails (`seatspace`.`floor`, CONSTRAINT `building_id` FOREIGN KEY (`id`) REFERENCES `building` (`id`))
I want to insert, update and delete floors relating to their specified building_id. Any help would be appreciated.
I have fixed the problem by changing the constraint name for the foreign key. I also rewrote parts of the schema so all of the desired columns were present. Here is the final schema and CRUD.
CREATE TABLE `floor` (
`floor_id` int(11) NOT NULL AUTO_INCREMENT,
`number` int(11) NOT NULL,
`building_id` int(11) NOT NULL,
PRIMARY KEY (`floor_id`),
UNIQUE KEY `floor_id_UNIQUE` (`floor_id`),
KEY `building_id_idx` (`building_id`),
CONSTRAINT `building_id` FOREIGN KEY (`building_id`) REFERENCES `building`
(`building_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
INSERT INTO `floor` (floor_id, `number`, building_id) VALUES (default, 3,
(SELECT building_id FROM building WHERE building_id=2)) ;
UPDATE `floor` SET `number`=3, building_id=1 WHERE floor_id=2;
DELETE FROM `floor` WHERE floor_id=3;
CREATE TABLE `building` (
`building_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`building_id`),
UNIQUE KEY `building_id_UNIQUE` (`building_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
INSERT INTO building (building_id, name) VALUES (DEFAULT, '1 West');
UPDATE `building` SET `name`='3 West' WHERE building_id=2;
DELETE FROM `building` WHERE building_id=2;

Get the value when a MySQL constraint fails

Assuming I am inserting rows in a MySQL table with a constraint
CREATE TABLE `parent` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
;
CREATE TABLE `child` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_parent` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
INDEX `FK_parent_child` (`id_parent`),
CONSTRAINT `FK_parent_child` FOREIGN KEY (`id_parent`) REFERENCES `parent` (`id`),
)
ENGINE=InnoDB
;
Then when I do an insert in the child table without the entry in the parent table:
INSERT INTO child (id, id_parent) VALUES (1, 1);
I get the following error:
Cannot add or update a child row: a foreign key constraint fails (`...`.`child`, CONSTRAINT `FK_parent_child` FOREIGN KEY (`id_parent`) REFERENCES `parent` (`id`))`
But is there a way to retrieve the value of the insert-failed row, aka 1 here? Because when I insert thousands of rows at the same time, it would be very useful to get the failed one.
I would like a fully-MySQL way, but a PHP way would work too in my case.

MySQL innoDB foreign key delete cascade from three tables

I have a MySQL database with several tables, connected with linking tables. My problem was that DELETE statements were very complicated. So in an attempt to make them simpler I tried setting up foreign keys with cascade deletes.
Here is my table structure
--------------
-n_size_class-
--------------
-s_id -
-s_name -
--------------
-------------
-n_size_rows-
-------------
-sr_id -
-sr_name -
-sr_value -
-------------
----------------
-n_size_columns-
----------------
-sc_id -
-sc_name -
-sc_value -
----------------
-----------------
-n_size_row_link-
-----------------
-srl_id -
-srl_size -
-srl_row -
-----------------
-----------------
-n_size_col_link-
-----------------
-scl_id -
-scl_size -
-scl_col -
-----------------
The idea is that the n_size_class table is the primary object (a size class) and then the rows and columns are children of the size class. The linking tables are then used to tie rows and columns to the size class. Previously, my inserts worked fine and deletes were a problem. Now that I tried setting up delete cascades, my inserts are broken (but my deletes work fine). My goal is to make inserts work properly, where size_class is inserted, then for each row, it is inserted into size_row and then also inserted into size_row_link, and the same for columns. Then when you delete just the size_class, all links and rows and columns are deleted as well.
What is the proper way to foreign key/cascade these tables? Right now, I get a foreign key constraint error when I try to insert anything into the columns or row table.
As per request, the create statements:
CREATE TABLE `n_size_class` (
`s_id` int(11) NOT NULL auto_increment,
`s_name` text NOT NULL,
PRIMARY KEY (`s_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE `n_size_columns` (
`sc_id` int(11) NOT NULL auto_increment,
`sc_name` text NOT NULL,
`sc_value` text NOT NULL,
PRIMARY KEY (`sc_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE `n_size_rows` (
`sr_id` int(11) NOT NULL auto_increment,
`sr_name` text NOT NULL,
`sr_value` text NOT NULL,
PRIMARY KEY (`sr_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE `n_size_row_link` (
`srl_id` int(11) NOT NULL auto_increment,
`srl_size` int(11) NOT NULL,
`srl_row` int(11) NOT NULL,
PRIMARY KEY (`srl_id`),
KEY `srl_row` (`srl_row`),
KEY `srl_size` (`srl_size`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE `n_size_col_link` (
`scl_id` int(11) NOT NULL auto_increment,
`scl_size` int(11) NOT NULL,
`scl_col` int(11) NOT NULL,
PRIMARY KEY (`scl_id`),
KEY `scl_col` (`scl_col`),
KEY `scl_size` (`scl_size`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
The way I see it you have 3 objects in play: Sizes, Rows, and Columns.
I'm assuming:
That the linking tables are because a Size can be assigned to many Rows/Columns, and Rows/Columns can have many Sizes.
That when a Size is deleted the assignments should be deleted, no the Rows/Columns themselves.
That when a Row/Column is deleted the assignments should be deleted, not the Sizes themselves.
So:
CREATE TABLE sizes (
size_id INTEGER UNSIGNED AUTO_INCREMENT,
size_name VARCHAR(255),
...
PRIMARY KEY(size_id)
);
CREATE TABLE rows (
row_id INTEGER UNSIGNED AUTO_INCREMENT,
...
PRIMARY KEY(row_id)
);
CREATE TABLE columns (
col_id INTEGER UNSIGNED AUTO_INCREMENT,
...
PRIMARY KEY(col_id)
);
CREATE TABLE l_row_size (
row_id INTEGER UNSIGNED,
size_id INTEGER UNSIGNED,
PRIMARY KEY(row_id, size_id),
CONSTRAINT FOREIGN KEY l_row_size-row_id (row_id) REFERENCES rows (row_id) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT FOREIGN KEY l_row_size-size_id (size_id) REFERENCES sizes (size_id) ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE TABLE l_col_size (
col_id INTEGER UNSIGNED,
size_id INTEGER UNSIGNED,
PRIMARY KEY(col_id, size_id),
CONSTRAINT FOREIGN KEY l_col_size-row_id (col_id) REFERENCES rows (col_id) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT FOREIGN KEY l_col_size-size_id (size_id) REFERENCES sizes (size_id) ON UPDATE CASCADE ON DELETE CASCADE
);
Then:
foreach( $sizes as $size ) {
$dbh->query("INSERT INTO sizes (size_name) VALUES ('{$size['name']}')");
$size_id = $dbh->last_insert_id();
foreach( $rows as $row ) {
$dbh->query("INSERT INTO l_row_size (size_id, row_id) VALUES ($size_id, {$row['id']})");
}
foreach( $cols as $col ) {
$dbh->query("INSERT INTO l_col_size (size_id, col_id) VALUES ($size_id, {$col['id']})");
}
}
edit
Sharf commented:
Each Size Class can have many rows and many columns, but each row and column can only belong to one size class.
Well then you only need 3 tables:
CREATE TABLE sizes (
size_id INTEGER UNSIGNED AUTO_INCREMENT,
...
PRIMARY KEY(size_id)
);
CREATE TABLE rows (
row_id INTEGER UNSIGNED AUTO_INCREMENT,
size_id INTEGER UNSIGNED,
...
PRIMARY KEY(row_id)
CONSTRAINT FOREIGN KEY rows-size_id (size_id) REFERENCES sizes (size_id) ON UPDATE CASCADE ON DELETE CASCADE,
);
CREATE TABLE columns (
col_id INTEGER UNSIGNED AUTO_INCREMENT,
size_id INTEGER UNSIGNED,
...
PRIMARY KEY(col_id),
CONSTRAINT FOREIGN KEY cols-size_id (size_id) REFERENCES sizes (size_id) ON UPDATE CASCADE ON DELETE CASCADE,
);
Linking tables are only truly useful in the case of n:m relationships, and this is a case of two 1:n relationships. Each Row/Column object need only store a reference to the Size to which they belong.

ID auto increase but not unique

I have a table that I want to have an id that will auto increase itself but not be primary or unique.
Is this possible?
You should really create another table, in that case.
E.g.
CREATE TABLE `Calls` (
`Id` INT(10) AUTO_INCREMENT,
`From` VARCHAR(100) NOT NULL,
`To` VARCHAR(100) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=INNODB;
CREATE TABLE `CallHistory` (
`Id` INT(15) AUTO_INCREMENT,
`CallId` INT(10) NOT NULL,
`Text` VARCHAR(255) NOT NULL,
PRIMARY KEY (`Id`),
KEY `CallHistory_Calls_idx` (`CallId`),
CONSTRAINT `CallHistory_Calls`
FOREIGN KEY (`CallId`)
REFERENCES `calls` (`Id`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=INNODB;
Here's a demo on SQLFiddle.
A benefit of this is that if you delete a row from Calls, the rows in CallHistory will also be deleted.
Running this query:
SELECT `Calls`.`Id`,
`Calls`.`From`,
`Calls`.`To`,
`CallHistory`.`Text`
FROM `Calls`, `CallHistory`
WHERE `Calls`.`Id` = `CallHistory`.`CallId`;
Gives results something like this:
This should work:
id int NOT NULL AUTO_INCREMENT
Anyway I don't see how it wouldn't stay unique unless you update existing values later
Yes, you need to set auto_increment constraint:
CREATE TABLE `test` (
`testID` int(11) NOT NULL, //primary key here
`testInc` int(11) NOT NULL AUTO_INCREMENT, //here is your non-primary auto increment column
PRIMARY KEY (`testID`),
KEY `testInc` (`testInc`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
and if you want this to be unique also then you may add unique constraint:
ALTER TABLE `test` ADD CONSTRAINT ux_unique_constraint UNIQUE `testInc`

Categories