mysql PDO ON DELETE CASCADE - not working - php

I have seen my question may already have an answer, and "in mysql, on delete cascade not working" seems to be more similar..... but I can't see anything advised on that post working for me.
The problem is, when I delete a recipe, I want that its attachment gets also deleted (well, step by step, at the moment I am just trying to remove it from mysql table, not from the folder where it is stored).
After I post here a similar question but regarding how to create mysql trigger, I set the foreign key, and on delete cascade, so I though, when a recipe gets delete, the attachment as well, but it happens absolutely nothing to the attachment.... What am I doing wrong?
Next to each recipe I have a button to delete it:
echo '<a class="toLink" href="delete_recipe.php?id=' . $recipe['id'] . '" title="delete recipe" onclick="return confirm(\'Are you sure you want to delete this recipe?\');">Delete recipe</a>';
In delete_recipe.php:
<?php require 'includes/functions.php';
$recipeId = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
if(delete_recipe($recipeId) == true) {
header('Location: index.php');
exit;
} else {
$error_message = "Could not delete recipe";
}
In functions.php:
function delete_recipe($recipe_id = ':recipe_id') {
include 'db_connection.php';
try {
$sql = "DELETE FROM recipes ";
$sql .= "WHERE id =:recipe_id ";
$sql .= "LIMIT 1";
$results = $conn->prepare($sql);
$results->bindParam(':recipe_id', $recipe_id, PDO::PARAM_INT);
if($results->execute()) {
echo '1 row has been removed';
}
$conn = null;
} catch(PDOException $e) {
echo 'Error: ' . $e->getMessage() . '<br />';
return false;
}
return true;
}
I think I have set the foreign key and "delete on cascade" properly..... if I do:
show create table recipes:
| recipes | CREATE TABLE `recipes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`attachment_id` int(11) NOT NULL,
`chef_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_recipes_attachments1_idx` (`attachment_id`),
KEY `fk_recipes_chefs1_idx` (`chef_id`),
CONSTRAINT `fk_recipes_attachments1` FOREIGN KEY (`attachment_id`) REFERENCES `attachments` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_recipes_chefs1` FOREIGN KEY (`chef_id`) REFERENCES `chefs` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 |
show create table attachments:
| attachments | CREATE TABLE `attachments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`attachment_path` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 |
Any idea why it does not remove the attachment from the attachments table that belongs to the recipe I am deleting?
Thank you

You have your foreign key relationship backwards. The attachments table should have a recipe_id column, and that should be a foreign key to recipes.
CREATE TABLE `attachments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`attachment_path` varchar(255) NOT NULL,
`recipe_id` INT(11),
PRIMARY KEY (`id`),
FOREIGN KEY (`recipe_id`) REFERENCES `recipe` (`id`) ON DELETE CASCADE
);
The way you did it, deleting an attachment would delete the recipe.

Related

PDO: Integrity constraint violation (UPDATE TABLE)

First Table:
CREATE TABLE Portfolio_Categories
(
cat_id int(11) NOT NULL,
cat_title varchar(255) NOT NULL,
cat_dir varchar(255) NOT NULL
)
ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;
Second Table:
CREATE TABLE Portfolio_Images
(
img_id int(11) NOT NULL,
cat_id int(11) NOT NULL,
img varchar(255) NOT NULL,
img_title varchar(255) DEFAULT NULL
)
ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=latin1 COMMENT='Table to store the Portfolio Images';
Constraints:
ALTER TABLE Portfolio_Categories
ADD PRIMARY KEY (cat_id);
ALTER TABLE Portfolio_Images
ADD PRIMARY KEY (img_id), ADD KEY cat_id (cat_id), ADD KEY img_id (img_id);
ALTER TABLE Portfolio_Images ADD CONSTRAINT cat_id FOREIGN KEY
(cat_id) REFERENCES Portfolio_Categories (cat_id);
My PHP Code:
$query = "UPDATE
Portfolio_Images
SET
Portfolio_Images.img = :new_img,
Portfolio_Images.img_title = :new_tit,
Portfolio_Images.cat_id =
(SELECT t_cat.cat_id FROM (SELECT * FROM Portfolio_Categories) AS t_cat WHERE t_cat.cat_title = :new_cat)
WHERE
Portfolio_Images.img = :old_img;";
$stmt = $_MySQLConn->prepare($query);
$stmt->bindParam(':new_img', $new_img);
$stmt->bindParam(':new_tit', $new_tit);
$stmt->bindParam(':new_cat', $new_cat);
$stmt->bindParam(':old_img', $old_img);
if($stmt->execute())
{
$return_value = array('success'=>true,
'new_img:'=>$new_img,
'new_tit'=>$new_tit,
'new_cat'=>$new_cat,
'old_img'=>$old_img);
}
else
{
$return_value = array('success'=>false,'error_code'=>'Could not execute query');
}
What should it do:
It should update my table without any error (as it does if I run the statement directly)
What does it do:
PHP shows me this error message:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a child row: a foreign key constraint fails
(1_new.Portfolio_Images, CONSTRAINT cat_id FOREIGN KEY
(cat_id) REFERENCES Portfolio_Categories (cat_id))
This means that you are inserting a row in Portfolio_Images where the value in Portfolio_Images.cat_id does not exist in Portfolio_Categories.cat_id.
In other words, if in Portfolio_Categories.cat_id you only have the values 1, 2, 4 you can only insert in Portfolio_Images.cat_id the values 1, 2 or 4.

insert and display data on a dashboard for currently (logged in)user using PHP, MySql

I have made a user_login table, having pk = userid.
A credit_request table is created which references to userid as fk.
when the user login, he should see only his entries in the dashboard.
But, here i am not able to insert data, once i link a foreign key to it.
and even the data inserted through phpmyadmin is visible to all users.
Please help me out.
how to insert and retrieve data for logged in users.
<>
//Database setup for Credit request
//Insert data into Credit request
if(isset($_POST['taskid']))
{
$taskid =$_POST['taskid'];
$orderid = $_POST['orderid'];
$status = $_POST['status'];
$query1 = "INSERT INTO credit_request(taskid, orderid, status)
VALUES ('$taskid', '$orderid', '$status')";
if ($connect->query($query1) === TRUE) {
echo "New record created successfully";
} else {
echo "Error: " . $query1 . "<br>" . $connect->error;
}
}
//Display data for credit request
$query2 = "SELECT taskid, orderid, status FROM credit_request WHERE agentid = '$userid'";
$res = $connect->query($query2);
if ($res->num_rows > 0) {
// output data of each row
while($row = $res->fetch_assoc()) {
echo "<br>taskid: " . $row["taskid"]. " -orderid: " . $row["orderid"]. " --:" . $row["status"]."";
}
} else {
echo "0 results";
}
I think you have problem on update, on delete when creating foreign key..
Here's an example of how you'd build your schema:
CREATE TABLE `country` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`country_name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE `state_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`state_name` varchar(45) DEFAULT NULL,
`country_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `country_fk` FOREIGN KEY (`country_id`)
REFERENCES `country` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='';
INSERT INTO country (country_name) VALUES ('US of A');
INSERT INTO state_table (state_name,country_id) VALUES
('Minnesota', 2),
('Arizona', 2);
See this fiddle for more.

Alternative method to delete child element from parent besides on delete cascade

I have 2 tables:
Warehouse (Parent)
Subwarehouse (Child)
Here is the creation of tables
//Create Warehouse Table
function einv_createWarehouseTable($conn, $db_type){
// Create SQL Statement To Create Table according to Database
$sql = "
CREATE TABLE IF NOT EXISTS `einv_warehouse` (
`einv_wh_id` INT(11) NOT NULL AUTO_INCREMENT,
`einv_wh_code` VARCHAR(4) NOT NULL,
`einv_wh_name` VARCHAR(255) NOT NULL,
`einv_wh_desc` TEXT NOT NULL,
`einv_wh_remark` TEXT NULL,
PRIMARY KEY (`einv_wh_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
";
//Create Sub Warehouse Table
function einv_createSubWarehouseTable($conn, $db_type){
// Create SQL Statement To Create Table according to Database
$sql = "
CREATE TABLE IF NOT EXISTS `einv_subwarehouse` (
`einv_whs_id` INT(11) NOT NULL AUTO_INCREMENT,
`einv_whs_wh_id` INT(11) NOT NULL,
`einv_whs_code` VARCHAR(4) NOT NULL,
`einv_whs_name` VARCHAR(255) NOT NULL,
`einv_whs_desc` TEXT NOT NULL,
`einv_whs_remark` TEXT NULL,
PRIMARY KEY (`einv_whs_id`),
FOREIGN KEY (`einv_whs_wh_id`) REFERENCES einv_warehouse(`einv_wh_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
";
I would like to be able to delete my parent table alongside clearing the entire child data.
I'd prefer an alternative method besides using on delete cascade which will result me into altering the table.
It is troublesome because these codings would require a drop and install process which is time consuming since there are many existing tables.
tl;dr - another method to delete all child data when selected parent id is
deleted
besides using on delete cascade
Here is my delete sql in my function.php page:
base_executeSQL("DELETE FROM einv_warehouse WHERE einv_wh_id = " . $whid . "");
base_executeSQL("DELETE FROM einv_subwarehouse WHERE einv_whs_id = " . $whid . "");

Insertion Failed:Cannot add or update a child row: a foreign key constraint fails

I have two tables- users and language with a foreign key link of their primary key 'id'.
I have checked that the type is innoDB for the tables. I have delete- restrict and update -cascade.
This insert query, inserts it into the language table: (it can be more than one row which is added as the form has dynamic clickevent button)
if(empty($_SESSION['user_id'])) { // user not logged in; redirect to somewhere else }
$sql_insert = "INSERT into `language`
(`native`,`other`,`other_list`,`other_read`, `other_spokint`
,`other_spokprod`,`other_writ` )
VALUES
('$native','$other','$other_list','$other_read','$other_spokint','$other_spokprod',
'$other_writ') ";
mysql_query($sql_insert,$link) or die("Insertion Failed:" . mysql_error());
}
This is the full error:
Insertion Failed:Cannot add or update a child row: a foreign key constraint fails
(`members`.`language`, CONSTRAINT `language_ibfk_1` FOREIGN KEY (`id`)
REFERENCES `users` (`id`))
Any help would be appreciated!
Table structure for table language:
CREATE TABLE IF NOT EXISTS `language` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`native` varchar(30) NOT NULL,
`other` varchar(30) NOT NULL,
`other_list` varchar(9) NOT NULL,
`other_read` varchar(9) NOT NULL,
`other_spokint` varchar(9) NOT NULL,
`other_spokprod` varchar(9) NOT NULL,
`other_writ` varchar(9) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
RELATIONS FOR TABLE `language`:
`id`
`users` -> `id`
You have to use a structure like this:
create table users (
id int not null auto_increment,
<additional fields>,
primary key (id)
) ENGINE=InnoDB;
create table language(
id int not null auto_increment,
user_id int not null,
<additional fields>,
primary key (id),
foreign key (user_id) references users(id) on delete restrict on update cascade
) ENGINE=InnoDB;

Ignore duplicates when using INSERT in a Database with Symfony and Doctrine

I have a table
CREATE TABLE `sob_tags_articles` (
`tag_id` int(11) NOT NULL,
`article_id` int(11) NOT NULL,
`id` int(11) NOT NULL auto_increment,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=112
And triing to save an object with Doctrine:
$sbTagsArticles = new SobTagsArticles();
$sbTagsArticles->article_id = $pubId;
$sbTagsArticles->tag_id = $tagId;
$sbTagsArticles->save();
But if record exists with the same $pubId and $tagId new record will be insertet with new PK.
How to do INSERT IGNORE into table with symfony?
$sbTagsArticles->isNew();
returns 1.
Thnx.
try
{
$record->save();
}
catch(Doctrine_Exception $e)
{
if($e->getErrorCode() !== $duplicateKeyCode)
{
/**
* if its not the error code for a duplicate key
* value then rethrow the exception
*/
throw $e;
}
/**
* you might want to fetch the real record here instead
* so yure working with the persisted copy
*/
}
You should be ensuring that the same record doesnt exist on the application side not the SQL side. If you dont ever want the same article/tag combo to exist then add a unique index to (article_id, tag_id). That should generate a mysql error which will in turn generate a doctrine exception that you can catch. There isnt an ignore flag for saves... You might be able to use one operating at a lower level of the DBAL (Doctrine_Query, Doctrine_Connection, etc..) but not directl from the ORM layer.
Doctrine_Record::isNew() will always return true if you have instantiated record asopposed to pulling it from the db otherwise it has way it has no way to know that the record is/isnt new.
Also why are you using the MyISAM storage engine? Im pretty sure this will actually result in more overhead when using Doctrine since it then needs to emulate constraints on the php side. Normally your schema would look something like this:
CREATE TABLE `sob_tags_articles` (
`tag_id` int(11) NOT NULL,
`article_id` int(11) NOT NULL,
`id` int(11) NOT NULL auto_increment,
PRIMARY KEY (`id`),
CONSTRAINT `some_unique_constraint_name_1`
FOREIGN KEY `article_id`
REFERENCES `article` (`id`)
ON DELETE CASCADE,
CONSTRAINT `some_unique_constraint_name_2`
FOREIGN KEY `tag_id`
REFERENCES `tag` (`id`)
ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=112
This is the actual code to be used
try
{
$record->save();
}
catch(Doctrine_Connection_Exception $e)
{
if($e->getPortableCode() != Doctrine::ERR_ALREADY_EXISTS)
{
/**
* if its not the error code for a duplicate key
* value then rethrow the exception
*/
throw $e;
}
/**
* you might want to fetch the real record here instead
* so yure working with the persisted copy
*/
}
You could extend the SobTagsArticles object with a new save method, and check if the record already exists:
public function exists() {
$q = Doctrine_Query::create()
->from('sobtagsarticles ta')
->where('ta.tag_id = ? and ta.article_id = ?', array($this->getTagId(), $this->getArticleId()));
if (!$result = $q->execute())
{
parent::save();
}
}
This way the object will be saved only if it doesn't exist.
You could also set an unique index to your table like so:
UNIQUE INDEX `sb_tags_articles_unique` (`tag_id` ASC, `article_id` ASC)
Your schema would look like this:
CREATE TABLE `sob_tags_articles` (
`tag_id` int(11) NOT NULL,
`article_id` int(11) NOT NULL,
`id` int(11) NOT NULL auto_increment,
PRIMARY KEY (`id`),
UNIQUE INDEX `sb_tags_articles_unique` (`tag_id` ASC, `article_id` ASC),
CONSTRAINT `some_unique_constraint_name_1`
FOREIGN KEY `article_id`
REFERENCES `article` (`id`)
ON DELETE CASCADE,
CONSTRAINT `some_unique_constraint_name_2`
FOREIGN KEY `tag_id`
REFERENCES `tag` (`id`)
ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=112

Categories