INSERT INTO multiple tables through multiple foreign keys - php

I have multiple table connected together by a few different foreign keys (see attahced image).
I am trying to insert into the projects table. I've been trying to accomplish this through the following code below, but it's not working. Right now I am getting an error saying that neither client_id_fk, project_manager_id_fk have a value. That makes sense since I didn't include them in the insert, but aren't auto incrementing and I also can't just add a random int to those fields since that throws an error as well. It technically works if I set the client_id_fk and project_manager_id_fk to NULL, but then there's no data in the other tables...Please help
$sql1 = "INSERT INTO PROJECTS (Project_Name, StartDate) VALUES( '".$_POST["Project_Name"]."','".$_POST["StartDate"]."')";
$sql2 = "INSERT INTO CLIENTS(Client_Name, Client_Email, Client_Phone) VALUES ('".$_POST["Client_Name"]."','".$_POST["Client_Email"]."','".$_POST["Client_Phone"]."')";
$sql3 = "INSERT INTO PROJECT_MANAGERS(ProjectManager_Name,Project_Manager_Email, Project_Manager_Phone) VALUES ('".$_POST["ProjectManager_Name"]."','email', 'phone')";
$sql4 = "INSERT INTO TYPE_OF_WORK(TypeOfWork) VALUES ('".$_POST["TypeOfWork"]."')";

Pattern:
-- Insert data into slave tables
INSERT INTO slave_1 (columns_1) VALUES ('values_1');
INSERT INTO slave_2 (columns_2) VALUES ('values_2');
-- Insert data into main table,
-- query FK values from slaves
-- using values inserted above
-- as filtering conditions
INSERT INTO main (columns_main, fk_column_1, fk_column_2)
SELECT 'values_main', slave_1.id, slave_2.id
FROM ( SELECT id FROM slave_1 WHERE columns_1 = 'values_1' ) slave_1
JOIN ( SELECT id FROM slave_2 WHERE columns_2 = 'values_2' ) slave_2
If it is possible that some subquery in last INSERT may return more than 1 row then wrap output column in this subquery into MAX() function (you will receive id for the last row matched - i.e. just inserted).

Step back and think about the relationships you're modelling. You have told MySQL that a Project has a Client and a Project Manager; that makes sense. Then you've tried to insert a Project with only this information:
INSERT INTO PROJECTS (Project_Name, Start_Date) ...
The error you're getting is asking you "which Client is this Project for, and who is the Project Manager?" That's something only you can know.
If it's a new Client, you need to insert that before the Project; if it's a new Project Manager, you need to insert that before the Project too. Once you've inserted them, you need to get their IDs, e.g. with the LAST_INSERT_ID() function.
If it's an existing Client and/or Project Manager, you need to look up their IDs based on whatever logic makes sense in your application.
Once you have those two IDs, you can create you Project:
INSERT INTO PROJECTS (Project_Name, Start_Date, Client_Id, Project_Manager_Id) ...

This is wrong:
$sql1 = "INSERT INTO PROJECTS (Project_Name, StartDate) VALUES( '".$_POST["Project_Name"]."','".$_POST["StartDate"]."')";
$sql2 = "INSERT INTO CLIENTS(Client_Name, Client_Email, Client_Phone) VALUES ('".$_POST["Client_Name"]."','".$_POST["Client_Email"]."','".$_POST["Client_Phone"]."')";
$sql3 = "INSERT INTO PROJECT_MANAGERS(ProjectManager_Name,Project_Manager_Email, Project_Manager_Phone) VALUES ('".$_POST["ProjectManager_Name"]."','email', 'phone')";
$sql4 = "INSERT INTO TYPE_OF_WORK(TypeOfWork) VALUES ('".$_POST["TypeOfWork"]."')";
Because you are trying to INSERT into projects a client.id and a project_manager.id that does not exist in the database. So the above should actually be written like this (in case you use mysqli):
$link = mysqli_connect('localhost', 'my_user', 'my_password', 'my_db');
/* check connection */
if (!$link) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
// First add the client in case the table is completely empty
$stmt = mysqli_prepare($link, "INSERT INTO clients(name, email, phone) VALUES (?,?,?);");
mysqli_stmt_bind_param($stmt, 'sss', $_POST["Client_Name"], $_POST["Client_Email"], $_POST["Client_Phone"]);
/* execute prepared statement */
mysqli_stmt_execute($stmt);
/* close statement and connection */
mysqli_stmt_close($stmt);
// Then add the project_manager in case the table is completely empty
$stmt = mysqli_prepare($link, "INSERT INTO project_managers(name, email, phone) VALUES (?,?,?);");
mysqli_stmt_bind_param($stmt, 'sss', $_POST["ProjectManager_Name"], 'email', 'phone');
/* execute prepared statement */
mysqli_stmt_execute($stmt);
/* close statement and connection */
mysqli_stmt_close($stmt);
// Also add the type_of_work in case the table is completely empty
$stmt = mysqli_prepare($link, "INSERT INTO type_of_work(TypeOfWork) VALUES (?);");
mysqli_stmt_bind_param($stmt, 's', $_POST["TypeOfWork"]);
/* execute prepared statement */
mysqli_stmt_execute($stmt);
/* close statement and connection */
mysqli_stmt_close($stmt);
// Finally add your project
$stmt = mysqli_prepare($link, "INSERT INTO projects (project_name, start_date, client_id, project_manager_id) SELECT ?,?,client.id,project_managers.id FROM client,project_managers WHERE client.name = ? AND client.email = ? AND client.phone = ? AND project_managers.name = ?;");
mysqli_stmt_bind_param($stmt, 'ssssss', $_POST["Project_Name"],$_POST["StartDate"],$_POST["Client_Name"], $_POST["Client_Email"], $_POST["Client_Phone"],$_POST["ProjectManager_Name"]);
/* execute prepared statement */
mysqli_stmt_execute($stmt);
/* close statement and connection */
mysqli_stmt_close($stmt);
/* close connection */
mysqli_close($link);

Related

MySQL INSERT with a field coming from another table fails

I Need to insert data in a table but 1 of the fields will come from another table but not working...
Code as below:
//Save payment to table paylog
$sql = "INSERT INTO `paylog`(`payment_id`, `date_approved`, `newcredit`, `before`) VALUES (?,?,?,?)";
$stmt = $conn->prepare($sql);
$stmt->bind_param('ssss',$payment->id,$dateApproved,
$payment->transaction_amount,(SELECT credit from tokens WHERE token=$payment->external_reference LIMIT 1));
$stmt->execute();
$stmt->close();
Assistance welcome
Paulo
Just move that SELECT subquery up inside of $sql, keep $payment->external_reference as a binded parameter.
See https://stackoverflow.com/a/42132551/7977859

how to use 2 inserts in the same record PHP SQL

I am using the below code to grab a users ID from another table and creating a new record in this table. in the same row there is a field called action and I would like to insert either 'Log-In' or 'Log-Out' in this field for the same record.
my question is im not sure how to incorporate it with the code below without the database creating a new blank line
try{
// check for user ID in sessions table and apply to new session_log record
$sql = "INSERT INTO session_logs (USER_ID, first, last, email) SELECT USER_ID, first, last, email FROM sessions WHERE email=:email";
$stmt = $pdo->prepare($sql);
// Bind parameters to statement
$stmt->bindParam(':email', $_REQUEST['email']);
// Execute the prepared statement
$stmt->execute();
} catch(PDOException $e){
die("ERROR: Could not able to execute $sql. " . $e->getMessage());
}
Unfortunately, Table and Column names CANNOT be replaced by parameters in PDO so you cant just bind the SELECT column as a value or similar, however, you can manipulate the string yourself to add in the required value like so:
$action = 'Log-In'; // if you get this value from user input in any way, be sure to sanitize it with something like `mysqli_real_escape_string`
$sql = "INSERT INTO session_logs (USER_ID, first, last, email, action) SELECT USER_ID, first, last, email, '$action' FROM sessions WHERE email=:email";

How to insert a value into an auto_increment of a different table in the same string

I am using mysqli_multi_query to insert user's information and a default null profile photo, there are two tables for that, "esc_usuarios" for the personal data and "esc_usuarios_fotos" for the photos.
What do I want is, after inserting the personal data, insert this null image in the "esc_usuarios_fotos" table binding "img_usu_codigo" with this inserted person, the person's id is being auto incremented in the column "usu_codigo" from the table "esc_usuarios".
The query:
<?php
$inserir_usuario = "INSERT INTO `esc_usuarios`
(
usu_nome,
usu_senha,
usu_sobrenome,
usu_cpf,
usu_rg,
usu_nasc,
usu_endereco,
usu_numero,
usu_bairro,
usu_cep,
usu_cidade,
usu_uf,
usu_tel,
usu_cel,
usu_genero,
usu_email,
usu_indicador_codigo,
usu_datacadastro
) VALUES (
'$nome',
'".md5('$password')."',
'$sobrenome',
'$cpf',
'$rg',
'$nascimento',
'$endereco',
'$numero',
'$bairro',
'$cep',
'$cidade',
'$uf',
'$tel',
'$cel',
'$genero',
'$email',
'" . $_SESSION['codigo'] . "',
'$trn_date'
);
INSERT INTO esc_usuarios_fotos(img_local,img_usu_codigo) VALUES ('null', //i want to insert here the inserted person's id "usu_codigo" of the first insert statement)";
$re = mysqli_multi_query($conexao, $inserir_usuario);
Tackling a few issues here. You really should be using parameterized inserts for security reasons. Split out your inserts and then use insert_id to grab the newly created ID from your person insert. Wrap everything in a transaction as others in the comments pointed out - this will ensure you get everything or nothing.
And lastly, use mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); to turn MySQL errors into PHP exceptions. You can then wrap everything in a try/catch block. Good luck!
Pseduo code:
// Turn MySQL errors into PHP exceptions.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
// Open connection
$connection = new mysqli(...);
// check connection
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
// Start transaction here
...
/***********************************/
/********** PERSON INSERT **********/
/***********************************/
if ($stmt = $connection->prepare("INSERT INTO `esc_usuarios` ... (?, ?, ...)")) {
/* bind parameters for markers */
$stmt->bind_param("s", $...);
...
/* execute first query */
$stmt->execute();
/* This is the newly created ID */
$id = $connection->insert_id
/***********************************/
/********** PHOTOS INSERT **********/
/***********************************/
if ($stmt = $connection->prepare("INSERT INTO `esc_usuarios_fotos` ... (?, ?)")) {
/* Use that newly created ID here along with other params for your query */
$stmt->bind_param("s", $id);
/* execute query */
$stmt->execute();
}
}
// Commit transaction here
...
}
catch ( Exception $e ) {
// Rollback transaction if the exception is DB related
...
}

looping a php script to insert data for multiple users

I have two tables: phpbb_sn_fms_groups and phpbb_fms_user_groups, which I would like to INSERT into using the two queries below, however the first problem is I can't possibly manually run the two queries ~1000 times for each user_id (56 through 1060). The second problem is I need to INSERT the auto incremented fms_gid from the first query (table: phpbb_sn_fms_groups) into fms_id from the second query (table: phpbb_sn_fms_users_group) when the php script INSERTs each user_id.
// user_id: 56 through 1060
// fms_gid in the table phpbb_sn_fms_users_group needs the unique fms_gid for each row from the table phpbb_sn_fms_groups because it doesn't autoincrement.
$result = mysql_query("INSERT INTO phpbb_sn_fms_groups (fms_gid, user_id, fms_name, fms_clean, fms_collapse) VALUES ('autoincrementednumberthatdoesntneedtobeinserted', '56', 'Staff', 'staff', '0')")
or die(mysql_error());
$result = mysql_query("INSERT INTO phpbb_sn_fms_users_group (fms_gid, user_id, owner_id) VALUES ('inserttheautoincrementednumberfromfms_gidinphpbb_sn_fms_groups', '2', '56')")
or die(mysql_error());
Any help would be appreciated. Thanks!
This is a great time for PDO.
See http://php.net/manual/en/book.pdo.php for connection info but something like
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
// First select the users you need query.
$stmt = $pdo->prepare("SELECT id, name FROM users WHERE id BETWEEN 56 AND 1060");
$stmt->execute();
$result = $stmt->fetchAll();
OR if literally 56 through 1060 you can use a for loop.
Then loop through those results to execute
foreach($result as $row) {
$stmt1 = $pdo->prepare("INSERT INTO phpbb_sn_fms_groups (fms_gid, user_id, fms_name, fms_clean, fms_collapse) VALUES ('autoincrementednumberthatdoesntneedtobeinserted', :user_id , 'Staff', 'staff', '0')");
$stmt1->bindParam(":user_id", $row['id']);
$stmt1->execute();
//get last inserted id.
$inserted_id = $pdo->lastInsertId();
$stmt2 = $pdo->prepare("INSERT INTO phpbb_sn_fms_users_group (fms_gid, user_id, owner_id) VALUES (:last_id, '2', :user_id)");
$stmt2->bindParam(":last_id", $inserted_id);
$stmt2->bindParam(":user_id", $row['id']);
$stmt2->execute();
}
Hope this gets you started. Can also be done in mysqli. Don't want to jump into that debate. I just like naming the parameters for binding.

SQL/PHP INSERT INTO multiple rows with $row

So pretty much my issue is that I need to send multiple SQL entries using information based on another SQL entry.
I've simplified the code down that I was using so it's easily understandable.
$sql = mysql_query("SELECT product FROM `cart` WHERE username = '".$user."' LIMIT 10");
while ($rowcart = mysql_fetch_row($sql)) {
$sendorder = "INSERT INTO Orders (order_id, product) VALUES ('NULL', '".$rowcart[0]."')";
mysql_query($sendorder);
}
When I ran it, it had failed to work; so I tried to echo $sendorder to see exactly what was sending and it turns out it's copying the INSERT INTO part on each entry, instead of just copying the values.
Example output:
INSERT INTO Orders (order_id, product) VALUES ('NULL', 'Cakes')
INSERT INTO Orders (order_id, product) VALUES ('NULL', 'Sweets')
INSERT INTO Orders (order_id, product) VALUES ('NULL', 'Cakes')
INSERT INTO Orders (order_id, product) VALUES ('NULL', 'Brownies')
INSERT INTO Orders (order_id, product) VALUES ('NULL', 'Cakes')
You said, "I need to send multiple SQL entries using information based on another SQL entry." The following approach is more efficient than what you are attempting. Note that I use neither php nor mysql so I might have some syntax errors.
insert into orders
(product)
select product
from cart
where username = $user
As far as the limit 10 goes, if you want to restrict the person to 10 items, you should do something to ensure that only 10 rows go into the cart table.
Mysqli example
<?php
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'my_database');
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$stmt = $mysqli->prepare("SELECT product FROM `cart` WHERE username = ? LIMIT 10");
$stmt->bind_param('s', $user);
$stmt->execute();
$stmt->bind_result($product);
while($stmt->fetch()) {
$tvalue[] = $product;
}
$stmt = $mysqli->prepare("INSERT INTO Orders (product) VALUES (?)");
$stmt->bind_param("s", $one);
foreach ($tvalue as $one) {
$stmt->execute();
}
printf("%d Row inserted.\n", $stmt->affected_rows);
/* close statement and connection */
$stmt->close();
/* close connection */
$mysqli->close();
?>
If i understand correctly, what you want to do is to send an unique query, you can do this by appending every value to be inserted at the end of a single query string:
<?php
// code
$sql=mysql_query("SELECT product FROM cart WHERE username='".$user."' LIMIT 10");
$result=mysql_query($sql);
if(mysql_num_rows($result)) {
$rowcart=mysql_fetch_row("$result");
$sendorder="INSERT INTO Orders (order_id, product) VALUES ('NULL', '".$rowcart[0]."')";
while($rowcart=mysql_fetch_row($result))
$sendorder.=", ('NULL', '".$rowcart[0]."')";
mysql_query($sendorder);
}
// code
?>
I assume, your order_id is a primary key, and auto_increment. You can leave that:
INSERT INTO Orders (product) VALUES ('Cakes')
or if you really want to insert it, then use
INSERT INTO Orders (order_id, product) VALUES (NULL, 'Cakes')
if you add quotes ' around it, then it will be parsed as a string. And since, that is not a string, but integer, it will cause syntax error.
You should be able to do this in a single SQL statement something like this..
INSERT INTO Orders(order_id,product)
SELECT null,product
FROM cart
WHERE username = $name
LIMIT 0,10
To refactor even further I would suggest you probably dont need to insert the null value just do:
INSERT INTO Orders(product)
SELECT product
FROM cart
WHERE username = $name
LIMIT 0,10
If your table is structured to allow NULL in the order_id col then this will be populated as null by default.
And as Dan just said doesnt seem to be much point putting a limit on either

Categories