Keep subtracting value in loop getting mysql result php - php

I have an mysql table named example.
Id | Amount | Left | Filled
1 | 1 | 1 | 0
2 | 4 | 4 | 0
5 | 7 | 7 | 0
I have an variable named $var = 9
Now I have an array named $array with those ids as array([0] => 1, [1] => 2, [2] => 5) Which itself is a mysql result.
How do I make a loop so that ids in array keep subtracting the left and keep filling as per the amount but within the total value of $var so that my end result in table is
Id | Amount | Left | Filled
1 | 1 | 0 | 1
2 | 4 | 0 | 4
5 | 7 | 3 | 4

You can use while loop in order to loop on the ids and reduce the amount in each iteration.
I am not sure how you access your DB so I leave it pseudo.
Consider the following code:
$ids = array(1,2,5);
$value = 9;
function reduceAmount($id, $value) {
$query = mysqli_query($conn, "SELECT * FROM example WHERE Id='$id'");
$row = mysqli_fetch_array($query);
$take = min($row['Left'], $value); // the amount you can take (not more then what left)
$left = $row['Left'] - $take;
$filled = $row['Filled'] + $take;
$conn->query("UPDATE example SET Left='$left', Filled='$filled' WHERE Id='$id'")
return max(0, $value - $take);
}
while ($value > 0 && !empty($ids)) { // check if value still high and the options ids not finish
$id = array_shift($ids); //get first ID
$value = reduceAmount($id, $value);
}
You can check at the end of the loop if value still bigger then 0 - this can happen when no enough "Amount" in ids

Related

How to query based on multiple relations between columns - MySQL?

I have four columns in a properties table: property_id, value, id, material_id.
I also have an array of properties: Array $properties
The schema is a bit complicated, because I want to find the material_id based on the matching properties.
An example:
$properties = array(['property_id'=>1,'value'=>3],['property_id'=>2,'value'=>6],['property_id'=>3,'value'=>4]);
Example table output:
+----+-------------+-------------+-------+
| id | material_id | property_id | value |
+----+-------------+-------------+-------+
| 1 | 1 | 3 | 5 |
| 2 | 1 | 3 | 5 |
| 3 | 1 | 3 | 5 |
| 4 | 2 | 1 | 3 |
| 5 | 2 | 2 | 6 |
| 6 | 2 | 3 | 4 |
| 10 | 4 | 1 | 9 |
| 11 | 4 | 2 | 3 |
| 12 | 4 | 3 | 6 |
+----+-------------+-------------+-------+
Now, I need material_id that satisfies all the properties. How can I do that..? Do I need to use exist statement of MySQL?
Now, for each element in your array you will want to run a statement that looks like this:
SELECT material_id FROM properties WHERE property_id = 2 AND value = 3;
Do you need help on the php code also? You could run a for each loop, but I will need to know what way you are using to communicate with your database for more specifics.
edit
foreach ($properties as $foo => $bar)
{
$sql = 'SELECT material_id FROM properties WHERE ';
foreach ($bar as $key => $value)
{
$sql .= $key .' = '. $value .' AND ';
}
$sql .= 'true';
*run your PDO code on $sql here*
}
On behalf of performance, it's not a good idea to run a query per array's value. If you have an oversized array things can get pretty slower.
So, best solution can be to build a single query including all conditions presented on $properties array:
<?php
$properties = array(['property_id'=>1,'value'=>3],['property_id'=>2,'value'=>6],['property_id'=>3,'value'=>4]);
$qCondition = [];
foreach($properties as $prop) {
$q = sprintf("(property_id = %d AND value = %d)", $prop["property_id"], $prop["value"]);
$qCondition[] = $q;
}
// assuming that your database table name is 'materials'
$sql = sprintf("SELECT * FROM materials WHERE (" . implode(" OR ", $qCondition) . ")");
echo $sql;
Result:
SELECT * FROM materials
WHERE ((property_id = 1 AND value = 3) OR (property_id = 2 AND value = 6) OR (property_id = 3 AND value = 4))
Therefore, you need to run only one single query to get all desired rows.
You can play with suggested solution here: http://ideone.com/kaE4sw

While doesn't count to the last element of an array

I have some lines of data on a table as shown below :
+-------------------+-------+
| criteria | value |
+-------------------+-------+
| Pengalaman Kerja | 4 |
| Pendidikan | 3 |
| Usia | 5 |
| Status Perkawinan | 2 |
| Alamat | 6 |
| Pengalaman Kerja | 3 |
| Pendidikan | 1 |
| Usia | 4 |
| Status Perkawinan | 2 |
| Alamat | 1 |
+-------------------+-------+
10 rows in set (0.00 sec)
I tried to fetch them all in PHP using fetch_object() and then convert the returned data into arrays and sum the values of each criteria listed on the table.
example : Pengalaman kerja has two values (4 and 3) so the result for Pengalaman Kerja array will be 7.
$result = $db->query($sql);
$value = array();
while($row=$result->fetch_object()){
if(!isset($value[$row->criteria]){
$value[$row->criteria] = 0;
})
$value[$row->criteria] += $row->value;
var_dump($value);
}
When I ran var_dump to $value (which is now contains summed value of each criteria) it showed me :
array(5) {
["Pengalaman Kerja"]=>
int(7)
["Pendidikan"]=>
int(4)
["Usia"]=>
int(9)
["Status Perkawinan"]=>
int(4)
["Alamat"]=>
int(6)
}
Pengalaman kerja is correct because 4 + 3 = 7
Pendidikan is correct because 3 + 1 = 4
Usia is correct because 5 + 4 = 9
Status Perkawinan is correct because 2 + 2 = 4
And the wrong thing is Alamat showing 6 that it should be 7 because 6 + 1 = 7
I'm sure it was because one of Alamat record was on the last of lines and the while() function didn't count until the last of lines.
While() function only counted to the last - 1
How can I solve this problem so Alamat shows 7 as it is suppossed to show ?
Why even bother doing this in PHP? If you just want the sum of all rows grouped by criteria then do it with a simple MySQL query?
SELECT criteria, SUM(value) AS total FROM table GROUP BY criteria
EDIT: If you insist on doing it your way then aside from a couple of typos in your code, which would usually cause runtime errors, your code should work as expected. When I run it against a table with the exact same data I get the expected results.
BTW, PDOStatement has no method called fetch_object (this is the name of the helper function) so if you want to use a method to fetch the query results as an object for a PDOStatement you have to use the proper name which is fetchObject().
PHP
$result = $dbh->query("SELECT * FROM test");
$value = array();
while ($row = $result->fetchObject()) {
if (!isset($value[$row->criteria])) {
$value[$row->criteria] = 0;
}
$value[$row->criteria] += $row->value;
}
var_dump($value);
Results
array (size=5)
'Pengalaman Kerja' => int 7
'Pendidikan' => int 4
'Usia' => int 9
'Status Perkawinan' => int 4
'Alamat' => int 7

Merge first column that has the same second column

I have an INNER JOIN query that returns this result:
first column | second column
2 | 15
5 | 16
6 | 16
5 | 18
6 | 22
I want to output them in my page like this:
first column | second column
2 | 15
5,6 | 16
| 18
| 22
Total first column: 2
It will combine the first column that has the same second column. And value of the combined first column will be share between them.
And would also tell the total first column (which in the example is 2).
I'm still trying with this code:
if($stmt = $con->prepare("SELECT firsttb.firstcolumn, secondtb.secondcolumn FROM firsttb INNER JOIN secondtb ON firsttb.connectid = secondtb.connectid WHERE firsttb.getid = ? ORDER BY secondtb.secondcolumn")){
$stmt->bind_param("i",$_GET["getid"]);
$stmt->execute();
$stmt->bind_result($firstcolumn,$secondcolumn);
$lastid = 0;
$total = 0;
$combine = "";
while($stmt->fetch()){
if($lastid == $secondcolumn){
$combine = $combine."".$firstcolumn;
$lastid = $secondcolumn;
}
else {
$totalrow = $totalrow + 1;
$lastid = $secondcolumn;
$combine = $secondcolumn;
echo $combine." | ".$secondcolumn."<br>";
}
}
$stmt->close();
echo "Total first column: ".$totalrow;
}
But only get this output:
first column | second column
2 | 15
5 | 16
5 | 18
6 | 22
Total first column: 4
It is okay to scrap my code and create it with your own. Just want to look for the right idea.

Add one to INT in table if not exists issue

(this is my first question so sorry if I do something wrong)
So I am trying to write a tournament standings program. The idea is submit 12 players through a form with their placement and then if that person is not already in the table, create a row in a DB and if it is in the table, add one to the appropriate column. Here is the applicable code :
for($i = 1; $i < 14; $i++) {
$g = $i - 1;
$fields = array('first', 'second', 'third', 'fourth', 'lose', 'tie');
$array[$g] = array($_GET['nameplayer' . $i], $_GET['placementplayer' . $i]); //Because there are 12 people, I used a for-loop for selecting player # hence the $array[$g]. It is being filled with the name and placement
//Insert Player Name
if($array[$g][0] != "") {
$k = $array[$g][0]; //Name of the person
$z = $_GET['tournyname'];
$t = $array[$g][1]; //Placement of the person (can be 1, 2, 3, 4, tie or lose)
$checkme = mysql_query("SELECT * FROM tournamentstandings WHERE name = '$k' AND tournyname = '$_GET[tournyname]'")or die(mysql_error()); //Getting the specific row for the guy I wanna add +1 to
if($t != "Tie" && $t != "Loss") { //Defining $y which is the field name for where the +1 should go
$y = $fields[$t - 1];
} else if ($t == "Tie") {
$y = $fields[5];
} else if ($t == "Loss") {
$y = $fields[4];
}
if (mysql_num_rows($checkme)){
$qone = mysql_query("SELECT $y FROM tournamentstandings WHERE name = '$k' AND tournyname = '$_GET[tournyname]'");
while($query = mysql_fetch_array($qone)) {
echo "updated";
mysql_query("UPDATE tournamentstandings SET $y = '$qone[$y] + 1' WHERE name = '$k' AND tournyname = '$z'") or die(mysql_error()); //THIS IS THE TROUBLE LINE
}
}
else if($y == "first" && !mysql_num_rows($checkme)) {
mysql_query("REPLACE INTO tournamentstandings(name, first, tie, second, third, fourth, lose, tournyname, totalplayed, totalpoints, pointspergame, winpercentage) VALUES('$k', '1', '0', '0', '0', '0', '0', '$z', '0', '0', '0', '0')")or die(mysql_error()); //Does the exact same thing but for $y == "second" and so on inserting 1 if the row does not already exist
}
So the issue is that sometimes when I add a new player, it goes to like 3 instead of 1 meaning that the 'trouble line' is called but no "update" (echoed) is displayed which is bizarre. If I comment out that line, it works fine but will not add +1 if the row already exists
So table wise lets say someone submits 12 names; name1 (first), name2 (second), name3 (third), name4 (fourth), name5 (lose) ... name 12 (lose) and none of those exist all under tournyname FFA (can be FFA, 1 Ally, 2 Ally, 6v6 which you can specify in the form)
it should be :
name | first | tie | second | third | fourth | lose | tournyname
name1| 1 | 0 | 0 | 0 | 0 | 0 | FFA
name2| 0 | 0 | 1 | 0 | 0 | 0 | FFA
name3| 0 | 0 | 0 | 1 | 0 | 0 | FFA
name4| 0 | 0 | 0 | 0 | 1 | 0 | FFA
name5| 0 | 0 | 0 | 0 | 0 | 1 | FFA
and so on
but what is happening is:
name | first | tie | second | third | fourth | lose | tournyname
name1| 3 | 0 | 0 | 0 | 0 | 0 | FFA
name2| 0 | 0 | 3 | 0 | 0 | 0 | FFA
name3| 0 | 0 | 0 | 2 | 0 | 0 | FFA
name4| 0 | 0 | 0 | 0 | 1 | 0 | FFA
name5| 0 | 0 | 0 | 0 | 0 | 1 | FFA
Or something random like that where the first 3 are broken and the last few are okay. When I try to update it later (just add one to an existing row, it works fine. It is just that initial submission. I have tried a while to figure out what it is and I dont know. I have tried :
Changing queries using REPLACE
Limiting the number of times the for loop runs to the number of submitted entries (does not have to be 12, can be 1-12
Adding AUTO_INCREMENT id
Primary Key changes
and a whole bunch of playing around with the select queries and such. Is there something small I am missing? :) If I am missing something that yall need just let me know!
Thanks very much!
INSERTED IMAGE OF ISSUE ::
All of the red boxes indicate the THIRD BATCH OF 12 all of the black boxes indicated the errors. Those numbers should be one because before I submitted the form, those rows did not exist. All of the names are unique so nothing in that pic should be above a one.
You can use insert...on duplicate key update in place of first searching for value and then updating the value. It will reduce MySQL operation to single query and must solve your problem as well.
It might simplify your life if you pushed the SQL calls to stored procs in the database, then you can test the SQL separately from the application code.
while($query = mysql_fetch_array($qone)) {
echo "updated";
$val=$query["$y"]+1;
mysql_query("UPDATE tournamentstandings SET $y = '$val' WHERE name = '$k' AND tournyname = '$z'") or die(mysql_error()); //THIS IS THE TROUBLE LINE
}

MySQL: applying a random sort on multiple columns

In order to have a well scrambled table (for a psychological experiment), I'd like to sort each column of my array by RAND().
Althrough this code works:
SELECT Sort.Variable1, Sort.Variable2 FROM Sort ORDER BY Variable1, Variable2 ASC LIMIT 0 , 30
replacing "ASC" by "RAND()" make the query fail. Can someone give me an advice (even a solution with PHP) ?
Thanks
Edit:
Thanks to all your responses, I finally did it. Here's my PHP code for this (and sorry for the old-fashioned-not-brand-new-PDO-queries). Even if it's maybe useless, I post it:
$i=0;
//Describe to retrieve variables' names
$sqlCol= 'DESCRIBE Sort';
$sqlCol= mysql_query($sqlCol);
while ($res=mysql_fetch_array($sqlCol)) {
$var[$i]=$res['Field'];
$i++;
}
$NbCol=mysql_num_rows($sqlCol); //Number of column to shuffle
// Number of items for each column
$sqlCount= 'SELECT COUNT(*) FROM Sort';
$req2= mysql_query($sqlCount) or die ('Err');
$NbLignes= mysql_result($req2,0,0) or die ();//Number of rows
//Data array
$sql= "SELECT * FROM Sort";
$req= mysql_query($sql) or die ('Err');
$sort=mysql_fetch_array($req);
for($i=0;$i<$NbCol;$i++) {
${'sql'.$i}='SELECT * FROM Sort ORDER BY RAND()';
${'input'.$i} = mysql_query(${'sql'.$i});
while(${'array'.$i}=mysql_fetch_array(${'input'.$i})) {
$bigArray[$i][]=${'array'.$i}[$i];
}
}
for($i=0;$i<$NbLignes;$i++) {
echo '<div id="q'.$i.'"style="margin-bottom: 50px; float:left">Question '.($i+1);
echo '<ul id="sortable'.$i.'" class="sortable">';
for($j=0;$j<$NbCol;$j++) {
echo '<li class="ui-state-default" id="'.$var[$j].$i.'" name="'.$var[$j].$i.'">'. $bigArray[$j][$i].'</li>';
}
echo '</ul></div>';
}
Using ORDER BY RAND() won't randomize columns - it will randomize rows.
To randomize each column separately in SQL you can:
create a result set for each column separately
randomize the order of each of them
join the columns by row number
Unfortunately the MySQL development team haven't yet implemented ROW_NUMBER which would have made this task easy, but you can workaround it by simulating ROW_NUMBER using variables:
SELECT
Column1,
Column2
FROM
(
SELECT Column1, #rn1 := #rn1 + 1 AS rank
FROM Table1, (SELECT #rn1 := 0) vars
) T1
JOIN
(
SELECT Column2, #rn2 := #rn2 + 1 AS rank
FROM Table1, (SELECT #rn2 := 0) vars
ORDER BY RAND()
) T2
ON T1.rank = T2.rank
Here is one possible method to do what you want using PHP. In the example code, I generate a list of numbers and place them in an array. You will need to grab the list from your database.
<?php
// Create 20 rows.
$rows = 20;
// Create an empty array to hold sorted values.
$sort = array();
// Fill the array with ascending/descending numbers.
for ($i = 0; $i < $rows; $i++) {
$sort[$i]['var1'] = $i + 1;
$sort[$i]['var2'] = $rows - $i;
}
// Display the sorted array.
print "Sorted:\n";
print_rows($sort);
// Here's where the important bit happens:
// Create two arrays, each containing a list of the
// array keys from the sorted array (one for each column).
$var1 = array_keys($sort);
$var2 = array_keys($sort);
// Shuffle each list or array keys (one for each column).
shuffle($var1);
shuffle($var2);
// Create an empty array to hold shuffled values.
$shuffle = array();
// For every row in the list of shuffled keys, get
// the matching value from the sorted array, and
// place it in the shuffled array.
for ($i = 0; $i < $rows; $i++) {
$shuffle[$i]['var1'] = $sort[$var1[$i]]['var1'];
$shuffle[$i]['var2'] = $sort[$var2[$i]]['var2'];
}
// Display the shuffled array.
print "\nShuffled:\n";
print_rows($shuffle);
function print_rows($array) {
print "Row | Var 1 | Var2\n";
print "------------------\n";
foreach ($array as $key=>$row) {
printf("%3d | %5d | %4d\n", $key, $row['var1'], $row['var2']);
}
}
?>
Here's the output:
Sorted:
Row | Var 1 | Var2
------------------
0 | 1 | 20
1 | 2 | 19
2 | 3 | 18
3 | 4 | 17
4 | 5 | 16
5 | 6 | 15
6 | 7 | 14
7 | 8 | 13
8 | 9 | 12
9 | 10 | 11
10 | 11 | 10
11 | 12 | 9
12 | 13 | 8
13 | 14 | 7
14 | 15 | 6
15 | 16 | 5
16 | 17 | 4
17 | 18 | 3
18 | 19 | 2
19 | 20 | 1
Shuffled:
Row | Var 1 | Var2
------------------
0 | 8 | 2
1 | 19 | 12
2 | 14 | 5
3 | 16 | 17
4 | 2 | 8
5 | 11 | 4
6 | 7 | 11
7 | 9 | 10
8 | 12 | 1
9 | 5 | 9
10 | 13 | 20
11 | 10 | 6
12 | 17 | 19
13 | 18 | 18
14 | 4 | 14
15 | 20 | 7
16 | 3 | 16
17 | 15 | 15
18 | 6 | 3
19 | 1 | 13
The code is a bit rough and ready. I'm sure there are a number of ways in which it could be improved. For example, you could change it so the it is able to handle a variable number of columns. However, the basic idea is there.
Edit:
Here's a tidied up version of the code, which will handle a variable number of columns:
// Here's where the important bit happens:
// Create an empty array to hold shuffled values.
$shuffle = array();
// Get the name of each column (key) in the array.
foreach (array_keys($sort[0]) as $col) {
// Create an array of keys containing a list of the
// array keys from the sorted array.
$keys = array_keys($sort);
// Shuffle each list or array keys.
shuffle($keys);
// For every row in the list of shuffled keys, get
// the matching value from the sorted array, and
// place it in the shuffled array.
for ($i = 0; $i < $rows; $i++) {
$shuffle[$i][$col] = $sort[$keys[$i]][$col];
}
}
// Display the shuffled array.
print "\nShuffled:\n";
print_rows($shuffle);
You can do by 2 SQL statments:
SELECT Sort.Variable1 FROM Sort ORDER BY RAND(), Variable1 LIMIT 0 , 30
SELECT Sort.Variable2 FROM Sort ORDER BY RAND(), Variable2 LIMIT 0 , 30
if you need random in PHP array use: [array_rand][1]
<?php
// load all table values in array i just set them
$input = array("Neo", "Morpheus", "Trinity", "Cypher", "Tank");
$rand_keys = array_rand($input, 2);
echo $input[$rand_keys[0]] . "\n";
echo $input[$rand_keys[1]] . "\n";
?>

Categories