Adjusting values in MySQL based on current value - php

My database is for keeping track of user's balances, and there are certain actions that will add or remove balance from the users. Currently I am doing this to get the balance and update it
$conn->prepare("SELECT * FROM users WHERE userid=:uid")
$conn->bindValue(':uid', $data['id']
$conn-execute()
$currentBal = $conn->fetch()
$newBal = $currentBal['balance'] + 100
$conn->prepare("UPDATE users SET balance=:bal WHERE userid=:uid")
$conn->bindValue(':bal', $newBal)
$conn->bindValue(':uid', $data['id']
Is there a way to directly do math within the query to add or remove? It is an integer.

Just do arithmetic:
UPDATE users
SET balance = balance + :inc
WHERE userid = :uid;
You can hardcode the 100, but I think it is better to pass it in as a parameter.

Related

How to update many rows with uniqid() making them unique in php

I created a new column in mysql, that is going to store a unique value for all of the elements inside the database.
Now I would like to populate all rows with this unique value using uniqid().
But since the function makes use of microtime(), I can't update all rows together.
How could I do it?
$unique_id = uniqid();
$sql = "UPDATE posts SET unique_id = :unique_id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['unique_id' => $unique_id]);
This code updates the same value for all rows.
How can every row be unique?
try with below code
SET #r := 0;
UPDATE posts
SET unique_id = (#r := #r + 1)
ORDER BY RAND();
Try this ,
update posts set unique_id = #i:=#i+1 order by rand();
The numbers will now randomly assigned to rows, but each row has a unique value.
uniqid('', TRUE),
You can use uniqid with the entropy to make it more sensitive in time to narrow down even more the chance of duplicates but keep one thing in mind:
This function does not guarantee uniqueness of return value. Since
most systems adjust system clock by NTP or like, system time is
changed constantly. Therefore, it is possible that this function does
not return unique ID for the process/thread. Use more_entropy to
increase likelihood of uniqueness.
What you can do as well is to put a random prefix like:
uniqid(mt_rand(), TRUE);
That will eliminate every chance to generate a duplicate.
You are going to use a random prefix + entropy sensitivity. The generated value will be unique even if your script runs that fast that the timestamp happens to be the same even in miliseconds.
The problem with your code is that you use uniqid() function one time by assigning it to a variable and from there you get duplicates of course cause you use this variable:
Try this code:
$sql = "UPDATE posts SET unique_id = uuid()";
$stmt = $pdo->prepare($sql);
$stmt->execute();
So after some tries I came across my own solution, using uniqid().
Here's my code, commented:
// Selecting all the posts
$sql = "SELECT id, pro_key FROM posts";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$posts = $stmt->fetchAll();
// Looping through all the results and updating them one by one with a delay of 1 second between the updates
foreach($posts as $post) {
$sql = "UPDATE posts SET unique_id = :unique_id WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $post->id, 'unique_id' => uniqid()]);
// delay
sleep(1);
}
Hope this helps.

update all rows in table with different data php mysql

I have an application where investment profit should be calculated on daily basis, which I intend to do using a cron job.
Presently, based on the rate a user has and the amount he possess, I have written a statement to calculate the profit as
$rate = $row_cron['rate'];
$amount = $row_cron['amount'];
$usernamex = $row_cron['Username'];
$check = $rate * $amount / 100;
$sql = "UPDATE users
SET invest = invest + $check
WHERE status = 'member'";
to fetch my records I have also created a recordset of data using
mysql_select_db($database_emirate, $emirate);
$query_cron = "SELECT * FROM users";
$cron = mysql_query($query_cron, $emirate) or die(mysql_error());
$row_cron = mysql_fetch_assoc($cron);
$totalRows_cron = mysql_num_rows($cron);
I have used this query to get all users in my table
Now the above code snippets only returns the first record in my table to be updated.
What I am trying to achieve is to return all records in my table so as to calculate and update their records at the same time, based on their various column data below
$rate = $row_cron['rate'];
$amount = $row_cron['amount'];
please help
Simply use pure SQL as you are updating the same table with calculated column. No loops are needed. Just run one query in PHP.
UPDATE `users`
SET invest = invest + (rate * amount / 100)
WHERE status = 'member'
Do note: SQL allows arithmetic calculations and some RDBMS's like MySQL even maintains mathematical and statistical functions.

How to handle/optimize thousands of different to executed SELECT queries?

I need to synchronize specific information between two databases (one mysql, the other a remote hosted SQL Server database) for thousands of rows. When I execute this php file it gets stuck/timeouts after several minutes I guess, so I wonder how I can fix this issue and maybe also optimize the way of "synchronizing" it.
What the code needs to do:
Basically I want to get for every row (= one account) in my database which gets updated - two specific pieces of information (= 2 SELECT queries) from another SQL Server database. Therefore I use a foreach loop which creates 2 SQL queries for each row and afterwards I update those information into 2 columns of this row. We talk about ~10k Rows which needs to run thru this foreach loop.
My idea which may help?
I have heard about things like PDO Transactions which should collect all those queries and sending them afterwards in a package of all SELECT queries, but I have no idea whether I use them correctly or whether they even help in such cases.
This is my current code, which is timing out after few minutes:
// DBH => MSSQL DB | DB => MySQL DB
$dbh->beginTransaction();
// Get all referral IDs which needs to be updated:
$listAccounts = "SELECT * FROM Gifting WHERE refsCompleted <= 100 ORDER BY idGifting ASC";
$ps_listAccounts = $db->prepare($listAccounts);
$ps_listAccounts->execute();
foreach($ps_listAccounts as $row) {
$refid=$row['refId'];
// Refsinserted
$refsInserted = "SELECT count(username) as done FROM accounts WHERE referral='$refid'";
$ps_refsInserted = $dbh->prepare($refsInserted);
$ps_refsInserted->execute();
$row = $ps_refsInserted->fetch();
$refsInserted = $row['done'];
// Refscompleted
$refsCompleted = "SELECT count(username) as done FROM accounts WHERE referral='$refid' AND finished=1";
$ps_refsCompleted = $dbh->prepare($refsCompleted);
$ps_refsCompleted->execute();
$row2 = $ps_refsCompleted->fetch();
$refsCompleted = $row2['done'];
// Update fields for local order db
$updateGifting = "UPDATE Gifting SET refsInserted = :refsInserted, refsCompleted = :refsCompleted WHERE refId = :refId";
$ps_updateGifting = $db->prepare($updateGifting);
$ps_updateGifting->bindParam(':refsInserted', $refsInserted);
$ps_updateGifting->bindParam(':refsCompleted', $refsCompleted);
$ps_updateGifting->bindParam(':refId', $refid);
$ps_updateGifting->execute();
echo "$refid: $refsInserted Refs inserted / $refsCompleted Refs completed<br>";
}
$dbh->commit();
You can do all of that in one query with a correlated sub-query:
UPDATE Gifting
SET
refsInserted=(SELECT COUNT(USERNAME)
FROM accounts
WHERE referral=Gifting.refId),
refsCompleted=(SELECT COUNT(USERNAME)
FROM accounts
WHERE referral=Gifting.refId
AND finished=1)
A correlated sub-query is essentially using a sub-query (query within a query) that references the parent query. So notice that in each of the sub-queries I am referencing the Gifting.refId column in the where clause of each sub-query. While this isn't the best for performance because each of those sub-queries still has to run independent of the other queries, it would perform much better (and likely as good as you are going to get) than what you have there.
Edit:
And just for reference. I don't know if a transaction will help here at all. Typically they are used when you have several queries that depend on each other and to give you a way to rollback if one fails. For example, banking transactions. You don't want the balance to deduct some amount until a purchase has been inserted. And if the purchase fails inserting for some reason, you want to rollback the change to the balance. So when inserting a purchase, you start a transaction, run the update balance query and the insert purchase query and only if both go in correctly and have been validated do you commit to save.
Edit2:
If I were doing this, without doing an export/import this is what I would do. This makes a few assumptions though. First is that you are using a mssql 2008 or newer and second is that the referral id is always a number. I'm also using a temp table that I insert numbers into because you can insert multiple rows easily with a single query and then run a single update query to update the gifting table. This temp table follows the structure CREATE TABLE tempTable (refId int, done int, total int).
//get list of referral accounts
//if you are using one column, only query for one column
$listAccounts = "SELECT DISTINCT refId FROM Gifting WHERE refsCompleted <= 100 ORDER BY idGifting ASC";
$ps_listAccounts = $db->prepare($listAccounts);
$ps_listAccounts->execute();
//loop over and get list of refIds from above.
$refIds = array();
foreach($ps_listAccounts as $row){
$refIds[] = $row['refId'];
}
if(count($refIds) > 0){
//implode into string for use in query below
$refIds = implode(',',$refIds);
//select out total count
$totalCount = "SELECT referral, COUNT(username) AS cnt FROM accounts WHERE referral IN ($refIds) GROUP BY referral";
$ps_totalCounts = $dbh->prepare($totalCount);
$ps_totalCounts->execute();
//add to array of counts
$counts = array();
//loop over total counts
foreach($ps_totalCounts as $row){
//if referral id not found, add it
if(!isset($counts[$row['referral']])){
$counts[$row['referral']] = array('total'=>0,'done'=>0);
}
//add to count
$counts[$row['referral']]['total'] += $row['cnt'];
}
$doneCount = "SELECT referral, COUNT(username) AS cnt FROM accounts WHERE finished=1 AND referral IN ($refIds) GROUP BY referral";
$ps_doneCounts = $dbh->prepare($doneCount);
$ps_doneCounts->execute();
//loop over total counts
foreach($ps_totalCounts as $row){
//if referral id not found, add it
if(!isset($counts[$row['referral']])){
$counts[$row['referral']] = array('total'=>0,'done'=>0);
}
//add to count
$counts[$row['referral']]['done'] += $row['cnt'];
}
//now loop over counts and generate insert queries to a temp table.
//I suggest using a temp table because you can insert multiple rows
//in one query and then the update is one query.
$sqlInsertList = array();
foreach($count as $refId=>$count){
$sqlInsertList[] = "({$refId}, {$count['done']}, {$count['total']})";
}
//clear out the temp table first so we are only inserting new rows
$truncSql = "TRUNCATE TABLE tempTable";
$ps_trunc = $db->prepare($truncSql);
$ps_trunc->execute();
//make insert sql with multiple insert rows
$insertSql = "INSERT INTO tempTable (refId, done, total) VALUES ".implode(',',$sqlInsertList);
//prepare sql for insert into mssql
$ps_insert = $db->prepare($insertSql);
$ps_insert->execute();
//sql to update existing rows
$updateSql = "UPDATE Gifting
SET refsInserted=(SELECT total FROM tempTable WHERE refId=Gifting.refId),
refsCompleted=(SELECT done FROM tempTable WHERE refId=Gifting.refId)
WHERE refId IN (SELECT refId FROM tempTable)
AND refsCompleted <= 100";
$ps_update = $db->prepare($updateSql);
$ps_update->execute();
} else {
echo "There were no reference ids found from \$dbh";
}

PHP code that subtracts from SQL when link is used

Good Day
I have a link that does the following
Find Client
It then runs the required page. I need when the link is used for it to subtract one value from a SQL database I have.
The database has the following Rows
id date credit
$sql = "UPDATE items SET credit = credit - 1";
I have tried entering the above string into the code as such:
Find Client
But can't seem to get it to work.
Please assist all I need is one credit to be deducted when the link is used. but the link must still preform the href as well
EDITED:
$sql = "insert into avis_lbs_log set lng = '".$long."', lat = '".$lat."', distance =
'".$distance."', msisdn = '".$msisdn."', date_time = '".$today."'";
$sql = "UPDATE avis_credit SET cred = cred - 1'";
You have to fire this query in lbs_map.php to decrement the value
//lbs_map.php
<?php
//mysql connection
$sql = "UPDATE items SET credit = credit - 1";
//execute the sql query
//your rest of code
What you need to do is set up code that doesn't contain your statement. This is to prevent SQL injection. A better way of doing it is:
Find Client
Then in your PHP, you can check if $_GET['do'] == 'update' and perform the update.

How do I apply a mathematical mysql query to each row in a database?

I am designing a database for an MMORPG, and the administrator back end. I need a function that will allow me to add a specified amount of the game's primary currency: Gold to each account in the database.
This is what I have:
function massAddGold($gold_amount){
dbconnect();
$value=mysql_query("SELECT * from `mmo_db1`.`users`;");
while ($row=mysql_fetch_array($value)){
$currentgold=$row['gold'];
$newgold=$currentgold+$gold_amount;
mysql_query("UPDATE `mmo_db1`.`users` SET `gold` = \"$newgold\";");
}
dbclose();
}
where mmo_db1 is the name of the database.
When I execute the command, massAddGold("50"); I then check the database. It takes the row with the highest value of Gold, adds the 50 gold to that, then applies that value to all of the rows. I need it to execute on each row individually.
Why do it in two queries what is wrong with one
UPDATE users SET gold = gold + 50;
mysql_query("UPDATE mmo_db1.users SET gold = gold+50");
ps, mysql* =bad
Why do a select first? If you want to give everyone an extra 50 gold, why not do something like:
UPDATE `mmo_db1`.`users` SET `gold` = `gold`+ $newgold;

Categories