I have been working on my first webapp and I hit a bit of a wall. I have a table in my db set up as follows:
student_id(student_id, first_name, last_name, bdate, etc...)
I also have several tables for classes set up similarly to this
class_table(id, student_id, quiz_1, quiz_2, etc....)
student_id is how I would like to track everything, from my understanding, this would be a primary key that would become a foreign key on the class tables.
What I would like to do is create an entry for the student on each class table when the php script I am writing creates a new student. This is what my query looks like:
$query = "INSERT INTO student_id(0, '$first_name', '$last_name'.... etc);".
"INSERT INTO class_table(0, LAST_INSERT_ID(), '$quiz_1', $quiz_2'...etc)";
Is this the right way to do this? I keep getting an error from my mysqli_query... so I am guessing this is where the problem is. How would I achieve this?
mysqli_query() (and mysql_query()) will only execute a single query. You would need to perform two calls to mysqli_query() or use mysqli_multi_query(), which will execute multiple queries in one call.
You're missing the VALUES clause:
$query = "INSERT INTO student_id VALUES (0, '$first_name', '$last_name'.... etc);".
"INSERT INTO class_table VALUES (0, LAST_INSERT_ID(), '$quiz_1', '$quiz_2'...etc)";
and you will need to use the mysqli_multi_query() function. See the example at http://www.php.net/manual/en/mysqli.multi-query.php#106126:
if ($mysqli->multi_query($query)) {
$i = 0;
do {
$i++;
} while ($mysqli->next_result());
}
if ($mysqli->errno) {
echo "Batch execution prematurely ended on statement $i.\n";
var_dump($statements[$i], $mysqli->error);
}
You could also create a stored procedure, and call it with all the needed parameters:
CALL insert_student('$first_name', '$last_name', '$quiz_1', $quiz_2', ... etc);
Here's an example:
CREATE PROCEDURE add_student(
IN v_first_name VARCHAR(50),
IN v_last_name VARCHAR(50),
IN v_quiz_1 VARCHAR(255),
IN v_quiz_2 VARCHAR(255)
)
DETERMINISTIC
MODIFIES SQL DATA
proc: BEGIN
START TRANSACTION;
INSERT INTO student_id VALUES (0, v_first_name, v_last_name);
IF ROW_COUNT() <= 0 THEN
ROLLBACK;
SELECT 0 AS result;
LEAVE proc;
END IF;
INSERT INTO class_table VALUES (0, LAST_INSERT_ID(), v_quiz_1, v_quiz_2);
COMMIT;
SELECT 1 AS result;
END;
Related
I want to use one form to insert into two different Microsoft sql tables. I tryed to use 2 inserts, but didnt work.
if (isset($_GET['submit'])) {
$sth = $connection->prepare("INSERT INTO DB.dbo.Fehler (QualiID, TestaufstellungID, ModulinfoID, failAfter, Datum, Verbleib, DUTNr) VALUES ($QualiID, $TestaufstellungID,$ModulinfoID,'$failAfter','$Datum','$Verbleib','$DUTNr')");
echo "INSERT INTO DB.dbo.Fehler (QualiID, TestaufstellungID, ModulinfoID, failAfter, Datum, Verbleib, DUTNr) VALUES ($QualiID, $TestaufstellungID,$ModulinfoID,'$failAfter',$Datum,'$Verbleib','$DUTNr')";
$sth->execute();
if($sth)
{
echo "";
}
else
{
echo sqlsrv_errors();
}
$MID = $connection->prepare("MAX(MID) as MID FROM DB.dbo.Fehler WHERE DB.dbo.Fehler.TestaufstellungID = '". $TestaufstellungID . "'");
$MID->execute();
$sth2 = $connection->prepare("INSERT INTO DB.dbo.Fehlerinfo (MID, Tester, Test, Ausfallbedingungen, Fehlerbeschreibung, Ersteller) VALUES ($MID, '$Tester','$Test','$Ausfallbedingungen','$Fehlerbeschreibung','$Ersteller')");
$sth2->execute();
To understand MID is the Primary key of table Fehler and ist the foreign key in the second table Fehlerinfo
Thats why i have the select work around to get the last MID and want to save it in a variable $MID to insert it into the second table.
Is there a smarter solution possible?
As I mentioned in the comments, generally the better way is to do the insert in one batch. This is very over simplified, however, should put you in the right direction. Normally you would likely be passing the values for the Foreign Table in a Table Value Parameter (due to the Many to One relationship) and would encapsulate the entire thing in a TRY...CATCH and possibly a stored procedure.
I can't write this in PHP, as my knowledge of it is rudimentary, but this should get you on the right path to understanding:
USE Sandbox;
--Couple of sample tables
CREATE TABLE dbo.PrimaryTable (SomeID int IDENTITY(1,1),
SomeString varchar(10),
CONSTRAINT PK_PTID PRIMARY KEY NONCLUSTERED (SomeID));
CREATE TABLE dbo.ForeignTable (AnotherID int IDENTITY(1,1),
ForeignID int,
AnotherString varchar(10),
CONSTRAINT PK_FTID PRIMARY KEY NONCLUSTERED(AnotherID),
CONSTRAINT FK_FTPT FOREIGN KEY (ForeignID)
REFERENCES dbo.PrimaryTable(SomeID));
GO
--single batch example
--Declare input parameters and give some values
--These would be the values coming from your application
DECLARE #SomeString varchar(10) = 'abc',
#AnotherString varchar(10) = 'def';
--Create a temp table or variable for the output of the ID
DECLARE #ID table (ID int);
--Insert the data and get the ID at the same time:
INSERT INTO dbo.PrimaryTable (SomeString)
OUTPUT inserted.SomeID
INTO #ID
SELECT #SomeString;
--#ID now has the inserted ID(s)
--Use it to insert into the other table
INSERT INTO dbo.ForeignTable (ForeignID,AnotherString)
SELECT ID,
#AnotherString
FROM #ID;
GO
--Check the data:
SELECT *
FROM dbo.PrimaryTable PT
JOIN dbo.ForeignTable FT ON PT.SomeID = FT.ForeignID;
GO
--Clean up
DROP TABLE dbo.ForeignTable;
DROP TABLE dbo.PrimaryTable;
As i mentioned the answer how it works for me fine atm.
if (isset($_GET['submit'])) {
$failInsert = ("INSERT INTO DB.dbo.Fehler (QualiID, TestaufstellungID, ModulinfoID, failAfter, Datum, Verbleib, DUTNr) VALUES ($QualiID, $TestaufstellungID,$ModulinfoID,'$failAfter','$Datum','$Verbleib','$DUTNr')");
$failInsert .= ("INSERT INTO DB.dbo.Fehlerinfo (MID, Tester, Test, Ausfallbedingungen, Fehlerbeschreibung, Ersteller) VALUES (NULL, '$Tester','$Test','$Ausfallbedingungen','$Fehlerbeschreibung','$Ersteller')");
$failInsert .= ("UPDATE DB.dbo.Fehlerinfo SET DB.dbo.Fehlerinfo.MID = i.MID FROM (SELECT MAX(MID)as MID FROM DB.dbo.Fehler) i WHERE DB.dbo.Fehlerinfo.TestID = ( SELECT MAX(TestID) as TestID FROM DB.dbo.Fehlerinfo)");
$sth = $connection->prepare($failInsert);
$sth->execute();
}
This question already has answers here:
How to get the last field in a Mysql database with PHP?
(5 answers)
Closed 9 years ago.
I am working on a register user form and I have two tables in mysql. What I want to do is when a new user has registered, take the id (which primary key) of that user and insert it into another table. What is the best way to do that?
Thanks in advance.
You need to use mysql_insert_id for this purpose. Here is an example:
<?php
$link = mysql_connect('localhost', 'mysql_user', 'mysql_password');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db('mydb');
mysql_query("INSERT INTO mytable (product) values ('kossu')");
printf("Last inserted record has id %d\n", mysql_insert_id());
?>
First insert the user details into users table and get inserted user id using mysql_insert_id. and use that user id to insert into another table.
AS ON GETTING IT ON PHP
GET LAST INSERT ID HERE
BUT IF YOU INTEND TO GET IT USING MYSQL QUERY
use stored procedure to store last insert id to a variable then generete your second query
INSERT INTO T1 (col1,col2) VALUES (val1,val2);
SET #last_id_in_T1 = LAST_INSERT_ID();
INSERT INTO T2 (col1,col2) VALUES (#last_id_in_T1,val2);
or direct insert after your first insert
INSERT INTO T1 (col1,col2) VALUES (val1,val2);
INSERT INTO T2 (col1,col2) VALUES (LAST_INSERT_ID(),val2);
Use any of transaction query for writing:
Following is in CI pattern:
$this->db->trans_start();
$this->db->query('AN SQL QUERY...');
$this->db->query('AN SQL QUERY...');
if(!$this->db->trans_complete()){
$this->db->trans_rollback();
}
$query1= "INSERT INTO employee ( username, email,...)
VALUES ('".$_POST["username"]."', ...)";
if($result1 = mysql_query($query1))
{
$emp_id = mysql_insert_id(); // last created id by above query
$query2= "INSERT INTO dept ( emp_id, dept_name, ...)
VALUES ('".$emp_id."', '".$_POST["dept_name"]."',...)";
if($result2 = mysql_query($query2))
{
//success msg
}
}
Another neat way to do it at do it at Database level itself is to used Stored Procedure
Look at this solution to see an example of how to do it. You will have to check how Stored procedures work in your specific database to get the specific syntax. This makes it error free even if someone refactors or moves around the code and more efficient.
Using trigger the Mysql on database-level. For example, I have two tables:
user(id int primary key, nombre varchar(50));
replication(id_r int primary key, nombre_r varchar(50));
Using the trigger:
create trigger user_r after insert on user
for each row
insert into replication(id_r, nombre_r)
select u.id, u.nombre
from user u
where u.id=NEW.id and u.nombre=NEW.nombre;
I have the following insert statements:
$sql ="INSERT INTO `firm`(name, VAT, active) VALUES ('$name', '$VAT', '$active')";
$sql = "INSERT INTO `area`(name, hub_name, fk_hub_id) VALUES ('$areaname',(SELECT `name` from hub WHERE name = '$hub_name'), (SELECT `id` from hub WHERE name = '$hub_name'))";
$sql ="INSERT INTO 'contactdetails'
(fk_firm_id,
address_physical_line_1,
address_physical_line_2,
address_physical_line_3,
address_physical_line_4,
address_physical_line_5,
address_physical_line_6,
address_physical_line_7,
address_physical_code,
address_postal_line_1,
address_postal_line_2,
address_postal_line_3,
address_postal_line_4,
address_postal_line_5,
address_postal_line_6,
address_postal_line_7,
address_postal_code,
fax_1,
fax_2,
phone_1,
phone_2,
phone_3,
phone_4)
VALUES ( (SELECT `id`
FROM firm
WHERE name = '$name'),
'$address_physical_line_1',
'$address_physical_line_2',
'$address_physical_line_3',
'$address_physical_line_4',
'$address_physical_line_5',
'$address_physical_line_6',
'$address_physical_line_7',
'$address_physical_code',
'$address_postal_line_1',
'$address_postal_line_2',
'$address_postal_line_3',
'$address_postal_line_4',
'$address_postal_line_5',
'$address_postal_line_6',
'$address_postal_line_7',
'$address_postal_code',
'$fax_1',
'$fax_2',
'$phone_1',
'$phone_2',
'$phone_3',
'$phone_4') ";
Do i have to use transactional statement to run these three queries. I have never worked with transactional statements. The one statement is depending on values of the other ones.
MySQL has AUTO_COMMIT set to true by default. This means that every query in your script will be executed before the one right after.
This allows you to do something like :
// Here I admit that the table is empty, with an auto-incremented id.
INSERT INTO test VALUES ('', 'First');
INSERT INTO test ('', SELECT value FROM test WHERE id = "1");
Here, you will insert a first row with id=1, value="First" and then id=2, value="First".
I'm not sure to really understand your question but if you need to perform several SQL requests guaranteeing they are either all done or none done, you have to explicitly create and commit a transaction:
START TRANSACTION
INSERT ...
INSERT ...
INSERT ...
-- All is ready, apply "all at once"
COMMIT
http://dev.mysql.com/doc/refman/5.0/en/commit.html
Just to be clear (?), from inside your transaction, all the SQL statements appear to be executed "one by one as usual". But from outside world (other transactions/connections to you SQL server) no change would appear until you COMMIT your transaction -- and then all changes will appear "all at once".
I recently asked a question about writing to multiple tables: PHP/MySQL insert into multiple data tables on submit
I have now tried out this code and there are no errors produced in the actual code but the results I am getting are strange. When a user clicks register this 'insert.php' page is called and the code can be found below.
<?php
$username = $_POST["username"];
$password = $_POST["password"];
$institution = $_POST["institution"];
$conn = pg_connect("database connection information"); //in reality this has been filled
$result = pg_query($conn, "INSERT INTO institutions (i_id, name) VALUES (null, '$institution') RETURNING i_id");
$insert_row = pg_fetch_row($result);
$insti_id = $insert_row[0];
// INSTITUTION SAVED AND HAS ITS OWN ID BUT NO MEMBER OF STAFF ID
$resultTwo = pg_query($conn, "INSERT INTO staff VALUES (NULL, '$username', '$password', '$insti_id'");
$insert_rowTwo = pg_fetch_row($resultTwo);
$user_id = $insert_rowTwo[0];
// USER SAVED WITH OWN ID AND COMPANY ID
// ASSIGN AN INSTITUTION TO A STAFF MEMBER IF THE STAFF'S $company_id MATCHES THAT OF THE
// INSTITUION IN QUESTION
$update = pg_query($conn, "UPDATE institutions SET u_id = '$user_id' WHERE i_id = '$insti_id'");
pg_close($conn);
?>
What the result of this is just the browser waiting for a server response but there it just constantly waits. Almost like an infinite loop I'm assuming. There are no current errors produced so I think it may be down to a logic error. Any ideas?
The errors:
RETURNING clause is missing in the second INSERT statement.
Provide an explicit list of columns for your second INSERT statement, too.
Don't supply NULL in the INSERT statements if you want the column default (serial columns?) to kick in. Use the keyword DEFAULT or just don't mention the column at all.
The better solution:
Use data-moidifying CTE, available since PostgreSQL 9.1 to do it all in one statement and save a overhead and round trips to the server. (MySQL knows nothing of the sort, not even plain CTEs).
Also, skip the UPDATE by re-modelling the logic. Retrieve one id with nextval(), and make do with just two INSERT statements.
Assuming this data model (you should have supplied that in your question):
CREATE TABLE institutions(i_id serial, name text, u_id int);
CREATE TABLE staff(user_id serial, username text, password text, i_id int);
This one query does it all:
WITH x AS (
INSERT INTO staff(username, password, i_id) -- provide column list
VALUES ('$username', '$password', nextval('institutions_i_id_seq'))
RETURNING user_id, i_id
)
INSERT INTO institutions (i_id, u_id, name)
SELECT x.i_id, x.user_id, '$institution'
FROM x
RETURNING u_id, i_id; -- if you need the values back, else you are done
Data model
You might think about changing your data model to a classical n:m relationship.
Would include these tables and primary keys:
staff (u_id serial PRIMARY KEY, ...)
institution (i_id serial PRIMARY KEY, ...)
institution_staff (i_id, u_id, ..., PRIMARY KEY(i_id, u_id)) -- implements n:m
You can always define institution_staff.i_id UNIQUE, if a user can only belong to one institution.
Sorry, let me try to explain .... recordID auto increments and is my primary key ..... LISTINGID refers to the ID in a different table. In this table 1 need to increment recordListingID for each record that has the same LISTINGID. My insert statement inserts upto 10 records that have the same LISTINGID I need the the recordListingID to start at 1 and so on.
Hi guys
I am inserting records into mysql from php it can be 1 or more records I need one of the cols to increment with the first entry being 1 here is my insert code
mysql_query("INSERT INTO car_listing_images (recordID, recordText, recordListingID, LISTINGID) VALUES ('', '$fileName', '??', '$listingid')");
where I have put ?? is the col that needs to increment. How can i achieve this?
Thanks in advance!
You can use the built in Auto_Increment function of MySql
AUTO_INCREMENT
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
MySql would increment the specified field by 1 (Or what ever interval you set)
You may use user-defined variables
A preface: If you need to have 2 fields that increment, but are not tied to each other, you are probably doing it wrong. It might be better to not have recordListingID and instead just use the recordID as they will probably be the same number.
If your tables are running InnoDB you can create transactions. Then you can try something like this:
<?php
mysql_query('START TRANSACTION');
$recordListingId = mysql_result(mysql_query("SELECT count(*)+1 as num FROM car_listing_images WHERE LISTINGID=$listingid"), 'num', 0);
mysql_query("INSERT INTO car_listing_images (recordID, recordText, recordListingID, LISTINGID) VALUES ('', '$fileName', '$recordListingId', '$listingid')");
mysql_query('COMMIT');
?>
If you don't have innodb, try using a stored procedure.
Alter your table structure to include the AUTO_INCREMENT attribute for your recordListingID column, then omit the column from your insert to have it auto-populate with an incremental number.
I.e: mysql_query("INSERT INTO car_listing_images (recordID, recordText, LISTINGID) VALUES ('', '$fileName', '$listingid')");
You can initialise the variable as 1 and use the post-increment operator:
$value = 1;
for(...){
$sql = 'INSERT ...';
$value++;
}
I don't know if I really understand your question.
If you're wanting to increment a column with every record, it should be defined as an AUTO_INCREMENT column. This way, in your INSERT statement if you insert NULL into that column, it will go up every time.
Alternatively you could do fieldname+1, but AUTO_INCREMENT is always preferred.
As per my comment, you could do something like this:
$row = mysql_fetch_assoc(mysql_query("SELECT MAX(recordListingID) AS `max` FROM car_listing_images"));
$next_id = $row['max'] + 1;
mysql_query("INSERT INTO car_listing_images (recordID, recordText, recordListingID, LISTINGID) VALUES ('', '$fileName', '$next_id', '$listingid')");
I would still seriously recommend against this, it's a much much better implementation to use an AUTO_INCREMENT field.
After your last comment I would suggest the following. You will not be able to do this in MySQL directly (unless you use a variable, but this may go wrong if you're inserting multiple RecordIDs too).
$next_id = 0;
foreach ($insert as $insert_stmt) {
$next_id++;
mysql_query("INSERT INTO car_listing_images (recordID, recordText, recordListingID, LISTINGID) VALUES ('', '$fileName', '$next_id', '$listingid')");
}
i think i know what you were/are trying to accomplish. there may be a better way to it, but what i did was to "select max(id)+1 as nextId from table" and store that in a variable that i used in the secondary id field that you called "recordListingID."
that way the first row you insert will have the same id and recordListingID, but each other row will auto_inc the id, but the recordListingID will be the same as the first.
in my situation, there is only one user doing this at a time, so there is no chance of errors, but in a multi-user situation, you may want to modify this to watch out for people doing inserts at the same time. like maybe marking the last row so your query knows it's finished so you could so something like "select max(id)+1 as nextId from table where lastRow =1" or something like that.