mysql muliple queries in one statement - php

I've looked around on stackoverflow for a similar question, but haven't found exactly what I was looking for, so here goes. In phpMyAdmin you can have multiple queries in one statement and it executes it for you, eg:'
UPDATE `test` WHERE `test2` = 4;
UPDATE `test` WHERE `test4` = 8;
UPDATE `test` WHERE `test8` = 1;
Now if I try to do something like that in PHP, it doesn't work at all. eg:
$test = 'UPDATE `test` SET `value` = "123" WHERE `test2` = 4;
UPDATE `test` SET `value` = "321" WHERE `test4` = 8;
UPDATE `test` SET `value` = "533" WHERE `test8` = 1;';
mysql_query($test);
Gives and error:
You have an error in your SQL syntax;
check the manual that corresponds to
your MySQL server version for the
right syntax to use near '; UPDATE
test SET value = "123" WHERE test2
= 4; UPDATE test SE' at line 1
Is it even possible to combine, say, multiple queries like above, in one statement? I want to do this in the following situation: (The logic behind this is probably very bad, but I don't have much MySQL experience, so please let me know if there's a better way to do it)
The following loops over a couple of times:
function SaveConfig($name, $value)
{
global $sql_save_query;
$sql = 'SELECT * FROM `config` WHERE `name` = "'.$name.'"';
$res = mysql_query($sql);
if($res)
{
$sql_save_query .= 'UPDATE `config` SET value = "'.$value.'" WHERE `name` = "' .$name. '"; '."\n";
}
else
{
$sql_save_query .= 'INSERT INTO `config`(`id`,`name`,`value`) VALUES("","' .$name. '","' .$value. '"); '."\n";
}
}
Then after the loop finishes it runs:
mysql_query($sql_save_query);
Which gives an error:
You have an error in your SQL syntax;
check the manual that corresponds to
your MySQL server version for the
right syntax to use near '; UPDATE
config SET value = "" WHERE name =
"fcolour2"; UPDATE config SE' at
line 1
Now my other option (in my mind) is to just execute an SQL query after each loop, one query at a time. But wouldn't that be bad/slow/bad practice?

the php API forbids you to issue multiple queries in a single call to reduce the chance of an SQL injection attack to your code (think of what would happen if I passed '; UPDATE users SET admin=1 WHERE username='hacker' to your login script as username). You need to either execute multiple statements, or wrap the logic of your statements into a single statement (which is not possible in your case).

It's not possible to execute multiple queries using mysql_query.
You can perform multiple inserts at once using this syntax:
INSERT INTO table (col1, col2) VALUES (0, 1), (2, 3), (4, 5); -- Insert 3 rows
In general less queries = better but for updates you just have to do them.

The loop you have in your example is indicative of an architectural problem.
If you are dealing with an existing record, pass the primary key - then you don't need the select at all - you can just run an update statement.
If you are dealing with a new record, pass no key - then you know to run an insert statement.

probably you can use INSERT ... ON DUPLICATE KEY UPDATE
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
Some other useful links
http://dev.mysql.com/doc/refman/5.0/en/replace.html
http://www.mysqlperformanceblog.com/2007/01/18/insert-on-duplicate-key-update-and-replace-into/

$sqls = explode(";",$test);
foreach ($sqls as $key=>$sql) {
if (strlen(trim($sql))>0) {
mysql_query(trim($sql));
}
}

Related

pdo update multiple rows in one query [duplicate]

I know that you can insert multiple rows at once, is there a way to update multiple rows at once (as in, in one query) in MySQL?
Edit:
For example I have the following
Name id Col1 Col2
Row1 1 6 1
Row2 2 2 3
Row3 3 9 5
Row4 4 16 8
I want to combine all the following Updates into one query
UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;
Yes, that's possible - you can use INSERT ... ON DUPLICATE KEY UPDATE.
Using your example:
INSERT INTO table (id,Col1,Col2) VALUES (1,1,1),(2,2,3),(3,9,3),(4,10,12)
ON DUPLICATE KEY UPDATE Col1=VALUES(Col1),Col2=VALUES(Col2);
Since you have dynamic values, you need to use an IF or CASE for the columns to be updated. It gets kinda ugly, but it should work.
Using your example, you could do it like:
UPDATE table SET Col1 = CASE id
WHEN 1 THEN 1
WHEN 2 THEN 2
WHEN 4 THEN 10
ELSE Col1
END,
Col2 = CASE id
WHEN 3 THEN 3
WHEN 4 THEN 12
ELSE Col2
END
WHERE id IN (1, 2, 3, 4);
The question is old, yet I'd like to extend the topic with another answer.
My point is, the easiest way to achieve it is just to wrap multiple queries with a transaction. The accepted answer INSERT ... ON DUPLICATE KEY UPDATE is a nice hack, but one should be aware of its drawbacks and limitations:
As being said, if you happen to launch the query with rows whose primary keys don't exist in the table, the query inserts new "half-baked" records. Probably it's not what you want
If you have a table with a not null field without default value and don't want to touch this field in the query, you'll get "Field 'fieldname' doesn't have a default value" MySQL warning even if you don't insert a single row at all. It will get you into trouble, if you decide to be strict and turn mysql warnings into runtime exceptions in your app.
I made some performance tests for three of suggested variants, including the INSERT ... ON DUPLICATE KEY UPDATE variant, a variant with "case / when / then" clause and a naive approach with transaction. You may get the python code and results here. The overall conclusion is that the variant with case statement turns out to be twice as fast as two other variants, but it's quite hard to write correct and injection-safe code for it, so I personally stick to the simplest approach: using transactions.
Edit: Findings of Dakusan prove that my performance estimations are not quite valid. Please see this answer for another, more elaborate research.
Not sure why another useful option is not yet mentioned:
UPDATE my_table m
JOIN (
SELECT 1 as id, 10 as _col1, 20 as _col2
UNION ALL
SELECT 2, 5, 10
UNION ALL
SELECT 3, 15, 30
) vals ON m.id = vals.id
SET col1 = _col1, col2 = _col2;
All of the following applies to InnoDB.
I feel knowing the speeds of the 3 different methods is important.
There are 3 methods:
INSERT: INSERT with ON DUPLICATE KEY UPDATE
TRANSACTION: Where you do an update for each record within a transaction
CASE: In which you a case/when for each different record within an UPDATE
I just tested this, and the INSERT method was 6.7x faster for me than the TRANSACTION method. I tried on a set of both 3,000 and 30,000 rows.
The TRANSACTION method still has to run each individually query, which takes time, though it batches the results in memory, or something, while executing. The TRANSACTION method is also pretty expensive in both replication and query logs.
Even worse, the CASE method was 41.1x slower than the INSERT method w/ 30,000 records (6.1x slower than TRANSACTION). And 75x slower in MyISAM. INSERT and CASE methods broke even at ~1,000 records. Even at 100 records, the CASE method is BARELY faster.
So in general, I feel the INSERT method is both best and easiest to use. The queries are smaller and easier to read and only take up 1 query of action. This applies to both InnoDB and MyISAM.
Bonus stuff:
The solution for the INSERT non-default-field problem is to temporarily turn off the relevant SQL modes: SET SESSION sql_mode=REPLACE(REPLACE(##SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES",""). Make sure to save the sql_mode first if you plan on reverting it.
As for other comments I've seen that say the auto_increment goes up using the INSERT method, this does seem to be the case in InnoDB, but not MyISAM.
Code to run the tests is as follows. It also outputs .SQL files to remove php interpreter overhead
<?php
//Variables
$NumRows=30000;
//These 2 functions need to be filled in
function InitSQL()
{
}
function RunSQLQuery($Q)
{
}
//Run the 3 tests
InitSQL();
for($i=0;$i<3;$i++)
RunTest($i, $NumRows);
function RunTest($TestNum, $NumRows)
{
$TheQueries=Array();
$DoQuery=function($Query) use (&$TheQueries)
{
RunSQLQuery($Query);
$TheQueries[]=$Query;
};
$TableName='Test';
$DoQuery('DROP TABLE IF EXISTS '.$TableName);
$DoQuery('CREATE TABLE '.$TableName.' (i1 int NOT NULL AUTO_INCREMENT, i2 int NOT NULL, primary key (i1)) ENGINE=InnoDB');
$DoQuery('INSERT INTO '.$TableName.' (i2) VALUES ('.implode('), (', range(2, $NumRows+1)).')');
if($TestNum==0)
{
$TestName='Transaction';
$Start=microtime(true);
$DoQuery('START TRANSACTION');
for($i=1;$i<=$NumRows;$i++)
$DoQuery('UPDATE '.$TableName.' SET i2='.(($i+5)*1000).' WHERE i1='.$i);
$DoQuery('COMMIT');
}
if($TestNum==1)
{
$TestName='Insert';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf("(%d,%d)", $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery('INSERT INTO '.$TableName.' VALUES '.implode(', ', $Query).' ON DUPLICATE KEY UPDATE i2=VALUES(i2)');
}
if($TestNum==2)
{
$TestName='Case';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf('WHEN %d THEN %d', $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery("UPDATE $TableName SET i2=CASE i1\n".implode("\n", $Query)."\nEND\nWHERE i1 IN (".implode(',', range(1, $NumRows)).')');
}
print "$TestName: ".(microtime(true)-$Start)."<br>\n";
file_put_contents("./$TestName.sql", implode(";\n", $TheQueries).';');
}
UPDATE table1, table2 SET table1.col1='value', table2.col1='value' WHERE table1.col3='567' AND table2.col6='567'
This should work for ya.
There is a reference in the MySQL manual for multiple tables.
Use a temporary table
// Reorder items
function update_items_tempdb(&$items)
{
shuffle($items);
$table_name = uniqid('tmp_test_');
$sql = "CREATE TEMPORARY TABLE `$table_name` ("
." `id` int(10) unsigned NOT NULL AUTO_INCREMENT"
.", `position` int(10) unsigned NOT NULL"
.", PRIMARY KEY (`id`)"
.") ENGINE = MEMORY";
query($sql);
$i = 0;
$sql = '';
foreach ($items as &$item)
{
$item->position = $i++;
$sql .= ($sql ? ', ' : '')."({$item->id}, {$item->position})";
}
if ($sql)
{
query("INSERT INTO `$table_name` (id, position) VALUES $sql");
$sql = "UPDATE `test`, `$table_name` SET `test`.position = `$table_name`.position"
." WHERE `$table_name`.id = `test`.id";
query($sql);
}
query("DROP TABLE `$table_name`");
}
Why does no one mention multiple statements in one query?
In php, you use multi_query method of mysqli instance.
From the php manual
MySQL optionally allows having multiple statements in one statement string. Sending multiple statements at once reduces client-server round trips but requires special handling.
Here is the result comparing to other 3 methods in update 30,000 raw. Code can be found here which is based on answer from #Dakusan
Transaction: 5.5194580554962
Insert: 0.20669293403625
Case: 16.474853992462
Multi: 0.0412278175354
As you can see, multiple statements query is more efficient than the highest answer.
If you get error message like this:
PHP Warning: Error while sending SET_OPTION packet
You may need to increase the max_allowed_packet in mysql config file which in my machine is /etc/mysql/my.cnf and then restart mysqld.
There is a setting you can alter called 'multi statement' that disables MySQL's 'safety mechanism' implemented to prevent (more than one) injection command. Typical to MySQL's 'brilliant' implementation, it also prevents user from doing efficient queries.
Here (http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html) is some info on the C implementation of the setting.
If you're using PHP, you can use mysqli to do multi statements (I think php has shipped with mysqli for a while now)
$con = new mysqli('localhost','user1','password','my_database');
$query = "Update MyTable SET col1='some value' WHERE id=1 LIMIT 1;";
$query .= "UPDATE MyTable SET col1='other value' WHERE id=2 LIMIT 1;";
//etc
$con->multi_query($query);
$con->close();
Hope that helps.
You can alias the same table to give you the id's you want to insert by (if you are doing a row-by-row update:
UPDATE table1 tab1, table1 tab2 -- alias references the same table
SET
col1 = 1
,col2 = 2
. . .
WHERE
tab1.id = tab2.id;
Additionally, It should seem obvious that you can also update from other tables as well. In this case, the update doubles as a "SELECT" statement, giving you the data from the table you are specifying. You are explicitly stating in your query the update values so, the second table is unaffected.
You may also be interested in using joins on updates, which is possible as well.
Update someTable Set someValue = 4 From someTable s Inner Join anotherTable a on s.id = a.id Where a.id = 4
-- Only updates someValue in someTable who has a foreign key on anotherTable with a value of 4.
Edit: If the values you are updating aren't coming from somewhere else in the database, you'll need to issue multiple update queries.
No-one has yet mentioned what for me would be a much easier way to do this - Use a SQL editor that allows you to execute multiple individual queries. This screenshot is from Sequel Ace, I'd assume that Sequel Pro and probably other editors have similar functionality. (This of course assumes you only need to run this as a one-off thing rather than as an integrated part of your app/site).
And now the easy way
update my_table m, -- let create a temp table with populated values
(select 1 as id, 20 as value union -- this part will be generated
select 2 as id, 30 as value union -- using a backend code
-- for loop
select N as id, X as value
) t
set m.value = t.value where t.id=m.id -- now update by join - quick
Yes ..it is possible using INSERT ON DUPLICATE KEY UPDATE sql statement..
syntax:
INSERT INTO table_name (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE a=VALUES(a),b=VALUES(b),c=VALUES(c)
use
REPLACE INTO`table` VALUES (`id`,`col1`,`col2`) VALUES
(1,6,1),(2,2,3),(3,9,5),(4,16,8);
Please note:
id has to be a primary unique key
if you use foreign keys to
reference the table, REPLACE deletes then inserts, so this might
cause an error
I took the answer from #newtover and extended it using the new json_table function in MySql 8. This allows you to create a stored procedure to handle the workload rather than building your own SQL text in code:
drop table if exists `test`;
create table `test` (
`Id` int,
`Number` int,
PRIMARY KEY (`Id`)
);
insert into test (Id, Number) values (1, 1), (2, 2);
DROP procedure IF EXISTS `Test`;
DELIMITER $$
CREATE PROCEDURE `Test`(
p_json json
)
BEGIN
update test s
join json_table(p_json, '$[*]' columns(`id` int path '$.id', `number` int path '$.number')) v
on s.Id=v.id set s.Number=v.number;
END$$
DELIMITER ;
call `Test`('[{"id": 1, "number": 10}, {"id": 2, "number": 20}]');
select * from test;
drop table if exists `test`;
It's a few ms slower than pure SQL but I'm happy to take the hit rather than generate the sql text in code. Not sure how performant it is with huge recordsets (the JSON object has a max size of 1Gb) but I use it all the time when updating 10k rows at a time.
The following will update all rows in one table
Update Table Set
Column1 = 'New Value'
The next one will update all rows where the value of Column2 is more than 5
Update Table Set
Column1 = 'New Value'
Where
Column2 > 5
There is all Unkwntech's example of updating more than one table
UPDATE table1, table2 SET
table1.col1 = 'value',
table2.col1 = 'value'
WHERE
table1.col3 = '567'
AND table2.col6='567'
UPDATE tableName SET col1='000' WHERE id='3' OR id='5'
This should achieve what you'r looking for. Just add more id's. I have tested it.
UPDATE `your_table` SET
`something` = IF(`id`="1","new_value1",`something`), `smth2` = IF(`id`="1", "nv1",`smth2`),
`something` = IF(`id`="2","new_value2",`something`), `smth2` = IF(`id`="2", "nv2",`smth2`),
`something` = IF(`id`="4","new_value3",`something`), `smth2` = IF(`id`="4", "nv3",`smth2`),
`something` = IF(`id`="6","new_value4",`something`), `smth2` = IF(`id`="6", "nv4",`smth2`),
`something` = IF(`id`="3","new_value5",`something`), `smth2` = IF(`id`="3", "nv5",`smth2`),
`something` = IF(`id`="5","new_value6",`something`), `smth2` = IF(`id`="5", "nv6",`smth2`)
// You just building it in php like
$q = 'UPDATE `your_table` SET ';
foreach($data as $dat){
$q .= '
`something` = IF(`id`="'.$dat->id.'","'.$dat->value.'",`something`),
`smth2` = IF(`id`="'.$dat->id.'", "'.$dat->value2.'",`smth2`),';
}
$q = substr($q,0,-1);
So you can update hole table with one query

Mysqli num_rows check to slow?

i have an c++ program that sending POST of logs to my server and store it on database, the problem is that the checking of duplicates before insert a new row is not working, i think that the program send the POST very fast and there is no delay between the POSTS to the server so the Mysqli can't handle this, is there any solution from server client? maybe locking rows or something?
$date = date('Y-m-d', time());
$prep_select_qa = 'SELECT * from `logs` WHERE `guid` = ? AND `error_code` = ? AND `date_create` = ?';
$select_qa = $db->prepare($prep_select_qa);
$select_qa->bind_param('sss', $_POST['guid'], $_POST['error_code'], $date);
$select_qa->execute();
$select_qa->store_result();
$num_rows = $select_qa->num_rows;
if($num_rows == 0)
{
$prep_insert_qa = 'INSERT INTO `logs` (`type`, `guid`, `sent_by`, `class_and_method`, `api_method`, `error_code`, `error_text`, `date_create`) VALUES (?,?,?,?,?,?,?,?)';
$insert_qa = $db->prepare($prep_insert_qa);
$insert_qa->bind_param('ssssssss', $new, $_POST['guid'], $_POST['sentBy'], $_POST['classAndMethodName'], $_POST['APImethod'], $_POST['ErrorCode'], $_POST['ErrorText'], $date);
$insert_qa->execute();
$insert_qa->store_result();
}
First, the answer to your question is that you are retrieving all the rows in order to count them. Presumably, this requires reading all the data in the table and returning some of it (unless you have indexes). A faster method is to check the value returned by this query:
SELECT count(*)
FROM `logs`
WHERE `guid` = ? AND `error_code` = ? AND `date_create` = ?';
And an even faster method is not to count but to determine if any row exists:
SELECT EXISTS (SELECT 1
FROM `logs`
WHERE `guid` = ? AND `error_code` = ? AND `date_create` = ?'
)
This will return 1 if the row exists and 0 otherwise. Both of the above queries and your original query will benefit from having an index on guid, error_code, date_create.
In practice, you should follow Marvin's advice and use a unique index. This means the database does the checking via a unique index rather than the application. One very important reason is a race condition. If two users are inserting the same row at the same time, both might execute the if statement, find there are no matching rows in the table, and then insert duplicate rows.
The SELECT scheme must be enclosed in a BEGIN...COMMIT transaction and have FOR UPDATE on it. Otherwise, some other connection can slip in and defeat your check.
Instead, try to do it in a single, atomic, instruction:
Once you have an INDEX that will prevent duplicates...
INSERT IGNORE -- Silently does nothing if it is a dup.
INSERT...ON DUPLICATE KEY UPDATE -- Lets you change something as you try to insert a dup.
Also, the INSERT solutions will be faster (which was your original question).

Syntax error with IF EXISTS UPDATE ELSE INSERT

I'm using MySQL 5.1 hosted at my ISP. This is my query
mysql_query("
IF EXISTS(SELECT * FROM licensing_active WHERE title_1='$title_1') THEN
BEGIN
UPDATE licensing_active SET time='$time' WHERE title_1='$title_1')
END ELSE BEGIN
INSERT INTO licensing_active(title_1) VALUES('$title_1')
END
") or die(mysql_error());
The error is
... check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF EXISTS(SELECT * FROM licensing_active WHERE title_1='Title1') THEN ' at line 1
My actual task involves
WHERE title_1='$title_1' AND title_2='$title_2' AND version='$version' ...ETC...
but I have reduced it down to make things simpler for my problem solving
In my searches on this, I keep seeing references to 'ON DUPLICATE KEY UPDATE', but don't know what to do with that.
Here is a simple and easy solution, try it.
$result = mysql_query("SELECT * FROM licensing_active WHERE title_1 ='$title_1' ");
if( mysql_num_rows($result) > 0) {
mysql_query("UPDATE licensing_active SET time = '$time' WHERE title_1 = '$title_1' ");
}
else
{
mysql_query("INSERT INTO licensing_active (title_1) VALUES ('$title_1') ");
}
Note: Though this question is from 2012, keep in mind that mysql_* functions are no longer available since PHP 7.
This should do the trick for you:
insert into
licensing_active (title_1, time)
VALUES('$title_1', '$time')
on duplicate key
update set time='$time'
This is assuming that title_1 is a unique column (enforced by the database) in your table.
The way that insert... on duplicate works is it tries to insert a new row first, but if the insert is rejected because a key stops it, it will allow you to update certain fields instead.
The syntax of your query is wrong. Checkout http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html
Use the on duplicate key syntax to achieve the result you want. See http://dev.mysql.com/doc/refman/5.0/en/insert-select.html
Another solution
$insertQuery = "INSERT INTO licensing_active (title_1) VALUES ('$title_1')";
if(!$link->query($insertQuery)){ // Insert fails, so update
$updateQuery = "UPDATE licensing_active SET time='$time' WHERE title_1='$title_1'";
$link->query($updateQuery);
}
Here is the example I tried and its works fine:
INSERT INTO user(id, name, address) VALUES(2, "Fadl", "essttt") ON DUPLICATE KEY UPDATE name = "kahn ajab", address = "Address is test"
I am amazed to see so many useless codes and answers...
Just replace INSERT with REPLACE.
¯\(ツ)/¯

How to return inserted row from INSERT statement with php, SQL SERVER 2005?

What is the easiest / most efficient way to get the entire row inserted after an INSERT statement?
I am pretty sure I could do this as follows:
$aQuery = "INSERT into myTable (a, b, c) VALUES (1, 'Hello', 'Goodbye')";
//the IDENTITY coloumn in myTable is named id
$result = sqlsrv_query($myConn, $aQuery );
if ($result) {
$res = sqlsrv_query('SELECT LAST_INSERT_ID()');
$row = sqlsrv_fetch_array($res);
$lastInsertId = $row[0];
$subQuery = "SELECT * FROM myTable where id = {$lastInsertId}";
$subResult = sqlsrv_query($myConn, $subQuery);
if ($subResult) {
while($subrow = sqlsrv_fetch_array($subResult)) {
echo($subrow ['id'] . ', '.
$subrow ['a'] . ', '.
$subrow ['b']); //etc...
}
}
}
However, I am concerned about the possibility of another insert occurring just before my SELECT LAST_INSERT_ID() and thus messing up my logic to boot. How can I be certain that the last inserted id is truly the INSERT I called previously, and not something happening somewhere else?
Is there a more appropriate way of doing this, perhaps a complete SQL solution (such that the query returns the row automatically rather than using PHP)?
UPDATE: myTable DOES have an explicitly defined (and auto-incremented) identity column, named id.
This will work:
"INSERT into myTable (a, b, c) OUTPUT Inserted.a, Inserted.b, Inserted.c VALUES (1, 'Hello', 'Goodbye')
In Sql Server, you would use select #lastID=SCOPE_IDENTITY()
And #LastID will have the last id inserted for the current scope; therefore, if there was another insertion in the middle, you would still get the correct record on your select.
Never use ##Identity for this or you may end up in a situation like you described.
If you were to use identity field (which maybe you should) there is a command called SCOPE_IDENTIY() which info you can find here:
http://msdn.microsoft.com/en-us/library/ms190315.aspx
Since you do not use it, you do not have to select latest data since you have it when you insert, so just use same data instead of selecting.

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