How to use a dynamic ID for a query? - php

In my code I insert a row in my MySQL table, if it does not exist. Since the query requires an unique index, I am just inserting $id, which is just a static value of 1 (line #8).
public function prepare($author, $arr) {
$conn = new mysqli($this->servername, $this->username, $this->password, $this->db_name);
foreach ($arr as $value) {
$stmt = $conn->prepare("INSERT IGNORE INTO kh_comments(id, author,abstract) VALUES (?, ?, ?)");
$id = 1; // Just a static value
$stmt->bind_param("dss", $id, $author, $value['id']);
$stmt->execute();
$stmt->close();
$conn->close();
}
}
I would now like to use a dynamic value instead of 1. The variable $idshould be smart enough to figure out which ID is affected. Or if there is another way to do this, I appreciate any suggestions!

In MySQL you can define auto increment fields using the AUTO_INCREMENT attribute in a create table or alter table command:
CREATE TABLE animals (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (id)
);
During the insertion you just do not assign any value to that column and MySQL will automatically assign its value for you:
INSERT INTO animals (name) VALUES
('dog'),('cat'),('penguin'),
('lax'),('whale'),('ostrich');
As the linked documentation says:
You can retrieve the most recent automatically generated AUTO_INCREMENT value with the LAST_INSERT_ID() SQL function or the mysql_insert_id() C API function. These functions are connection-specific, so their return values are not affected by another connection which is also performing inserts.
In mysqli use mysqli_insert_id() function to retrieve this value.

id has an AUTO_INCREMENT value. You don't have to put a value for it. I think this was your question.

Related

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)

Last Insert ID is not returning

I have following code for inserting data into database using PDO.
It inserts data into database but not return last inserted in ID.
here userid is primary key
try {
$dbh = new PDO('mysql:host=localhost;dbname=crud_demo', "username", "password");
$sqlQuery = "INSERT INTO users(userid,first_name,last_name,email,password)
VALUES(:userid,:first_name,:last_name,:email,:password)";
$statement = $dbh->prepare($sqlQuery);
$bind = array(
":userid" => "bhavik",
":first_name" => "Bhavik",
":last_name" => "Patel",
":email" => "bhavitk#live.in",
":password" => "1234567"
);
$statement->execute($bind);
echo $dbh->lastInsertId();
} catch (PDOException $e) {
echo $e->getMessage();
}
$dbh->lastInsertId(); always return 0 whatever i insert value for userid
lastInsertId() only returns IDs automatically generated in an AUTO_INCREMENT column. Your PRIMARY KEY is apparently a string (or at least you're inserting a string in it). Since you're inserting a known value, you don't actually need to find out the inserted ID — you've specified it yourself.
The userid doesn't have an auto_increment attribute in your database, so lastInsertId() will never return anything useful.
You can only lastInsertId() if your field is:
the primary key
not null
an integer type (int, bigint, etc.)
auto_increment
first you need to check insert query.
if its run proper then use mysql function like mysql_insert_id().
if this function is run property then may be possible to mistake in your $dbh->lastInsertId()
this function.

Insert new row in a table and auto id number

I want to insert a new row in my table. I want the id to be generated right automatically and not asked from the user. The user only provides title and text. I wrote this code in PHP:
<?php
$hostname = "localhost";
$database = "mydb";
$username = "myuser";
$password = "mypsw";
$link = mysql_connect( $hostname , $username , $password ) or
die("Attention! Problem with the connection : " . mysql_error());
if (!$link)
{
die('Could not connect: ' . mysql_error());
}
mysql_query("SET NAMES ‘utf8’",$link);
mysql_select_db("mydb", $link);
$lastid=mysql_insert_id();
$lastid=$lastid+1;
$sql="INSERT INTO announcements VALUES ('$lastid',CURDATE(),'$_POST[title]','$_POST[text]')";
if (!mysql_query($sql,$link))
{
die('Error: ' . mysql_error());
}
mysql_close($link);
header("Location: announcement.php");
?>
Sadly when I test it on my website, I get this error:
Error: Duplicate entry '0' for key 'PRIMARY'
Is mysql_insert_id() not working? What is wrong?
Don't do this. mysql will happily create an auto_increment column for you:
CREATE TABLE x (
id int not null primary key auto_increment
^^^^^^^^^^^^^^---add this to your PK field
);
INSERT INTO x (id) VALUES (null); // creates id = 1
INSERT INTO x (id) VALUES (null); // creates id = 2
mysql_insert_id() only returns the last id created by the CURRENT connection. You haven't inserted any data yet when you first run it, so you get back nothing.
Your version is incredibly vulnerable to race conditions. There is NO guarantee that the last ID you retrieve with mysql_insert_id() will not ALSO get retrieved by another copy of the script running in parallel, and get sniped out from under this copy of the script.
The primary key column on announcements should be auto_increment. When you do mysql_insert_id() it retrieves the id from the last query executed from that connection.
Because the INSERT is the query you are currently performing, it errors.
Try
INSERT INTO announcements
(date_field, title, text)
VALUES (CURDATE(),'$_POST[title]','$_POST[text]')
Just replace 'date_field', 'title', and 'text' with the applicable column names.
Alternatively the following should also work, as a NULL value in the AutoIncrement value should be acceptable
INSERT INTO announcements VALUES (NULL,CURDATE(),'$_POST[title]','$_POST[text]')
As mentioned in the other suggestion posted, you should make sure that the primary key field of the announcements table is set to be auto_increment.
Just for completion, you would use mysql_insert_id() when you want to use the id for the row you just inserted, i.e. if you then want to select the row you just inserted you could do
'SELECT * FROM announcements WHERE id = '.mysql_insert_id()
The problem is that you are asking for last insert id and you didn't inserted anything.
Convert your ID field in db to be autoincrement if its not.
Insert into database your announcment
Then ask for id using mysql_insert_id to get it.
But I see that you are not using it only when inserting then you don't need that functionality anyhow. Just insert without ID like this
"insert into announcements (InsertDate, Title, Text) VALUES (CURDATE(), '$_POST[title]', '$_POST[text]')";
and you should really be careful with your queries when using values from $_POST or $_GET or any other user typed value. There is possibility to execute SQLInjection through your form fields, so I suggest you to use mysql escape command or use parameters.
I hope this helps.
Assuming your table is set up properly, with the id field as AUTO_INCREMENT, you just need to perform an INSERT where you do not specify a value for id. That means you must specify the names of the columns you are inserting. So this line:
$sql="INSERT INTO announcements VALUES ('$lastid',CURDATE(),'$_POST[title]','$_POST[text]')";
becomes this
$sql="INSERT INTO announcements (`date`,`title`,`text`) VALUES (CURDATE(),'$_POST[title]','$_POST[text]')";
I guessed what your column names might be. Obviously they need to match your table definition.
If you do this, then the mysql_insert_id() function will return the id of the row you just inserted. (That is, it gives you the value of the previous insert, not the next one.)
You probably want to add "auto increment" to the table when creating it.
This will add an id automatically when inserting something.
e.g.
CREATE TABLE announcements
(
id int NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
some_date int(11),
title varchar(200),
text varchar(3000)
);
mysql_insert_id "Retrieves the ID generated for an AUTO_INCREMENT column by the previous query " - http://php.net/manual/en/function.mysql-insert-id.php

mysql_insert_id and my woes?

I'm trying to get the auto incremented column of a row. The code will explain, but basically I'm trying to insert a row into a table called orders, and then I want to get the auto incremented number.
This is my PHP.
<?php
$db = DBConnection::connect();
$q = "INSERT INTO orders (customerid, orderdate) VALUES (".$customerid.", CURRENT_TIMESTAMP)";
$ps = $db->prepare($q);
$ps->execute();
$db = null;
echo mysql_insert_id();
?>
At this stage all I really want to do is echo out the auto number.
This is my structure
CREATE TABLE `orders` (
`orderid` int(25) NOT NULL AUTO_INCREMENT,
`customerid` int(11) NOT NULL,
`orderdate` date DEFAULT NULL,
PRIMARY KEY (`orderid`),
KEY `orderid` (`orderid`)
)
Any help would be greatly appreciated, thank you :)
DBConnection != MySQL
You can't use functions from different libraries like that. You must either change mysql_num_rows() to the DBConnection equivalent, or change the DBConnection stuff to mysql_*.
PDO is different from mysql_* functions.
Since you've used PDO, you must use the method lastInsertId() from the PDO object:
$db->lastInsertId();
Try adding
$ps->execute()
or die(mysql_error());
This may show any errors that the database query is generating

Getting the final value to this MySQL query

I've got my database set up with three tables - code, tags, and code_tags for tagging posts.
This will be the SQL query processed when a post is submitted. Each tag is sliced up by PHP and individually inserted using these queries.
INSERT IGNORE INTO tags (tag) VALUES ('$tags[1]');
SELECT tags.id FROM tags WHERE tag = '$tags[1]' ORDER BY id DESC LIMIT 1;
INSERT INTO code_tags (code_id, tag_id) VALUES ($codeid, WHAT_GOES_HERE?)
The WHAT_GOES_HERE? value at the end is what I need to know. It needs to be the ID of the tag that the second query fetched. How can I put that ID into the third query?
I hope I explained that correctly. I'll rephrase if necessary.
Edit: Thanks for your help so far but I'm still struggling a bit in regards to what was pointed out - if it's already there I can't get the inserted ID...?
If you use INSERT IGNORE and a new record is ignored (because of a unique key violation) mysql_insert_id() and LAST_INSERT_ID() don't have a meaningful value.
But you can use INSERT ... ON DUPLICATE KEY UPDATE and LAST_INSERT_ID(expr) to set the data you expect LAST_INSERT_ID() to return in case of a doublet.
Step-by-step:
Let's assume you have a table tags like
CREATE TABLE tags (
id int auto_increment,
tag varchar(32),
dummy int NOT NULL DEFAULT 0, /* for demo purposes only */
primary key(id),
unique key(tag)
)
Inserting a tag twice results in a duplicate key violation because of unique key(tag). That's probably the reason why you've used INSERT IGNORE. In that case MySQL ignores the violation but the new record is ignored as well. The problem is that you want the id of the record having tag='xyz' regardless of whether it has been newly created or it was already in the database. But right now mysql_insert_id()/LAST_INSERT_ID() can oly provide the id of a new record, not an ignored one.
With INSERT ...ON DUPLICATE you can react on such duplicate key violations. If the new record can be inserted (no violation) it behaves like a "normal" INSERT. But in case of a duplicate key violation the part after ON DUPLICATE KEY is executed like an UPDATE statement for the record with that particular index value already existing in the table. E.g. (with an empty table tags)
INSERT INTO tags (tag) VALUES ('tag A') ON DUPLICATE KEY UPDATE dummy=dummy+1
This will simply insert the record as if there was no ON DUPLICATE ... clause. id gets the next auto-increment value, dummy the default value of 0 and tag='tag A'. Let's assume the newly create auto_increment value was 1. The resulting record stored in MySQL is (id=1, tag='tag A', dummy=0) and LAST_INSERT_ID() will return 1 right after this query. So far so good.
Now if you insert the same record again with the same query a violation occurs because of the first record (id=1, 'tag=tag A', dummy=0). For this already exisitng record the UPDATE statement after ON DUPLICATE KEY is executed, i.e. the record becomes (id=1, tag='tag A', dummy=1). But since no new record has been created there was also no new auto_increment value and LAST_INSERT_ID() becomes meaningless. So still the same problem as with INSERT IGNORE.
But there is a "special" construct that allows you to set the value LAST_INSERT_ID() is supposed to return after the ON DUPLICATE KEY UPDATE statement has been executed.
id=LAST_INSERT_ID(id)
Looks strange but it really only sets the value LAST_INSERT_ID() will return.
If you use the statement
INSERT INTO
tags
(tag)
VALUES
('xyz')
ON DUPLICATE KEY UPDATE
id=LAST_INSERT_ID(id)
LAST_INSERT_ID() will always return the id of the record having tag='xyz' no matter if it was added by the INSERT part or "updated" by the ON DUPLICATE KEY part.
I.e. if your next query is
INSERT INTO
code_tags
(code_id, tag_id)
VALUES
(4711, LAST_INSERT_ID())
the tags.id for the tag 'xyz' is used.
The self-contained example script uses PDO and prepared statements. It should do more or less what you want to achieve.
$pdo = new PDO("mysql:host=localhost;dbname=test", 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// set up temporary table and demo data
$pdo->exec('CREATE TEMPORARY TABLE tmpTags (id int auto_increment, tag varchar(32), primary key(id), unique key(tag))');
$pdo->exec('CREATE TEMPORARY TABLE tmpCode_tags (code_id int, tag_id int)');
$pdo->exec("INSERT INTO tmpTags (tag) VALUES ('tagA'), ('tagB')");
// prepare the statements
// set id=LAST_INSERT_ID(id), so LAST_INSERT_ID() gets a value even if the record is "ignored"
$stmtTags = $pdo->prepare('
INSERT INTO
tmpTags
(tag)
VALUES
(:tag)
ON DUPLICATE KEY UPDATE
id=LAST_INSERT_ID(id)
');
$stmtTags->bindParam(':tag', $tag);
$stmtCodeTags = $pdo->prepare('INSERT INTO tmpCode_tags (code_id, tag_id) VALUES (:codeid, LAST_INSERT_ID())');
$stmtCodeTags->bindParam(':codeid', $codeid);
// and some new records we want to insert
$testdata = array(
array('codeid'=>1, 'tags'=>'tagA tagC'), // tagA is already in the table "tags", tagC is a "new" tag
array('codeid'=>2, 'tags'=>'tagC tagD tagE') // tagC will already be inserted, tagD and atgE are "new"
);
// process (test)data
foreach($testdata as $data) {
// the parameter :codeid of $stmtCodeTags is bound to $codeid; assign it the "current" value
$codeid = $data['codeid'];
// split the tags
$tags = explode(' ', $data['tags']);
foreach($tags as $tag) {
// the parameter :tag is bound to $tag
// nothing more to do than to execute the statement
$stmtTags->execute();
// the parameter :codeid is bound to $codeid which was set to $codeid=$data['codeid']
// again nothing more to do than to execute the statement
$stmtCodeTags->execute();
}
}
unset($stmtTags);
unset($stmtCodeTags);
// let's see what we've got
$query = '
SELECT
ct.code_id, t.tag
FROM
tmpCode_tags as ct
JOIN
tmpTags as t
ON
ct.tag_id=t.id
';
foreach( $pdo->query($query, PDO::FETCH_NUM) as $row ) {
echo join(', ', $row), "\n";
}
prints
1, tagA
1, tagC
2, tagC
2, tagD
2, tagE
edit2: In case the PDO-part of the script and the prepared statements are intimidating, here's the same thing using the old php-mysql module. But I urge you to use parametrized prepared statements. Doesn't have to be PDO but I happen to like it. E.g. the mysqli module provides prepared statements as well, the old mysql module doesn't.
$mysql = mysql_connect('localhost', 'localonly', 'localonly') or die(mysql_error());
mysql_select_db('test', $mysql) or die(mysql_error());
// set up temporary table and demo data
mysql_query('CREATE TEMPORARY TABLE tmpTags (id int auto_increment, tag varchar(32), primary key(id), unique key(tag))', $mysql) or die(mysql_error());
mysql_query('CREATE TEMPORARY TABLE tmpCode_tags (code_id int, tag_id int)', $mysql) or die(mysql_error());
mysql_query("INSERT INTO tmpTags (tag) VALUES ('tagA'), ('tagB')", $mysql) or die(mysql_error());
// and some new records we want to insert
$testdata = array(
array('codeid'=>1, 'tags'=>'tagA tagC'), // tagA is already in the table "tags", tagC is a "new" tag
array('codeid'=>2, 'tags'=>'tagC tagD tagE') // tagC will already be inserted, tagD and atgE are "new"
);
// "prepare" the statements.
// This is nothing like the server-side prepared statements mysqli and pdo offer.
// we have to insert the parameters into the query string, i.e. the parameters must
// be escaped so that they cannot mess up the statement.
// see mysql_real_escape_string() for string literals within the sql statement.
$qsTags = "
INSERT INTO
tmpTags
(tag)
VALUES
('%s')
ON DUPLICATE KEY UPDATE
id=LAST_INSERT_ID(id)
";
$qsCodeTags = "
INSERT INTO
tmpCode_tags
(code_id, tag_id)
VALUES
('%s', LAST_INSERT_ID())
";
foreach($testdata as $data) {
// in this example codeid is a simple number
// let's treat it as a string literal in the statement anyway
$codeid = mysql_real_escape_string($data['codeid'], $mysql);
$tags = explode(' ', $data['tags']);
foreach($tags as $tag) {
// now $tag is certainly a string parameter
$tag = mysql_real_escape_string($tag, $mysql);
$query = sprintf($qsTags, $tag);
mysql_query($query, $mysql) or die(mysql_error());
$query = sprintf($qsCodeTags, $codeid);
mysql_query($query, $mysql) or die(mysql_error());
}
}
// let's see what we've got
$query = '
SELECT
ct.code_id, t.tag
FROM
tmpCode_tags as ct
JOIN
tmpTags as t
ON
ct.tag_id=t.id
';
$result = mysql_query($query, $mysql) or die(mysql_error());
while ( false!==($row=mysql_fetch_row($result)) ) {
echo join(', ', $row), "\n";
}
If I understand what you're attempting to achieve correctly, the second query is un-necessary - use mysql_insert_id to obtain the ID of previously inserted row, which is I presume what you need for "WHAT_GOES_HERE".

Categories