MySQL MyISAM race condition - php

The function has next structure:
$q = 'LOCK TABLES table1 WRITE;';
mysql_query($q);
$q = 'select id from table1 where is_delete = 0 limit 1;';
$res = mysql_fetch_assoc(mysql_query($q));
if($res) {
$q = 'UPDATE table1 SET is_delete = 1 WHERE id = '".$res['id']."'';
mysql_query($q);
}
$q = 'UNLOCK TABLES;';
mysql_query($q);
I locking all tables, but queries run parallel.
How fix this?

Check whether you're getting any MySQL errors on the LOCK TABLES query:
$q = 'LOCK TABLES table1 WRITE';
$r = mysql_query($q) or die(mysql_error());
However, if this is all you are doing, you can also simply write:
UPDATE `table1 SET `is_delete` = 1 WHERE `is_delete` = 0 LIMIT 1
which does not require any locks at all. Of course, this will only work if the data from your first query is not being processed in any way, and if it doesn't really matter which row you are updating, as long as it's one in which is_delete is set to 0. This is what the code you posted does, too, but it's not immediately obvious to me what you would want to use this code for :)
More generally, if you are using the default InnoDB storage engine for your MySQL table, you may want to look into SELECT ... FOR UPDATE:
http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
You could write:
$q = 'select id from table1 where is_delete = 0 limit 1 for update';
$res = mysql_fetch_assoc(mysql_query($q));
if($res) {
$q = 'UPDATE table1 SET is_delete = 1 WHERE id = '".$res['id']."'';
mysql_query($q);
}
See also: http://www.mysqlperformanceblog.com/2006/08/06/select-lock-in-share-mode-and-for-update/

Related

Feedback for php code

hello guys I am subtracting one unit from a variable called Eppl which resides in a Database and this is working perfectly. However I have added a condition which is that the value of the variable Eppl must be greater than 0 before the subtraction takes place. My code is as follows:
$id = $_GET["id"];
$result = $mysqli->query("SELECT `CreatedBy` AND `Eppl` FROM `events` WHERE `Eid` = '$id'");
$row = $result->fetch_assoc();
$sessionid = $row['CreatedBy'];
$notlesszero = $row['Eppl'];
$zero = 0;
//echo $result;
session_start();
if ((!($_SESSION['login_user'] == $sessionid)) && ($notlesszero>0)){
$mysqli->query("UPDATE `events` SET `Eppl` = `Eppl` - 1 WHERE `Eid` = '$id'");
$mysqli->query("INSERT INTO `eventusers` (EventID, UserID) VALUES ('{$id}', '{$_SESSION['login_user']}')");
header("location:view.php");
//}
}
The if branch works without the second condition $notlesszero>0...
What is the problem here?
Thanks for your help
Instead of querying the database to get the value of the field and then checking it, why not just add a condition on the UPDATE?
$mysqli->query("UPDATE `events` SET `Eppl` = `Eppl` - 1 WHERE `Eid` = '$id'");
to
$mysqli->query("UPDATE `events` SET `Eppl` = `Eppl` - 1 WHERE `Eid` = '$id' AND `Eppl` > 0");
The first query is wrong after you added Eppl to it. Fields to select should not be separated by AND. So
SELECT `CreatedBy` AND `Eppl` FROM
should be
SELECT `CreatedBy`, `Eppl` FROM
This is something you could have caught by inspecting the error information after executing the query, or at least by inspecting $row after changing the query. :-p

Make an array from a select with multiple rows

I'm trying my best here to find a solution for my issue, but with no luck.
I have a SELECT in my PHP to retrieve some products information like their IDs.
mysql_query("SELECT id_item FROM mytable WHERE status = '0' AND cond1 = '1' AND cond2 = '1'");
Every time I run this SELECT, I get 5 rows as result. After that I need to run a DELETE to kill those 5 rows using their id_item in my WHERE condition. When I run, manually, something like:
DELETE FROM mytable WHERE id_item IN (1,2,3,4,5);
It works! But my issue is that I don't know how to make an array in PHP to return (1,2,3,4,5) as this kind of array from my SELECT up there, because those 2 other conditions may vary and I have more "status = 0" in my db that can't be killed together. How am I suppose to do so? Please, I appreciate any help.
Unless there is more going on than what is shown, you should never have to select just to determine what to delete. Just form the DELETE query WHERE condition as you would in the SELECT:
DELETE FROM mytable WHERE status = '0' AND cond1 = '1' AND cond2 = '1'
But to answer how to get the IDs:
$result = mysqli_query($link, "SELECT id_item FROM mytable WHERE status = '0' AND cond1 = '1' AND cond2 = '1'");
while($row = mysqli_fetch_assoc($result)) {
$ids[] = $row['id_item'];
}
$ids = implode(',', $ids);
Move to PDO or MySQLi now.
First of all you shouldn't be using mysql_query anymore as the function is deprecated - see php.net
If this is a legacy application and you MUST use mysql_query you'll need to loop through the resource that's returned by mysql_query, which should look something like this
$result = mysql_query("SELECT id_item FROM mytable WHERE status = '0' AND cond1 = '1' AND cond2 = '1'");
$idArray = array();
while ($row = mysql_fetch_assoc($result)) {
$idArray[] = $row['id_item'];
}
if(count($idArray) > 0) {
mysql_query("DELETE FROM mytable WHERE id_item IN (" . implode(',' $idArray) . ")");
}
As said before, probably you don't even need a select. But you can do a select, grouping all ids together, and then put it in the delete IN.
$result = mysql_query("SELECT GROUP_CONCAT(DISTINCT id_item) AS ids FROM mytable WHERE status = '0' AND cond1 = '1' AND cond2 = '1'");
$ids = mysql_result( $result , 0, 'ids') ; // 1,2,3,4,5
if ($ids != ""){
mysql_query("DELETE FROM mytable WHERE id_item IN (" . $ids . ")");
}
GROUP_CONCAT

Updating the row with the biggest value

In the "user_id" column of my table, I'd like to insert the ID of the user who just registred from my page. The idea is to associate his recent generated income with the users id, just to spot an eventual double registration of the income.
In order to do this, I tought to update the user_id column, on the row where income_id has the biggest value, i.e. the last generated income, but something isn't working. My code is:
$query = "SELECT max( id_income ) FROM `affiliate_income`";
$last_income = mysql_query($query, $conn) or die(mysql_error());
$last = mysql_fetch_assoc($last_income);
$updtsql = "UPDATE affiliate_income SET `id_user`=".$row_user_code['id_user']."WHERE id_income =".$last;
$result = mysql_query($updtsql, $conn) or die(mysql_error());
any ideas?
Actually you can do it in one query,
UPDATE affiliate_income a
INNER JOIN (SELECT MAX(id_income) id_income FROM affiliate_income) b
ON a.id_income = b.id_income
SET a.id_user = 'valueHere'
You get the value of $last as array.So you have to giv the query like the following
$updtsql = "UPDATE affiliate_income SET `id_user`=".$row_user_code['id_user']."WHERE id_income =".$last['id_income'];
You try to get the max id_income but in the second query (updtsql) you try to find the id_income = array. Besides, you do not put a white space before WHERE clause.
$query = "SELECT max( id_income ) AS ii FROM `affiliate_income`";
$last_income = mysql_query($query, $conn) or die(mysql_error());
$last = mysql_fetch_assoc($last_income);
$updtsql = "UPDATE affiliate_income SET `id_user`=".$row_user_code['id_user']." WHERE id_income =".$last['ii'];
$result = mysql_query($updtsql, $conn) or die(mysql_error());

Pass column value from Select query to another query for insertion in PHP

I was thinking of accomplishing the following as a PHP multi_query. But I'm trying to figure out how to pass the column value from the select query to the insert and update queries.
$query = "SELECT tbl_links.link, link_id
FROM tbl_links
INNER JOIN tbl_items ON tbl_links.item_id = tbl_items.item_id
WHERE tbl_items.item_name like '".$items_name[$counter]."'
AND NOT EXISTS (
select link_id
from tbl_clickedlinks
where tbl_clickedlinks.link_id = tbl_links.link_id
AND tbl_clickedlinks.cust_id = '$items_custID[$counter]'
)
limit 0, 1;" ;
$query .= "INSERT INTO tbl_claimedlinks (cust_id, link_id, claim_time) VALUES ('$items_custID', $row['link_id'], NOW()) ;";
$query .= "UPDATE tbl_links SET click_count = click_count+1 where link_id = '$linkID' ;";*/
Problem is, I'm not sure how to pass the link_id value to the other queries. So I'm thinking I might have to rearrange the queries into one, but again, I'm just not sure how to pull that off.
Anyone got any suggestions?
You need to execute select query 1st then use its output to execute 2nd & 3rd query.
$query = "SELECT tbl_links.link, link_id
FROM tbl_links
INNER JOIN tbl_items ON tbl_links.item_id = tbl_items.item_id
WHERE tbl_items.item_name like '".$items_name[$counter]."'
AND NOT EXISTS (
select link_id
from tbl_clickedlinks
where tbl_clickedlinks.link_id = tbl_links.link_id
AND tbl_clickedlinks.cust_id = '$items_custID[$counter]'
)
limit 0, 1;" ;
$result = mysql_query($query);
while($row = mysql_fetch_array($result)) {
$query2 = "INSERT INTO tbl_claimedlinks (cust_id, link_id, claim_time) VALUES ('$items_custID', $row['link_id'], NOW()) ;";
$query3 = "UPDATE tbl_links SET click_count = click_count+1 where link_id = '$linkID' ;";*/
mysql_query($query2);
mysql_query($query3);
}

MySQL Update Query - By Row Number

I'd like to update a row in a MySQL table when a specific row number is reached
This is a little confusing since , the real row number of the record isn't a column in the table.
And there's no question of iterating over rows , since we're not iterating over an array as in mysql_fetch_array()
So , if I'd like to update - say the 3rd row of the table , what would the query be like?
I'm a noob at MySQL
Thanks a ton for your help ! :D
$link = mysqli_connect("localhost", "my_user", "my_password", "my_db");
$query = "SELECT MyColoumn FROM Mytable";
$result = mysqli_query($link, $query);
$row_needed = 3; //Your needed row e.g: 3rd row
for ($i=1,$i=$row_needed,$i++) {
$row = mysqli_fetch_array($result);
}
// now we are in 3rd row
$query = "UPDATE MyColumn FROM MyTable SET MyColumn = '".$MyColumnUpdate."' WHERE MyColumn = '".$row['MyColumn']."' ";
$result = mysqli_query($link, $query);
...
Try this query
UPDATE
tbl a,
(Select
#rn:=#rn+1 as rowId,
tbl.*
from
tbl
join
(select #rn:=0) tmp) b
SET
a.columnName = <VALUE>
WHERE
b.rowId = <rowNumber> AND
a.id = b.id;
NOTE The id column must be a unique one, you can use the primary key of that table...
SQLFIDDLE

Categories