MySQL updating an unknown number of fields - php

With an INSERT statement I can do something like this, passing in an unknown number of placeholders and values:
$insert_SQL = $db->prepare("INSERT INTO laptops ($fields) VALUES ($placeholders)");
$insert_SQL->execute([$values]);
Is there a similar method when you're updating a record but don't know the number of values? Something like this:
$update_SQL = $db->prepare("UPDATE laptops ($fields) VALUES ($placeholders) WHERE id = $id");
$update_SQL->execute([$values]);

Sort of. You could use REPLACE INTO:
$update_SQL = $db->prepare("REPLACE INTO laptops ($fields) ($placeholders)");
$update_SQL->execute([$values]);
Caveats:
$fields must include id. $values must include $id.
The table must have a primary key or unique index on id. It uses this to determine if a matching row already exists.
It will delete and insert a row, not actually update it. This might matter if you have triggers on the table or for some performance considerations.

Related

INSERT INTO two different tables, but have the same ID?

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);

Linking existing MySQL records in new query, PHP/PDO

$insert = $dbh->prepare('INSERT INTO tags (tag_name) VALUES (:tag)');
$insert->bindParam(':tag', $tag, PDO::PARAM_STR);
foreach($tags as $tag) {
$insert->execute();
$tag_id = $dbh->lastInsertID();
echo $tag_id."+".$photo_id."<br />";
$sql = "INSERT INTO tagrefs (tag_id, photo_id) VALUES (:tag_id,:photo_id)";
$q = $dbh->prepare($sql);
$q->execute(array(':tag_id'=>$tag_id,
':photo_id'=>$photo_id));
}
This particular piece of code inserts tags related to uploaded photos into a table called 'tags'. It links the tag_id to the photo_id in a table called 'tagrefs'. This all works fine, until I use a tag twice. Which is logical, because nothing is inserted (tags are unique, I simply want the entry in 'tagrefs' to list the photo_id for my next photo with tag_id's that already exist)
How do I make it so that my code compares the tags the user put in and compares them, or that the values of existing tags are returned and put into 'tagrefs' properly? Thank you very much in advance for your time.
If you use INSERT ... ON DUPLICATE KEY UPDATE, then lastInsertID() will return the AUTO_INCREMENT field's value of a matched row even if an UPDATE is performed instead of an insertion.
To ensure that it also works in versions of MySQL prior to v5.1.12, one can explicitly set the insertion id with MySQL's LAST_INSERT_ID() function:
INSERT INTO tags
(tag_name)
VALUES
(:tag)
ON DUPLICATE KEY UPDATE
id = LAST_INSERT_ID(id)

INSERT into Table On Columns That Exist

Suppose I have a very large array of information for a user:
$user=array(
"name"=>"john",
"ip"=>"xx.xx.xx.xx",
"email"=>"john#something.com",
//lots more values
)
Let's also suppose that this information needs to go into more than one table. For instance a username needs to go table users, address needs to go into a details table, etc.
Now, I use a certain self-made function to insert into my tables that matches array keys to column names and array values to the values being inputted. Something similar to this:
function insert_sql($table, arr $values){
GLOBAL $dbc;
$sql="INSERT INTO `$table` (".implode(array_keys($values), ", ").") VALUES (".implode(array_values($values), ", ").")";
$dbc->prepare($sql)->execute();
return $dbc->lastInsertId();
}
//I don't actually use this function, just trying to show you what is being accomplished.
The problem is that my function uses all the keys and all the values, so when I just need certain parts of the array put into multiple tables, it doesn't work.
The question is:
How do I make an INSERT statement ignore a column if it doesn't exist? So if I insert name,email,address, into table users, but this table doesn't have an address column, I need it to insert the row with the name and email but simply ignore the fact that the address column is not there.
EDIT: The other option is to make an array with the columns of a table and use it to filter the values array. Although I am not really sure how to set this up.
Find given table column names:
SELECT
column_name
FROM
information_schema.columns
WHERE
table_name = 'tablename'
And then just whitelist your keys in $values array
Example:
function insert_sql($table, array $values){
global $connection;
$query = "SELECT column_name FROM information_schema.columns WHERE table_name = :tablename";
/* #var $stmt PDOStatement */
$stmt = $connection->prepare($query);
$stmt->execute(array(
'tablename' => $table
));
$columns = array_flip($stmt->fetchAll(PDO::FETCH_COLUMN, 0));
$values = array_intersect_key($values, $columns);
var_dump($values);
}
How do I make an INSERT statement ignore a column if it doesn't exist?
So if I insert name,email,address, into table users, but this table
doesn't have an address column, I need it to insert the row with the
name and email but simply ignore the fact that the address column is
not there.
You can't
Instead you should map your data to the appropriate tables with separate inserts.

How do I get all the ids of the row created by one multiple row insert statement

I'm new to php. So, please forgive me if this seems like a dumb question.
Say i have a MySQL insert statement insert into table (a,b) values (1,2),(3,4),(5,6). table 'table' has a auto increment field called 'id'.
how can I retrieve all the ids created by the insert statement above?
It will be great if i get an example that uses mysqli.
You can't. I would suggest that you maintain your own ids (using guid or your own auto-increment table) and use it when you insert into the table.
But it's possible to get the auto-increment value for the last inserted using LAST_INSERT_ID():
http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
AngeDeLaMort's answer is almost right. Certainly, the most appropriate way to deal with the problem is to insert one row at a time and poll the insert_id or generate the sequence elsewhere (which has additional benefits in terms of scalability).
I'd advise strongly against trying to determine the last insert_id and comparing this the most recent insert_id after the insert - there's just too may ways this will fail.
But...an alternative approach would be:
....
"INSERT INTO destn (id, data, other, trans_ref)
SELECT id, data, other, connection_id() FROM source";
....
"SELECT id FROM destn WHERE trans_ref=connection_id()";
....
"UPDATE destn SET trans_ref=NULL where trans_ref=connection_id()";
The second query will return the ids generated (note that this assumes that you use the same connection for all 3 queries). The third query is necessary because connection ids to go back into the pool when you disconnect (i.e. are reused).
C.
In some cases, if you have another identifier of sort such as a UserID, you could filter your query by UniqueID's greater than or equal to mysql_insert_id(), limit by the number of affected rows and only display those by the user. This would really only work inside of a transaction.
$SQL = "INSERT INTO Table
(UserID, Data)
VALUES
(1,'Foo'),
(1,'Bar'),
(1,'FooBar')";
$Result = mysql_query($SQL);
$LastID = mysql_insert_id();
$RowsAffected = mysql_affected_rows();
$IDSQL = "SELECT RecordID
FROM Table
WHERE UserID = 1
AND RecordID >= '$LastID'
LIMIT '$RowsAffected'";
$IDResult = mysql_query($IDSQL);
as a follow up to AngeDeLaMort:
You could seperate your inserts and do it something like this:
$data = array (
array(1,2),
array(3,4),
array(5,6)
);
$ids = array();
foreach ($data as $item) {
$sql = 'insert into table (a,b) values ('.$item[0].','.$item[1].')';
mysql_query ($sql);
$id[] = mysql_insert_id();
}
Now all your new id's are in the $id array.
Maybe I can do this
$insert = "insert into table (a,b) values (1,2),(3,4),(5,6)";
$mysqli->query($insert);
$rows_to_be_inserted=3;
$inserted_id = $mysqli->insert_id // gives me the id of the first row in my list
$last_row_id = ($inserted_id+$rows_to_be_inserted)-1;
$mysql->query("select * from table where id between $inserted_id and $last_row_id");
what to you guys say?

Check if exists, if so, update by 1++, if not insert

Hey guys quick question, I currently have an insert statement
$query= "INSERT into new_mail VALUES ('$to1', '0')"; where fields are username, and message_number
Currently what I would do to check if the entry exists, is do a select query then check the number of rows with mysql_num_rows (php). If rows==1 then I get the current message_number and set it equal to
$row['message_number']+1.
Then I update that entry with another query.
Is there an easier way to do all this in just mysql with just one query (check if exists, if not insert, if so update message_number, increase by 1)?
Depending on how your table is structured, you may be able to use the ON DUPLICATE KEY UPDATE (link to the MySQL manual) feature of INSERT:
INSERT into new_mail VALUES ('$to1', '0') ON DUPLICATE KEY UPDATE message_number=message_number+1
Use INSERT...ON DUPLICATE KEY UPDATE. The MySQL manual has an example which does almost exactly what you need:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
To make this work you need to add a UNIQUE index on the column that you use to check for duplicates. There is one important warning though:
In general, you should try to avoid using an ON DUPLICATE KEY clause on tables with multiple unique indexes.
Got a little confused by your question and your table structures but I think you want something like this.
INSERT INTO new_mail (username, message_number)
VALUES ($username, $message_number)
ON DUPLICATE KEY UPDATE message_number=message_number + 1;
This is presuming username is your primary key (more likely something like userid). Hope this helps.
EDIT: The ON DUPLICATE KEY UPDATE answers are better, but you could do this (eludes the select query):
Assuming you're using the mysqli extenson:
$db = //Some construction of mysqli object;
$sql = 'UPDATE tablename SET RowValue = RowValue + 1 WHERE message_number = ?';
$updateStatement = $db->prepare($sql);
$updateStatement->bind_param('i', $message_number);
$message_number = //Set message number;
$updateStatement->execute();
if ($updateStatement->affectedRows == 0) {
$sql = 'INSERT INTO tablename (RowValue, message_number) VALUES (?, ?)';
$insertStatement = $db->prepare($sql);
$insertStatement->bind_param('ii', $rowValue, $messageNumber);
$rowValue = something;
$messageNumber = something;
$insertStatement->execute();
}

Categories