After looking around on stackoverflow, I'm still having a little trouble understanding the one-to-many relationship in mysql. I have a request coming in from the user (form submission) which will be stored in one table. This is a dynamic form that lets the user add extra fields therefore those will be stored in a separate table. So in short, in my db design, there will be one table for the users with PRIMARY KEY AUTO INCREMENT and there will be another table for the hostnames PER user (multiple fields -array) and using a foreign key that references to the primary key in the user table. Sorry if this is long but trying to make this a good question.
Example:
User Table: (ONE)
1. John Doe, blah, 11-12-15
2. Sally Po, blah, 11-14-15
3. John Doe, blah, 11-15-15
(these are three separate requests)
(numbers are primary key auto incr.)
Host Name Table: (MANY)
1. www.johndoe.com
1. www.johndoe2.com
1. www.johndoe3.com
2. www.sallypo.com
2. www.sallypo2.com
(these numbers (foreign key) should match the primary key for each request)
Code (Leaving out the actual queries + pretty sure I shouln't be using last_id):
$sql = "CREATE TABLE IF NOT EXISTS userTable (
id int AUTO_INCREMENT,
firstName VARCHAR(30) NOT NULL,
date DATE NOT NULL,
PRIMARY KEY (id)
)";
//query
$sql = "CREATE TABLE IF NOT EXISTS hostNamesTable (
id int NOT NULL,
hostName VARCHAR(90) NOT NULL,
FOREIGN KEY (id) REFERENCES userTable(id)
)";
//query
$sql = "INSERT INTO userTable (firstName, date)
VALUES ('$firstName', '$date')";
//query
$last_id = mysqli_insert_id();
for($i = 0; $i < sizeof($hostName); $i++){
$sql = "INSERT INTO hostNamesTable (id, hostName)
VALUES ('$last_id', '$hostName[$i]')";
//query
}
What am I doing wrong? (is this the right way to go about it?)
note: I was trying to get the last_id of the user Table so that I can use it in the hostName table as the foreign key
EDIT: I'm using MySQLi with php
EDIT 2:
After the changes, this is the error I am getting now: Cannot add or update a child row: a foreign key constraint fails (d9832482827984hb28397429.hostNamesTable, CONSTRAINT hostNamesTable_ibfk_1 FOREIGN KEY (id) REFERENCES userTable (id))Error: INSERT INTO hostNamesTable (id, hostName, ) VALUES ('', 'secondhost.net')
--Looks like the $last_id isn't even being recorded?
EDIT 3: Started working. Not sure what it was but I think it was because of some type.
why dont you just add an extra column in the hostNames table which is called "ref_user" and contains the ID of the user you are reffering to? So you can use unique IDs in both tables.
Make a query like:
SELECT * FROM hostNames WHERE ref_user = (SELECT id FROM userTable WHERE <uniqueColumn> = <uniqueIdentifierOfUser>);
But the included request must return only one line from users.
try adding mysqli $link as a parameter in your mysqli_insert_id
$last_id = mysqli_insert_id($link);
i presume you have this somewhere in your code
$link = mysqli_connect("localhost", "mysql_user", "mysql_password", "mysql_db");
if this doesn't work, try using mysql LAST_INSERT_ID() function
$last_id = $mysqli->query("SELECT LAST_INSERT_ID() AS last_id")->fetch_object()->last_id;
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();
}
I'm getting the error: Duplicate entry '0' for key 'PRIMARY'
the query which is being ran is:
INSERT INTO cars (make, model, Reg, colour, miles, price, dealerID, mpg, mph) VALUES ('cake', 'pie', 'k', 'blue', '100', '10', '9', '40', '80')
The primary key for the table is carIndex and is set as Auto Increment, as-well as not being mentioned in the query I don't understand this error. It keeps trying to place the new entry at the very start of the table instead of just adding it on.
The PHP which generates this query is:
function addcar()
{
session_start();
if (isset($_SESSION['user']))
{
$db = mysqli_connect('localhost', 'root', '', 'cdb')
or die('Error connecting');
$query = "INSERT INTO cars (make, model, Reg, colour, miles, price, dealerID, mpg, mph)
VALUES (
'".$_POST['manufacture']."',
'".$_POST['model']."',
'".$_POST['reg']."',
'".$_POST['colour']."',
'".$_POST['mileage']."',
'".$_POST['price']."',
'".$_SESSION['dealerID']."',
'".$_POST['mpg']."',
'".$_POST['mph']."'
)
";
$addcarquery = mysqli_query($db, $query)
or die("Error in query: '$query'");
}
}
Edit:
Table structure, sure how to do the visual example I've seen before so I'll describe.
It is made up of 8 fields, the 7 seen in the query + the Primary key of carIndex, currently the only relation ship is between dealerID and a table called dealers, with carIndex set as Auto Increment.
Edit2:
So.... I restarted XAMPP... and well yeah all seems to work fine now -.-' Sorry y'all.
$query = "INSERT INTO cars (carIndex, make, model, Reg, colour, miles, price, dealerID, mpg, mph)
VALUES (
'',
'".$_POST['manufacture']."',
...
One possibility is that it's not the PRIMARY KEY constraint on the cars table that is throwing the error, if there's a trigger being fired that is performing an INSERT. (We can't tell from the name of the constraint PRIMARY that it's definitely the cars table.)
Also, verify that the AUTO_INCREMENT attribute is defined on the PRIMARY KEY column. The output from SHOW CREATE TABLE cars is a quick way to verify the current table definition.
You need to provide us tables structure so we can precisely answer to your question.
Anyway, error You get Duplicate entry '0' for key 'PRIMARY' usually means that for some reason your primary key is NOT defined as AUTO_INCREMENT so when you not explicitly set values for it in query it will always evaluate to 0 and will produce error like those one.
To be precise, you will get such error after you try to insert second record. In empty table this query can pass and will assign 0 for your primary key but on next insert query will fail because you already have value 0 of primary key for first inserted record.
I have a database of Users and another table for Teachers. Teachers have all the properties as a user but also an e-mail address. When inserting into the DB how can I insert the info, ensuring that the ID is the same for both?
the ID currently is on automatic incrament.
this is what I have at the moment:
$sqlQuery="INSERT INTO user(firstName,lastName,DOB,title,password,classRoomID)
VALUES('$myFirstName','$myLastName','$myDOB','$myTitle','$newPassword','$myClassRoom')";
$result=mysql_query($sqlQuery);
$sqlQuery = "INSERT INTO teacher(email) VALUES ('$myEmail')";
$result=mysql_query($sqlQuery);
thank you!
use MYSQL function LAST_INSERT_ID()
OR php mysql http://ro1.php.net/manual/en/function.mysql-insert-id.php
why to use separate table for teachers. instead, you can have email field with in user table and additional field with flag (T ( for teacher) and U (for user). Default can be a U. This have following Pros.
Will Not increase table size as email would be varchar
Remove extra overhead of maintaining two tables.
Same Id can be used
If you want to have that as separate table then answer you selected is good one but make sure last insert id is called in same connection call.
After the first insert, fetch the last inserted id:
$last_id = mysqli_insert_id(); // or mysql_insert_id() if you're using old code
Or you could expand your second query and use mysql's integrated LAST_INSERT_ID() function:
$sqlQuery = "INSERT INTO teacher(id, email) VALUES ((SELECT LAST_INSERT_ID()), '$myEmail')";
Try this:
$sqlQuery="INSERT INTO user(firstName,lastName,DOB,title,password,classRoomID)
VALUES('$myFirstName','$myLastName','$myDOB','$myTitle','$newPassword','$myClassRoom')";
$result=mysql_query($sqlQuery);
$id = mysql_insert_id();
$sqlQuery = "INSERT INTO teacher(id, email) VALUES (' $id ','$myEmail')";
$result=mysql_query($sqlQuery);
Insert data into two tables & using the same ID
First method
$sqlQuery1 = "INSERT INTO user(firstName,lastName,DOB,title,password,classRoomID) VALUES('$myFirstName','$myLastName','$myDOB','$myTitle','$newPassword','$myClassRoom')";
$result1 = mysqli_query($conn, $sqlQuery1);
$lastID = mysqli_insert_id($conn);
$sqlQuery2 = "INSERT INTO teacher(email, lastID) VALUES ('$myEmail', 'lastID')";
$result2 = mysqli_query($conn, $sqlQuery2);
If the first method not work then this is the second method for you
$sqlQuery1 = "INSERT INTO user(firstName,lastName,DOB,title,password,classRoomID) VALUES('$myFirstName','$myLastName','$myDOB','$myTitle','$newPassword','$myClassRoom')";
$result1 = mysqli_query($sqlQuery1);
$sqlQuery2 = "INSERT INTO teacher(email) VALUES ('$myEmail')";
$result2 = mysqli_query($sqlQuery2);
You can set the Foreign Key in your database table (phpMyAdmin/ MySQL Workbench) to let the Foreign Key follow the Primary Key (ID). Then the data after insert will auto-follow the Primary Key ID.
Example here,
Teachers table set ID - Primary Key
Users table set UserID - Foreign Key (will follow the Teachers table ID)
if you're using MySQL WorkBench, you can refer to this link to set a foreign key.
https://dev.mysql.com/doc/workbench/en/wb-table-editor-foreign-keys-tab.html
Hope I can help any of you.
Though you can use the LAST_INSERT_ID() function in order to get the last insert id, the best approach in this case is to create a column reference to user id table.
teacher
id | user_id | email
So the teacher.id could be anyting, but the user_id column is the real reference to user table.
If you use InnoDB table, you can make the database consistent using Foreign keys
You Should Use A Transaction In MySQL. First insert In One Table And GET LAST_INSERT_ID().
Insert LAST_INSERT_ID() In Second Table.
$sqlQuery="INSERT INTO user(firstName,lastName,DOB,title,password,classRoomID)
VALUES('$myFirstName','$myLastName','$myDOB','$myTitle','$newPassword','$myClassRoom')";
$sqlQuery = "INSERT INTO teacher(LAST_INSERT_ID(), email) VALUES (' $id ','$myEmail')";
$result=mysql_query($sqlQuery);
I have a form to edit a record (specimen). On the form is a multiple select list which contains records from a table (topic). This select list shows topics as selected that exist for the specimen (as identified in the specimen_topic lookup table) as well as those that can be added to the specimen (from the topic table).
I want to be able to add topics not selected in the list to the lookup table where the topic_fk does not already exist for the specimen_fk:
CREATE TABLE IF NOT EXISTS `specimen_topic_lookup` (
`specimen_topic_lookup_pk` int(6) NOT NULL AUTO_INCREMENT,
`specimen_fk` int(6) NOT NULL,
`topic_fk` int(3) NOT NULL,
PRIMARY KEY (`specimen_topic_lookup_pk`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci AUTO_INCREMENT=8 ;
Any ideas how I can do this?
UPDATE
I have made the fields specimen_fk and topic_fk UNIQUE. Using the code below, only one record is created in specimen_table lookup, when two records should have been created (before making the fields UNIQUE, two records were created OK...). I assume this is because $specimen_pk is the same value for each insert.
foreach($topics as $topic){
$query_topics = "INSERT IGNORE INTO specimen_topic_lookup(specimen_fk, topic_fk)
VALUES ('$specimen_pk', '$topic')";
$result_topics = mysql_query($query_topics, $connection) or die(mysql_error());
}
Looks like having UNIQUE is stopping having a record made with the same value (which is at least what I expected...)
THIS WORKS
Without having to make specimen_fk OR topic_fk UNIQUE...
foreach($topics as $topic){
$query_topics = "INSERT INTO specimen_topic_lookup(specimen_fk, topic_fk)
SELECT '$specimen_pk', '$topic'
FROM DUAL
WHERE NOT EXISTS (SELECT 1
FROM specimen_topic_lookup
WHERE specimen_fk = '$specimen_pk' AND topic_fk = '$topic')";
$result_topics = mysql_query($query_topics, $connection) or die(mysql_error());
Create a unique index on the table and use insert ignore or on duplicate key update:
create unique index specimen_topic_lookup(specimen_fk, topic_fk);
insert ignore into specimen_topic_lookup(specimen_fk, topic_fk)
select $speciment_fk, $topic_fk;
Or, alternatively, you can just do the following without the unique index:
insert into specimen_topic_lookup(specifmen_fk, topic_fk)
select $speciment_fk, $topic_fk
from dual
where not exists (select 1
from specimen_topic_lookup
where specimen_fk = $specimen_fk and topic_fk = $topic_fk
);
Use an INSERT IGNORE statement. This will insert any rows that do not violate the unique key, and ignore the ones that do.
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.