I've got this test table:
CREATE TABLE IF NOT EXISTS `test` (
`id` INT(10) AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4;
inserting using either of these three
INSERT INTO `test` (`id`) VALUES (NULL);
INSERT INTO `test` (`id`) VALUES (0);
INSERT INTO `test` () VALUES ();
and issuing
SELECT LAST_INSERT_ID();
but the query always results in 0.
PHP's mysql_insert_id and PDO::lastInsertId() yield no result either.
I've been toying with this whole day and can't get it to work. Ideas?
The problem seemed to be in MySQL's phpmyadmin config file PersistentConnections set to FALSE which resulted in a new CONNECTION_ID every time a query was issued - therefore rendering SELECT LAST_INSERT_ID() ineffective.
more info in the subsequent topic Every query creates a new CONNECTION_ID()
Also thanks dnagirl for help
Just my 50 cents for this issue, I simply noticed that you won't get a LAST_INSERT_ID greater than 0 if your table has no AUTO_INCREMENT set to an index.
I wasted about half hour on this. Turns out I keep getting a LAST_INSERT_ID() of 0, which for this table is actually ok.
you have to combine
INSERT INTO test (title) VALUES ('test');SELECT LAST_INSERT_ID();
Then you will get the last insert id
I had the same issue. mysql_insert_id() or LAST_INSERT_ID() returned 0 when requested inside a PHP function with an INSERT query.
I sorted the issue by requesting the value of mysql_insert_id() from a separate PHP function called right after the function that INSERT query.
I Had the same issues but I have resolved this by creating a transaction.
$db->begin();
$sql = "INSERT INTO 'test' VALUES('test')";
if ($db->query($sql))
{
$id = $db->last_insert_id('test');
$db->commit();
return $id;
}
else{
$db->rollback();
return -1;
}
I had tried
return $db->last_insert_id('test');
after the "commit" but that always returned "0"
hope that can help you
it work perfectly...try it...
$result = mysql_query("INSERT INTO `test` (`title`) VALUES ('test')");
if ($result) {
$id = mysql_insert_id(); // last inserted id
$result = mysql_query("SELECT * FROM tablename WHERE id = $id") or die(mysql_error());
// return user details
if (mysql_num_rows($result) > 0) {
return mysql_fetch_array($result);
} else {
return false;
}
} else {
return false;
}
Related
I am performing an INSERT query in my database as such:
$query = "INSERT IGNORE INTO user VALUES ('', 0, $safe_email, '$hashed_password')";
$result = $db->query($query);
The 3rd row in the db table is email which I have set a unique constraint to.
If I try to insert a duplicate email, with the above query notice I have the INSERT IGNORE which won't insert the record if it is a duplicate to one that already exists in the db, however it won't give an error or any kind of indication that a duplicate record is trying be inserted.
I want to show a nice error message if a duplicate is found but with the INSERT IGNORE I am struggling to do this because it won't show an error it will just ignore the query.
So I need something like:
IF (duplicate entry found in db){
echo "User already exists";
}
END IF
Use normal insert query and implement the query in try-catch statement. 'Insert' query will fail if you try to insert same email since it is unique constraint. So you can catch the exception as the 'Insert' query fails.
Example:
try {
"your insert query";
} catch (Exception $e) {
"your insert failure exception"
}
NB: you can catch all the exceptions that occurred during the execution of insert query which will be more helpful
As per documentation on INSERT ... IGNORE:
If you use the IGNORE keyword, errors that occur while executing the INSERT statement are ignored. For example, without IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted. With IGNORE, the row still is not inserted, but no error occurs. Ignored errors may generate warnings instead, although duplicate-key errors do not.
You can issue a show warnings; or any compatible similar statement from your scripting language or SQL interface. If it returns one or more such warnings, may be one of them can be on such insertion issues. Using them, you can show proper error or consoling message to the end user.
Edit 1:
... but ... how do I throw my own error message instead of the default exception when using INSERT without the IGNORE.
You can define a BEFORE INSERT trigger to identify duplicate data row and throw custom error message when found one.
Example:
delimiter //
drop trigger if exists bi_table_trigger //
CREATE TRIGGER bi_table_trigger BEFORE INSERT ON table
FOR EACH ROW
BEGIN
declare rowCount int default 0;
declare error_message varchar(1024) default '';
SELECT COUNT(1) into rowCount FROM table
WHERE email = NEW.email;
IF ( rowCount > 0 ) THEN -- if( rowCount ) -- too works
set error_message =
concat( error_message, 'User with email \'' );
set error_message =
concat( error_message, NEW.email, '\' ' );
set error_message =
concat( error_message, 'already exists' );
-- throw the error
-- User with email '?' already exists ( example )
signal sqlstate 1062 set message_text = error_message;
END IF;
END;//
delimiter ;
What I'm trying to do is INSERT subscribers in my database, but IF EXISTS it should UPDATE the row, ELSE INSERT INTO a new row.
Ofcourse I connect to the database first and GET the $name, $email and $birthday from the url string.
$con=mysqli_connect("localhost","---","---","---");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$name=$_GET['name'];
$email=$_GET['email'];
$birthday=$_GET['birthday'];
This works, but just adds the new row;
mysqli_query($con,"INSERT INTO subs (subs_name, subs_email, subs_birthday)
VALUES ('$name', '$email', '$birthday')");
mysqli_close($con);
Here's what I tried;
mysqli_query($con,"INSERT INTO subs (subs_name, subs_email, subs_birthday)
VALUES '$name', '$email', '$birthday'
ON DUPLICATE KEY UPDATE subs_name = VALUES($name), subs_birthday = VALUES($birthday)");
mysqli_close($con);
and
mysqli_query($con,"IF EXISTS (SELECT * FROM subs WHERE subs_email='$email')
UPDATE subs SET subs_name='$name', subs_birthday='$birthday' WHERE subs_email='$email'
ELSE
INSERT INTO subs (subs_name, subs_email, subs_birthday) VALUES ('$name', '$email', '$birthday')");
mysqli_close($con);
and
mysqli_query($con,"IF NOT EXISTS(SELECT * FROM subs WHERE subs_email='$email')
Begin
INSERT INTO subs (subs_name, subs_email, subs_birthday)
VALUES ('$name', '$email', '$birthday')
End");
mysqli_close($con);
But none of them work, what am I doing wrong?
Any help is greatly appreciated!
Create a UNIQUE constraint on your subs_email column, if one does not already exist:
ALTER TABLE subs ADD UNIQUE (subs_email)
Use INSERT ... ON DUPLICATE KEY UPDATE:
INSERT INTO subs
(subs_name, subs_email, subs_birthday)
VALUES
(?, ?, ?)
ON DUPLICATE KEY UPDATE
subs_name = VALUES(subs_name),
subs_birthday = VALUES(subs_birthday)
You can use the VALUES(col_name) function in the UPDATE clause to
refer to column values from the INSERT portion of the INSERT ... ON
DUPLICATE KEY UPDATE - dev.mysql.com
Note that I have used parameter placeholders in the place of string literals, as one really should be using parameterised statements to defend against SQL injection attacks.
Try this:
INSERT INTO `center_course_fee` (`fk_course_id`,`fk_center_code`,`course_fee`) VALUES ('69', '4920153', '6000') ON DUPLICATE KEY UPDATE `course_fee` = '6000';
INSERT ... ON DUPLICATE KEY UPDATE
is a good solution as long as you don't mind AUTO_INCREMENT counters unnecessarily incrementing every time you end up doing an UPDATE. Since it tries to INSERT first, I noticed auto counters do increment.
Another solution I like that may be less performant, but easy to maintain is:
IF EXISTS(SELECT 1 FROM table WHERE column = value...) THEN
UPDATE table
SET column = value ...
WHERE other_column = other_value ...;
ELSE
INSERT INTO table
(column1, column2, ...)
VALUES
(value1, value2, ...);
END IF;
I understand that there exists INSERT IGNORE and INSERT ... ON DUPLICATE KEY UPDATE. However, when there is a duplicate key, I'd like to do a INSERT to a temporary table to keep a record of the unique key that has been violated, so that I can output it to the user.
Is there any way I can do a ON DUPLICATE INSERT? If it helps, I'm trying to do a bulk insert.
With ON DUPLICATE KEY UPDATE, you cannot insert into another table - nor is there an alternative function available.
Two custom/alternative ways you can accomplish this:
Using a stored procedure as outlined in the accepted answer to this question: MySQL ON DUPLICATE KEY insert into an audit or log table
Creating a trigger that logged every INSERT for your table into another table and querying the table full of "logs" for any duplicates.
Something similar to this should work:
CREATE TABLE insert_logs (
id int not null
);
delimiter |
CREATE TRIGGER insert_logs_trigger BEFORE INSERT ON your_table
FOR EACH ROW BEGIN
INSERT INTO insert_logs SET id = NEW.id;
END;
|
To get a list of the duplicates in the table, you could us:
SELECT id FROM insert_logs HAVING COUNT(id) > 1 GROUP BY id;
Maybe this could be helpful:
$time = time();
$countme = 1;
while ($countme > 0) {
$stmt = $mysqli->prepare("INSERT INTO loads (dte,filecode,id,acct,nmbr) VALUES (?,?,?,?,?) ON DUPLICATE KEY UPDATE dte = dte");
$stmt->bind_param("sssss", $time, $filecode, $id, $acct, $number);
$stmt->execute();
$countme++;
if ($stmt->affected_rows === 1) {
$countme = 0; // all is good
} else {
$time = $time + 1;
}
if ($countme === 4) {
exit;
}
}
recently i've been searching for a solution to the following situation:
I have mysql table with structure:
CREATE TABLE IF NOT EXISTS `battles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`active` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
`begindate` datetime NOT NULL,
`enddate` datetime NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
Every battle has begindate and enddate. Begindate is datetime of insert and usually enddate is three days later.
I would like to create a mysql event that stops the battle (sets active = 0) at the battle enddate. And i would like this event to be created on insert trigger in the battles table.
There is an related issue with very few answers (here).
They advise:
You should be able to do it using a trigger and the event scheduler:
create a trigger on the table that is fired on every update / insert
this trigger creates a scheduled event that occurs at the datetime of the row and updates >your second table
I've tried to create such a query but with no success.
DELIMITER |
DROP TRIGGER IF EXISTS battle_create_end|
CREATE TRIGGER battle_create_end AFTER INSERT ON battles
FOR EACH ROW BEGIN
CREATE EVENT IF NOT EXISTS CONCAT('battle_end_',NEW.id)
ON SCHEDULE AT NEW.enddate
DO
UPDATE battles SET battles.active = 0 WHERE battles.id = NEW.id;
END|
DELIMITER ;
The error i get is
1576 - Recursion of EVENT DDL statements is forbidden when body is present
I've tried with different delimiters in the for each row structure with no success either.
If someone can help, please advise.
BR,
Ilko
Sorry brother but from what I have been reading what you are proposing is not possible. I don't think you can create an event with a trigger. Which is a bummer because it would be useful for me as well.
It would however be easier to create the event when the row for each battle is created. Hear is an example of some code I found from a guy explaining how events work.
<?php
// establish database connection and filter incoming data
// ...
// insert blog post with pending status, get id assigned to post
$query = "INSERT INTO blog_posts (id, title, post_text, status)
VALUES (NULL, :title, :postText, 'pending')";
$stm = $db->prepare($query);
$stm->execute(array(":title" => $title, ":postText" => $text));
$id = $db->lastInsertId();
// is this a future post?
if (isset($_POST["schedule"], $_POST["time"])) {
$scheduleDate = strtotime($_POST["time"]);
$query = "CREATE EVENT publish_:id
ON SCHEDULE AT FROM_UNIXTIME(:scheduleDate)
DO
BEGIN
UPDATE blog_posts SET status = 'published' WHERE id = :id;
END";
$stm = $db->prepare($query);
$stm->execute(array(":id" => $id, ":scheduleDate" => $scheduleDate));
}
// this is not a future post, publish now
else {
$query = "UPDATE blog_posts SET status = 'published' WHERE id = :id";
$stm = $db->prepare($query);
$stm->execute(array(":id" => $id));
}
So basically create the event when you add a battle to the table.
I am trying to insert into my table, but only if the information doesn't exist already.
This works:
$sql = //"if not exists (select `id` from friends where `id` = :id) " . //ERROR!
"insert into `friends` (`id`, `fb_id`, `name`, `id2`, `fb_id2`, `name2`) " .
"values (:id, :fb_id, :name, :id2, :fb_id2, :name2)";
try
{
$stmt = $this->db->prepare($sql);
if (!$stmt)
{
$errorcode = (string)
$stmt->errorCode();
trigger_error("mysql errorcode : " . $errorcode, E_USER_ERROR);
$data = array( "note" => "mysql error code: " . $errorcode );
return json_encode( $data );
}
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->bindParam(':fb_id', $fb_id, PDO::PARAM_INT);
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
$stmt->bindParam(':id2', $id2, PDO::PARAM_INT);
$stmt->bindParam(':fb_id2', $fb_id2, PDO::PARAM_INT);
$stmt->bindParam(':name2', $name2, PDO::PARAM_STR);
$result = $stmt->execute();
$stmt->closeCursor();
}
catch (Exception $e)
{
die ($e->getMessage() );
}
I tried if not exists ( select id ... etc as commeted out in the first line, but that didn't work. It returned error code 00000 with (string) $stmt->errorCode();, I googled it and it means: to many mysql connections, this can't be the problem as other queries work fine.
How do I insert into the table when not exist and how do I get mysql error information?
I've never seen your syntax before, putting an exists clause before the insert clause, but the following should work.
INSERT INTO `friends`
SELECT :id, :fp_id, :name, :id2, :fb_id2, :name2
FROM `friends`
WHERE NOT EXISTS ( select `id` from friends where `id` = :id )
LIMIT 1;
Just realized that you'll need at least one record in your friends table before this'll go.
insert IGNORE into `friends` (`id`, `fb_id`, `name`, `id2`, `fb_id2`, `name2`)
values (:id, :fb_id, :name, :id2, :fb_id2, :name2)
Or you want to prevent duplicate id's you can add a trigger
DELIMITER $$
CREATE TRIGGER bi_friends_each BEFORE INSERT ON friends FOR EACH ROW
BEGIN
DECLARE TestId integer;
SELECT id INTO TestId FROM friends WHERE id = new.id LIMIT 1;
IF (id IS NOT NULL) THEN BEGIN
/*force an error to prevent insert*/
SELECT * FROM force_an_error_table_unwilling_to_insert_dup_key;
END; END IF;
END $$
DELIMITER ;
Note that if id is a UNIQUE or PRIMARY KEY field inserting a duplicate key will create an error and rollback any pending transaction.
If you are using a non-transactional engine, MySQL will stop inserting rows at the error point leaving only part of your rows inserted.
Your question is vague as to why you want to do the IGNORE test. So I'll recap the options and the implications:
If you want a transaction to fail, set id as primary key and just insert as normal, the resulting conflict will generate an error and rollback the transaction.
If you want to just insert stuff with no worries about duplicate id's set field is to AUTOINCREMENT and replace the value for id with null. INSERT INTO table (id, fb_id,name,id,fb_id2,name2) VALUES (null,:fb_id,:name,:id2,:fb_id2,:name2)
If you just want the one insert not to succeed, do the INSERT IGNORE ... as stated above.
If you do not have transactions (MyISAM et al), you may have to do a test SELECT first and only INSERT a bunch of values after the test shows it is save to proceed.
You could use INSERT IGNORE assuming you have a unique index on id. See this post for discussion about the pros/cons: "INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE"
This solution works even if you do not have any rows in your table.
INSERT INTO t (
x,
y,
z) (
SELECT
'00000',
'11111',
'22222'
FROM
DUAL
WHERE
NOT EXISTS (
SELECT
1
FROM
t
WHERE
c = '00000'
AND x = '11111'
AND y = '22222'
)
LIMIT 1
);