Multiple prepared statements into many to many relationship table using last id - php

[Updated code from suggestions]
Currently I have two tables in my database. The second table is a junction table for multiple categories from each unique id from the first table. Nothing too special.
Need to accomplish:
I'd like to use two prepared statements where specifically the second statement gets the ID from the first and loops through. Here's what I've tried:
//set autocommit to off
$conn->autocommit(FALSE);
//first table
$stmt1 = $conn->prepare("INSERT INTO birds (db_category, db_class) VALUES (?, ?)");
$stmt1->bind_param('ss',$_POST['db_category'],$_POST['db_class']);
$stmt1->execute();
//get the inserted ID
$lastID = $stmt1->insert_id;
$stmt1->close();
//second table (many to many)
$stmt2 = $conn->prepare("INSERT INTO birdsBiome (birds_id, biomes_id) VALUES (?, ?)");
$arrayValue = $_POST['biomeCheck'];
foreach ($arrayValue as $arrayInsert) {
$stmt2->bind_param('ii', $lastID, $arrayInsert);
$stmt2->execute();
}
$stmt2->close();
//commit both statements
$conn->commit();
$conn->close();

You can access the last insert id as a property of the mysqli object:
$lastID = $conn->insert_id;
Or alternatively you don't have to store $lastID at all if you access it within your SQL:
$stmt2 = $conn->prepare("INSERT INTO birdsBiome (birds_id, biomes_id)
VALUES (LAST_INSERT_ID(), ?)");
By the way, in your code example above you didn't execute $stmt1, so there will be no last insert id anyway.

Related

How to return ID of existing row if there is a duplicate row during MySQL INSERT?

I have two tables: movies and genres, and a junction table movieOfGenre for many-to-many relationships between the movies and genres tables. Now, when I am using transactions to insert movies and genres into my database using PHP, genres were being created twice even if there was a duplicate. Then I updated the code with ...ON DUPLICATE KEY UPDATE... and now if there is an existing genre with the same name, the auto_increment ID of the existing genre is being updated when I use this transaction query:
mysqli_autocommit($connect, false);
$query_success = true;
$stmt = $connect->prepare("INSERT INTO movies (id, title, plot, rating, releaseDate, duration, language, country, posterUrl, trailerUrl) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->bind_param("ssssssssss", $defaultId, $title, $plot, $rating, $releaseDate, $duration, $language, $country, $poster, $trailer);
if (!$stmt->execute()) {
$query_success = false;
}
$movieId = mysqli_insert_id($connect);
$stmt->close();
foreach ($genres as $genre) {
$stmt = $connect->prepare("INSERT INTO genres (id, name) VALUES (?, ?) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID()");
$stmt->bind_param("ss", $defaultId, $genre);
if (!$stmt->execute()) {
$query_success = false;
}
$genreId = mysqli_insert_id($connect);
$stmt->close();
$stmt = $connect->prepare("INSERT INTO movieofgenre (movieId, genreId) VALUES (?, ?)");
$stmt->bind_param("ii", $movieId, $genreId);
if (!$stmt->execute()) {
$query_success = false;
}
$stmt->close();
}
if ($query_success) {
mysqli_commit($connect);
} else { ?>
alert('Error adding movie.');
<?php mysqli_rollback($connect);
}
How do I write the query so that if during insertion there is an existing row with the same genre.name, it returns the ID of the existing row without updating it?
Thanks in advance.
genres.name should be a unique column:
CREATE TABLE genres
...
UNIQUE KEY name
use IGNORE - duplicate exception will not be thrown
INSERT IGNORE INTO genres (name) VALUES (?)
get the id by name:
SELECT id FROM genres WHERE name = ?
I'm not sure this help but you may want to check example below. Lazy to do php coding this days, But I have similar issue with MYSQL last time if I understand your issue correctly :P
INSERT INTO sample_table (unique_id, code) VALUES ('$unique_id', '$code')
ON DUPLICATE KEY UPDATE code= '$code'
Hope this resolve your problem

How do I get the ID of an inserted row?

I have this following example query, which works - I CAN insert values into my MySQL table, which also includes an unique id column. I want to get the id from the inserted row, after I execute the query. However what I get is 0 every time ($gotId=0).
What am I doing wrong?
$stmt = $conn->prepare("INSERT INTO ....... ");
$stmt-> bind_param("ss", ....);
$stmt->execute();
$gotId = $conn->insert_id;
Full query:
$conn = $db->connect();
$stmt = $conn->prepare("INSERT INTO table(value1, value2) VALUES(?, ?)");
$stmt-> bind_param("ss", $value1, $value2);
$stmt->execute();
$gotId = $conn->insert_id;
After calling the execute() method on the PreparedStatement, the id of the insert row will be in the insert_id attribute Only read it.
$stmt->execute();
$gotId = $stmt->insert_id;
Taken from here
$query = "INSERT INTO .......";
$mysqli->query($query);
printf ("New Record has id %d.\n", $mysqli->insert_id);
More Info

PHP/mysql: mysqli prepared statement insert same value multiple times within for loop

I am using a prepared statement to insert multiple rows into a table using a for loop. What I require is for the same value ($id) to be inserted into all rows of the "id" column. Likewise, the timestamp should be inserted into the "submitted" column over all iterations.
My current code only inserts one column. Here is the code:
if($stmt = $link->prepare("INSERT INTO table (id, alt_ord, alt_id, rank, submitted) VALUES ($id,?,?,?, NOW())")){
$stmt->bind_param('iii', $q_ord, $q_ID, $rating);
for($i=0; $i < count($_POST['alt_ord']); $i++){
$q_ord = $_POST['alt_ord'][$i];
$q_ID = $_POST['alt_id'][$i];
$rating = $_POST['rank_'][$i];
$stmt->execute();
}
$stmt->close();
}
Using a combination of ?s with $id and NOW() in the INSERT statement is clearly incorrect. How would I repeat the ID and timestamp values in the insert as intended?
Assuming $id is an unknown value (from user input, etc), simply bind it along with the others and don't forget to check for errors
// make mysqli trigger useful errors (exceptions)
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$stmt = $link->prepare('INSERT INTO table (id, alt_ord, alt_id, rank, submitted) VALUES (?, ?, ?, ?, NOW())');
$stmt->bind_param('iiii', $id, $q_ord, $q_ID, $rating);
for ($i = 0; $i < count($_POST['alt_ord']); $i++) {
$q_ord = $_POST['alt_ord'][$i];
$q_ID = $_POST['alt_id'][$i];
$rating = $_POST['rank_'][$i]; // you sure about this one? "rank_"?
$stmt->execute();
}

Insert into 2 tables from 1 form. Mysql Transaction?

The user will create an article and submit an image with it.
+The article will go to the articles table.
+The image will go to images table (so that it can be used in other areas of the site).
It has been suggested I use TRANSACTIONS but I am getting errors.
$sql ='BEGIN INSERT INTO articles(article_title, article_text, article_date)
VALUES (?, ?, NOW())
INSERT INTO images(article_id, image_caption)
VALUES(LAST_INSERT_ID(),?);
COMMIT';
$stmt = $conn->stmt_init();
if ($stmt->prepare($sql)) {
$stmt->bind_param('sss', $_POST['article_name'], $_POST['description'], $_POST['image_caption']);
$OK = $stmt->execute();
printf("%d Row inserted.\n", $stmt->affected_rows);
$stmt->free_result();
} else{
echo "Failure- article not uploaded";
}
$mysqli->query("START TRANSACTION");
$stmt = $mysqli->prepare('INSERT INTO articles(article_title, article_text, article_date) VALUES (?, ?, NOW())');
$stmt->bind_param('ss', $_POST['article_name'], $_POST['description']);
$stmt->execute();
$stmt = $mysqli->prepare('INSERT INTO images (article_id, image_caption) VALUES(LAST_INSERT_ID(),?)');
$stmt->bind_param('s', $_POST['image_caption']);
$stmt->execute();
$stmt->close();
$mysqli->query("COMMIT");
It looks like you are using PDO (nice!). With PDO, you can get your transactions in an easy way with beginTransaction() and commit()
Your code would look like:
$pdo->beginTransaction();
// .. fire your 'normal' queries.
// .. and yet some more queries
$pdo->commit();
Then, I'd personally write separate INSERT queries in just two separate statements. More readable in my opinion.
Example:
$pdo->beginTransaction();
$first = $pdo->prepare('INSERT INTO table (field, otherField) VALUES(?,?)');
$second = $pdo->prepare('INSERT INTO table (field, otherField) VALUES(?,?)');
$first->execute(array( .. your data (values) .. ));
$second->execute(array( .. your data (values) .. ));
$pdo->commit();
$sql ='START TRANSACTION;
INSERT INTO articles (article_id,article_title, article_text, article_date) VALUES (NULL,?, ?, NOW());
INSERT INTO images (article_id, image_caption) VALUES(LAST_INSERT_ID(),?);
COMMIT;';

PHP PDO Transactions?

I have a signup page and basically I need data inserted into 4 tables. I'm new to PDO and am confused over something.
Basically if any of the inserts fail I don't want anything added to the database, that seems simple enough.
My confusion is, I need to first insert the users username, email, password etc in my users table so I can get (not sure how) using PDO the uid MySQL has given my user (auto incremented by mysql). I need the user uid MySQL gave my user for the other tables as the other tables needs the uid so everything is linked properly together. My tables are InnoDB and I have foreign keys going from users_profiles(user_uid), users_status(user_uid), users_roles(user_uid) to the users.user_uid so they are all linked together.
But at the same time I want to ensure that if for example after data is inserted in the users table (so I can get the uid MySQL gave user) that if any of the other inserts fail that it removes the data that was inserted into the users table.
I thinks it's best I show my code; I have commented out the code and have explained in the code which may make it easier to understand.
// Begin our transaction, we need to insert data into 4 tables:
// users, users_status, users_roles, users_profiles
// connect to database
$dbh = sql_con();
// begin transaction
$dbh->beginTransaction();
try {
// this query inserts data into the `users` table
$stmt = $dbh->prepare('
INSERT INTO `users`
(users_status, user_login, user_pass, user_email, user_registered)
VALUES
(?, ?, ?, ?, NOW())');
$stmt->bindParam(1, $userstatus, PDO::PARAM_STR);
$stmt->bindParam(2, $username, PDO::PARAM_STR);
$stmt->bindParam(3, $HashedPassword, PDO::PARAM_STR);
$stmt->bindParam(4, $email, PDO::PARAM_STR);
$stmt->execute();
// get user_uid from insert for use in other tables below
$lastInsertID = $dbh->lastInsertId();
// this query inserts data into the `users_status` table
$stmt = $dbh->prepare('
INSERT INTO `users_status`
(user_uid, user_activation_key)
VALUES
(?, ?)');
$stmt->bindParam(1, $lastInsertID, PDO::PARAM_STR);
$stmt->bindParam(2, $activationkey, PDO::PARAM_STR);
$stmt->execute();
// this query inserts data into the `users_roles` table
$stmt = $dbh->prepare('
INSERT INTO `users_roles`
(user_uid, user_role)
VALUES
(?, ?)');
$stmt->bindParam(1, $lastInsertID, PDO::PARAM_STR);
$stmt->bindParam(2, SUBSCRIBER_ROLE, PDO::PARAM_STR);
$stmt->execute();
// this query inserts data into the `users_profiles` table
$stmt = $dbh->prepare('
INSERT INTO `users_profiles`
(user_uid)
VALUES
(?)');
$stmt->bindParam(1, $lastInsertID, PDO::PARAM_STR);
$stmt->execute();
// commit transaction
$dbh->commit();
} // any errors from the above database queries will be catched
catch (PDOException $e) {
// roll back transaction
$dbh->rollback();
// log any errors to file
ExceptionErrorHandler($e);
require_once($footer_inc);
exit;
}
I'm new to PDO and there maybe errors or problems above I have yet to notice because I can't test yet until I figure out my problem.
I need to know how I can insert the users data in the users table first so i can get the uid MySQL gave my user
Then get the uid as I need it for the other tables
But at the same time if a query fails for whatever reason after inserting into users table that the data is also deleted from the users table aswell.
This function returns primary key of just inserted record: PDO::lastInsertId
You will need it for NEED_USERS_UID_FOR_HERE parameter. Use it just after INSERT statement.
Since you started a transaction, data will not be inserted into any table if any error occures provided you use InnoDB engine for your MySQL tables (MyISAM doesn't support transactions).

Categories