Trying to get code to update database column total by 3 - php

I am working on code that updates points for someone when they contribute content. I have a table "points" and a column "contributions." When I create a variable called contributions and assign it a value of 3 and then do SET contributions = $contributions such as this below code it WORKS:
$contributions = 3
$yesupdate = "UPDATE points SET contributions = $contributions WHERE ID =
$user_ID";
$stmt2 = $dbh->prepare($yesupdate);
$stmt2->bindParam(':WID', $yes_WID, PDO::PARAM_INT);
$stmt2->bindParam(':approved', $e = Y, PDO::PARAM_STR);
$stmt2->bindParam(':position', $row2[0]['position'], PDO::PARAM_INT);
$stmt2->execute();
HOWEVER, I do not want the points to be set to 3. I want it to add 3 each time. So I tried the below approach, but nothing happens:
$yesupdate = "UPDATE points SET contributions = $contributions + 3 WHERE ID
= $user_ID";
$stmt2 = $dbh->prepare($yesupdate);
$stmt2->bindParam(':WID', $yes_WID, PDO::PARAM_INT);
$stmt2->bindParam(':approved', $e = Y, PDO::PARAM_STR);
$stmt2->bindParam(':position', $row2[0]['position'], PDO::PARAM_INT);
$stmt2->execute();
Can anyone see what I am missing? Do I need to set the $contributions variable in example 2 like I did in example 1? If so, what would I assign to that variable when I just want the code to update the existing value of "contributions" in the database by 3?

You want your query to reference the current value in the column (not the variable) and add three:
UPDATE points SET contributions = contributions + 3 WHERE ID = $user_ID
You should use the prepare properly though too, have a look at: PHP Manual: PDO::prepare

$yesupdate = "UPDATE points SET contributions = contributions + 3 WHERE ID = $user_ID";
$stmt2 = $dbh->prepare($yesupdate);
$stmt2->bindParam(':WID', $yes_WID, PDO::PARAM_INT);
$stmt2->bindParam(':approved', $e = Y, PDO::PARAM_STR);
$stmt2->bindParam(':position', $row2[0]['position'], PDO::PARAM_INT);
$stmt2->execute();

Related

How to generate a sequential number that restarts yearly in a web application

I need to generate a code which consists of some arbitrary prefix, a year, and an incrementing number. The incrementing number must start at 1 at the first time when the number is generated that year.
This code needs to be added to the sqlite database and be available elsewhere in the PHP script.
What i have done now uses 4 accesses to the database:
$codePrefix = 'TEST';
$stmt = $db->prepare(
'INSERT INTO test (year)
VALUES(strftime("%Y", "now"))'
);
$stmt->execute();
$id = $db->lastInsertId();
$stmt = $db->prepare('SELECT `year` FROM `test` WHERE `id`=:id');
$stmt->bindValue(':id', $id);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$year = $result['year'];
$stmt = $db->prepare('SELECT Ifnull(Max(id), 0) `max_id` FROM `test`
WHERE `year`<:year');
$stmt->bindValue(':year', $year);
$result = $stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$previousMax = $result['max_id'];
$codeSuffix = $id-$previousMax;
$code = "{$codePrefix}-{$year}-{$codeSuffix}";
$stmt = $db->prepare('UPDATE `test` SET `code`=:code WHERE `id`=:id');
$stmt->bindParam(':code', $code);
$stmt->bindParam(':id', $id);
$stmt->execute();
Here i am abusing the fact that the id is an integer primary key, and autoincrements.
This works. But i feel that it is doing something very easy in a very complicated manner.
Is there a better solution? I need to assume that the midnight of the first of January can happen at any moment of the code, so i cannot do things like get the year information from PHP without hitting the database.
Before somebody asks, the reason i am using prepared statements even when no values are bound is because late on obviously more data will be inserted into the table.
Consider a pure SQL solution using the ROW_NUMBER window function. Below assigns to new field, new_id:
UPDATE test
SET new_id = 'TEST_' || test.[Year] || '_' || sub.rn
FROM (
SELECT id,
[Year],
ROW_NUMBER() OVER (PARTITION BY [Year] ORDER BY id) AS rn
FROM test
) AS sub
WHERE test.id = sub.id;

PHP while() function is running my query 3 times

My problem is that:
I have a users table in MySQL. I made a query with MySQLi which looks like:
if($stmt = $mysqli->prepare("SELECT condition,name,money FROM users WHERE fbid = ?")){
$stmt->bind_param('s',$_SESSION['FBID']);
$stmt->execute();
$stmt->store_result();
$num_of_rows = $stmt->num_rows;
$stmt->bind_result($condition,$name,$money);
while ($stmt->fetch()) {
And here's my problem, because I want different users to add equal usernames to their ids. So, my code is the following:
if($_GET['name']!='' && $money>'500'){
$stmt2 = $mysqli->prepare("UPDATE users SET `condition` = `condition` + 5, `money` = `money` - 5 WHERE fbid = ? AND name = ?");
$stmt2->bind_param("ss", $_SESSION['FBID'],$_GET['name']);
$stmt2->execute();
$stmt2->close();
I want to update only that value in the database where user ID = $_SESSION[fbid] and name = $_GET[name]. So if I have an account with id 1922838445 and I have three names, for example, John, Joe, and Jill and $_GET[name]=='Joe' then update only that value at the same ids. It works until that point that update only the got value, but it does that 3 times... Because of while () maybe??? How can I fix it?
The two code samples have to come one after!! Because of checking the value of money..
There's no need for the first SELECT and the loop, just put the condition on money into the UPDATE query itself.
if ($_GET['name'] != '') {
$stmt = $mysqli->prepare("
UPDATE users
SET condition = condition + 5, money = money - 5
WHERE fbid = ? AND name = ?
AND money > 500")
$stmt->bind_param("ss", $_SESSION['FBID'], $_GET['name']);
$stmt->execute();
}
Try this instead to get only one record:
It gets only the record you need because it has a WHERE clause on both parameters that you plan to update, instead of only a partial match on the fbid like you had before.
Before you were getting 3 records because you had a partial key search, then looping through the records and updating the same record over and over against, regardless of the value of the second part of the key in the record you were looping against.
if($stmt = $mysqli->prepare("SELECT condition,name,money FROM users WHERE fbid = ? AND name = ?")){
$stmt->bind_param("ss", $_SESSION['FBID'],$_GET['name']);
$stmt->execute();

How to perform a specific calculation like 1500*20/100 using PDO or MYSQLI?

I am not sure how to perform good calculations. Example, you have inserted a value into the pay Column, lets say there is an input of $1500 and you have a Pay2 column that is blank. I want to take the 1500 and take 20% off, so I was thinking Pay*20/100 and then it would input 1200 into the Pay2 column. So in the same row, I would have 1500 and 1200. Any help would be great.
Select Pay Column in a database, do the calculation and insert it into the Pay2 column in the same row.
This could be any value, it does not have to be 1500, it could be 900 or 90.
SELECT Pay FROM database
MPay = Pay*20/100
UPDATE Pay2 Set MPay = Pay2
If you want to take a percentage off of a value you can use this function
// this function returns amount after discount
function calcDiscount($percentage, $pay){
return $pay - (($percentage/100) * $pay);
}
// call the function
$pay = 1500;
$discount = 20;
$pay2 = calcDiscount($discount, $pay);
So in your pdo and sql coding you can call the function:
//this code works for this $id. For multiple id's you will need a loop
$id = 1;
$discount = 20;
$conn = pdo_connect();
$sql = 'SELECT Pay1
FROM Your_Table
WHERE ID = :ID';
$statement = $conn->prepare($sql);
$statement->bindValue(":ID", $id, PDO::PARAM_STR);
$statement->execute();
// 1. get the pay1 from the row
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
// store the value in a variable
$pay = $result[0]['Pay1'];
// 2. calculate the discount for Pay1
$pay2 = calcDiscount($discount, $pay);
// 3. update the column for pay2
$sql = 'UPDATE Your_Table
SET Pay2 = :pay2
WHERE ID = :ID';
$statement = $conn->prepare($sql);
$statement->bindValue(":pay2", $pay2, PDO::PARAM_INT);
$statement->bindValue(":ID", $id, PDO::PARAM_STR);
$statement->execute();
$conn = null;
For your MySQL statements, you actually want to use SELECT to grab the pay from a table and UPDATE to change the value in a column

Is there any better approach to pass variables safely instead of prepared statement? [duplicate]

This question already has answers here:
Use bound parameter multiple times
(5 answers)
Closed 6 years ago.
prepared statement is a very good approach for passing variables to the query with high security and efficiency. So all fine. Just there is a small thing which sometimes makes me uncomfortable.
Actually sometimes my queries are made dynamically. And I don't know how many times should I pass a variable. Suppose this query:
UPDATE user
SET reputation = reputation + (CASE id WHEN :op THEN 2 WHEN :user THEN 15 END)
WHERE id in (:user, :op);
I should pass 2 variables ($user, $op) and I have to bind each one them twice:
$sth->bindValue(":op", $op, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":op", $op, PDO::PARAM_INT);
Well sometimes that query will be like this:
UPDATE user
SET reputation = reputation + (CASE id WHEN :op THEN 2 WHEN :user THEN 15 END)
WHERE id in (:user, :op),
fee = fee +
(CASE id WHEN :op THEN (SELECT SUM(op_val) FROM money WHERE id = :post_id)
WHEN :user THEN (SELECT SUM(user_val) FROM money WHERE id = :post_id)
END)
WHERE id in (:user, :op);
For query above, I should pass 1 more variable ($post_id). In other word 4 more bind value:
$sth->bindValue(":op", $op, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":op", $op, PDO::PARAM_INT);
$sth->bindValue(":post_id", $post_id, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":post_id", $post_id, PDO::PARAM_INT);
$sth->bindValue(":user", $user, PDO::PARAM_INT);
$sth->bindValue(":op", $op, PDO::PARAM_INT);
See? That's hard for me to pass variables to a dynamic query. I mean I have to pass one variable several times. Well is there any other approach to validate a variable instead of prepared statement?
In general one can either:
Define some user variables that are then used by subsequent queries in the same session:
$set = $pdo->prepare('SET #op = :op, #user = :user, #post = :post');
$set->bindValue('op' , $op , PDO::PARAM_INT);
$set->bindValue('user', $user, PDO::PARAM_INT);
$set->bindValue('post', $post, PDO::PARAM_INT);
$set->execute();
$sth = $pdo->query('
UPDATE user
SET reputation = reputation + CASE id
WHEN #op THEN 2
WHEN #user THEN 15
END,
fee = fee + CASE id
WHEN #op THEN (SELECT SUM(op_val) FROM money WHERE id = #post)
WHEN #user THEN (SELECT SUM(user_val) FROM money WHERE id = #post)
END
WHERE id in (#user, #op)
');
Create a materialised table that contains your variables, which you join to your query:
$sth = $pdo->prepare('
UPDATE user
JOIN (SELECT :op AS op, :user AS user, :post AS post) AS variables
SET reputation = reputation + CASE id
WHEN variables.op THEN 2
WHEN variables.user THEN 15
END,
fee = fee + CASE id
WHEN variables.op THEN (SELECT SUM(op_val) FROM money WHERE id = variables.post)
WHEN variables.user THEN (SELECT SUM(user_val) FROM money WHERE id = variables.post)
END
WHERE id in (variables.user, variables.op)
');
$sth->bindValue('op' , $op , PDO::PARAM_INT);
$sth->bindValue('user', $user, PDO::PARAM_INT);
$sth->bindValue('post', $post, PDO::PARAM_INT);
$sth->execute();
However, in this specific case, one could break the UPDATE into two:
$sth1 = $pdo->prepare('
UPDATE user
SET reputation = reputation + 2,
fee = fee + (SELECT SUM(op_val) FROM money WHERE id = :post)
WHERE id = :op
');
$sth1->bindValue('op' , $op , PDO::PARAM_INT);
$sth1->bindValue('post', $post, PDO::PARAM_INT);
$sth2 = $pdo->query('
UPDATE user
SET reputation = reputation + 15,
fee = fee + (SELECT SUM(user_val) FROM money WHERE id = :post)
WHERE id = :user
');
$sth2->bindValue('user', $user, PDO::PARAM_INT);
$sth2->bindValue('post', $post, PDO::PARAM_INT);
$sth1->execute();
$sth2->execute();
You can bind variables within the Execute. You would still prepare the statement. Instead of bindParam() you can insert variables as an array in the execute statement.
$stmt->execute(array(':var1'=>$var1, ':var2'=>$var2));

Code inserted triplicate records a few times and now works periodically

I have code that inserts a row in the points table when a user1 approves a post. I wrote code so that it only approves the post if the user is not the author of the post. There can be a maximum of 10 posts at any time to choose from for approve.
However, while this will only approve a post (and insert a record in points) if the current user is not the author of the post, it will not just insert the record for the post that is approved. Rather it will insert as many rows into points table as there are posts for user.
What I want to do is insert into points for a post that is approved by the current user where the post author is not the current user.
I am very close. This code works, except that it will insert all records if there are multiple posts by other users instead of just the one post that the current user chooses to approve.
$results2 = $dbh->prepare("select
wp_users.ID,
wp_users.display_name,
stories.ID AS ID1,
stories.SID,
writing.ID AS ID2,
writing.WID,
writing.text
FROM writing
LEFT JOIN stories on writing.SID = stories.SID
LEFT JOIN wp_users ON writing.ID = wp_users.ID
WHERE (stories.SID = $the_SID)
order by writing.WID asc limit 10
");
$results2->bindParam(':wp_users.ID', $user_ID, PDO::PARAM_INT);
$results2->bindParam(':display_name', $display_name, PDO::PARAM_STR);
$results2->bindParam(':stories.ID', $ID1, PDO::PARAM_INT);
$results2->bindParam(':stories.SID', $the_SID, PDO::PARAM_STR);
$results2->bindParam(':writing.WID', $WID, PDO::PARAM_STR);
$results2->bindParam(':writing.ID', $ID2, PDO::PARAM_INT);
$results2->bindParam(':text', $text, PDO::PARAM_STR);
$results2->execute();
$row2 = $results2->fetchAll(PDO::FETCH_ASSOC);
foreach ($row2 as $result5) {
$blurb = $result5['ID2'];
settype($blurb, "integer");
}
//PA APPROVE INSERT CONTROL
if(isset($_POST ['yes'])){
// Get values from form
$yes_WID = $_POST['yes'];
$yesupdate = "UPDATE writing SET approved = :approved, position = :position
WHERE WID = :WID";
$stmt2 = $dbh->prepare($yesupdate);
$stmt2->bindParam(':WID', $yes_WID, PDO::PARAM_INT);
$stmt2->bindParam(':approved', $e = Y, PDO::PARAM_STR);
$stmt2->bindParam(':position', $row2[0]['position'], PDO::PARAM_INT);
$stmt2->execute();
$yes_WID = $_POST['yes'];
//trying to give points as long as user is not the author
$contpoint = 3;
foreach($row2 as $result5){
if($blurb !== $user_ID){
$yesupdate2 = "INSERT INTO points(ID,
SID,
WID,
PID) VALUES(
:ID,
:SID,
:WID,
:PID)";
$stmt9 = $dbh->prepare($yesupdate2);
$stmt9->bindParam(':ID', $blurb, PDO::PARAM_INT);
$stmt9->bindParam(':SID', $the_SID, PDO::PARAM_INT);
$stmt9->bindParam(':WID', $yes_WID, PDO::PARAM_INT);
$stmt9->bindParam(':PID', $contpoint, PDO::PARAM_INT);
$stmt9->execute();
}
}
It would appear that your if condition is not being evaluated properly. Are $blurb and $user_ID the same type?
From http://php.net/manual/en/language.operators.comparison.php
$a != $b Not equal TRUE if $a is not equal to $b after type juggling.
$a !==$b Not identical TRUE if $a is not equal to $b, or they are not of
the same type.
What is the purpose of this code? It just sets $blurb to each of the values and then does nothing with the result unless the brace in between the code listings is not correctly shown. So is it a foreach inside of a foreach?
In any case, it does not appear that you set $user_ID as an integer in the same manner as you do for $blurb.
foreach ($row2 as $result5) {
$blurb = $result5['ID2'];
settype($blurb, "integer");
}
Do away with the first foreach loop and combine it with the second as such:
foreach($row2 as $result5){
$blurb = $result5['ID2'];
$userID = $result5['user_ID'];
settype($blurb, "integer");
settype($userID, "integer");
if($blurb !== $userID){
...etc

Categories