Find lowest value from multiple array php [closed] - php

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I'm developing a number based game to calculate the combined lowest number from a multiple array.
Example:
$arr1 = array('score_1'=>0,'score_2'=>5,'score_3'=>0,'score_4'=>2,'score_5'=>1);
$arr2 = array('score_1'=>3,'score_2'=>0,'score_3'=>2,'score_4'=>0,'score_5'=>0);
$arr3 = array('score_1'=>0,'score_2'=>0,'score_3'=>0,'score_4'=>4,'score_5'=>0);
The above example result will be:
score_1 = 0+3+0 = 3
score_2 = 5+0+0 = 5
score_3 = 0+2+0 = 2
score_4 = 2+0+4 = 6
score_5 = 1+0+0 = 1 /*This is the winning number*/
Each array is a submission from each user, stored in a single db field (instead of in separate fields eg.. score_1,score_e etc...)
I'm not using separate table field because the game requires 180 score fields later. To optimize the database I'm using an array instead of table field for each score.
I'm storing each row like this:
score_1:0,score_2:0 etc...
Later I'm looping through each row like:
$main_score[main_score] = $array_score[score_$key]=$value;
And the end result for each row:
$arr1 = array('score_1'=>0,'score_2'=>5,'score_3'=>0,'score_4'=>2,'score_5'=>1);
How do I make the calculation?
Explain me how am i gonna deal with this situation: Ref: below image.
This isn't it, there are more 210 individual inputs more to go.
Similar application

You really should read about database normalization, then if you normalize your database, it isn't important if you store 5 or 100 scores per user. Take a look at the following table schemas:
users
id
name
scores
id
user_id
score_nr
value
To fetch your example result from these tables, you have to use the following query:
SELECT `score_nr`, SUM(`value`) AS `value_sum`
FROM `scores` GROUP BY `score_nr`
To fetch the score_nr with the smallest sum:
SELECT `score_nr`, SUM(`value`) AS `value_sum`
FROM `scores` GROUP BY `score_nr` ORDER BY `value_sum` ASC LIMIT 1

Loop trough the arrays simultaneously and calculate the sum of them. Keep track of the smallest key and value:
$smallest_val = PHP_INT_MAX;
$smallest_key = '';
foreach($arr1 as $key => $val) {
echo $key ." = ". $val ."+". $arr2[$key] ."+". $arr3[$key] ."<br />";
$sum = $val + $arr2[$key] + $arr3[$key];
if($sum < $smallest_val) {
$smallest_val = $sum;
$smallest_key = $key;
}
}
echo "Winrar: ". $smallest_key . " with value " . $smallest_val;
Working example

i think you can make one new table on your database for scoring.
for example you have table game which primary key by game_id
table : scoring
------------------------------------
|id|game_id | score_no| arr | score |
------------------------------------
|1 | 0 | score_1 | 1 | 0 |
|2 | 0 | score_2 | 1 | 5 |
|3 | 0 | score_3 | 1 | 0 |
|4 | 0 | score_4 | 1 | 2 |
|5 | 0 | score_5 | 1 | 1 |
|6 | 0 | score_1 | 2 | 0 |
|7 | 0 | score_2 | 2 | 5 |
|8 | 0 | score_3 | 2 | 0 |
|9 | 0 | score_4 | 2 | 2 |
|10| 0 | score_5 | 2 | 1 |
|11| 0 | score_1 | 3 | 0 |
|12| 0 | score_2 | 3 | 5 |
|13| 0 | score_3 | 3 | 0 |
|14| 0 | score_4 | 3 | 2 |
|15| 0 | score_5 | 3 | 1 |
------------------------------------
and you can select it with query
SELECT score_no, SUM(`score`) AS `sum_score` FROM `scores` GROUP BY game_id, score_no

If you want to stick with your current schema, the solution with the least amount of code should be the following:
$summedScores = array_map('array_sum', array_merge_recursive($arr1, $arr2, $arr3));
asort($summedScores, SORT_NUMERIC);
reset($summedScores);
$winnerScoreNr = key($summedScores);

Related

Reorder mysql table ROWS on front end, and update backend [duplicate]

I have a table of food items. They have a "Position" field that represents the order they should appear in on a list (listID is the list they are on, we don't want to re-order items on another list).
+--id--+--listID--+---name---+--position--+
| 1 | 1 | cheese | 0 |
| 2 | 1 | chips | 1 |
| 3 | 1 | bacon | 2 |
| 4 | 1 | apples | 3 |
| 5 | 1 | pears | 4 |
| 6 | 1 | pie | 5 |
| 7 | 2 | carrots | 0 |
| 8,9+ | 3,4+ | ... | ... |
+------+----------+----------+------------+
I want to be able to say "Move Pears to before Chips" which involves setting the position of Pears to position 1, and then incrementing all the positions inbetween by 1. so that my resulting Table look like this...
+--id--+--listID--+---name---+--position--+
| 1 | 1 | cheese | 0 |
| 2 | 1 | chips | 2 |
| 3 | 1 | bacon | 3 |
| 4 | 1 | apples | 4 |
| 5 | 1 | pears | 1 |
| 6 | 1 | pie | 5 |
| 7 | 2 | carrots | 0 |
| 8,9+ | 3,4+ | ... | ... |
+------+----------+----------+------------+
So that all I need to do is SELECT name FROM mytable WHERE listID = 1 ORDER BY position and I'll get all my food in the right order.
Is it possible to do this with a single query? Keep in mind that a record might be moving up or down in the list, and that the table contains records for multiple lists, so we need to isolate the listID.
My knowledge of SQL is pretty limited so right now the only way I know of to do this is to SELECT id, position FROM mytable WHERE listID = 1 AND position BETWEEN 1 AND 5 then I can use Javascript (node.js) to change position 5 to 1, and increment all others +1. Then UPDATE all the records I just changed.
It's just that anytime I try to read up on SQL stuff everyone keeps saying to avoid multiple queries and avoid doing syncronous coding and stuff like that.
Thanks
This calls for a complex query that updates many records. But a small change to your data can change things so that it can be achieved with a simple query that modifies just one record.
UPDATE my_table set position = position*10;
In the old days, the BASIC programming language on many systems had line numbers, it encouraged spagetti code. Instead of functions many people wrote GOTO line_number. Real trouble arose if you numbered the lines sequentially and had to add or delete a few lines. How did people get around it? By increment lines by 10! That's what we are doing here.
So you want pears to be the second item?
UPDATE my_table set position = 15 WHERE listId=1 AND name = 'Pears'
Worried that eventually gaps between the items will disappear after multiple reordering? No fear just do
UPDATE my_table set position = position*10;
From time to time.
I do not think this can be conveniently done in less than two queries, which is OK, there should be as few queries as possible, but not at any cost. The two queries would be like (based on what you write yourself)
UPDATE mytable SET position = 1 WHERE listID = 1 AND name = 'pears';
UPDATE mytable SET position = position + 1 WHERE listID = 1 AND position BETWEEN 2 AND 4;
I've mostly figured out my problem. So I've decided to put an answer here incase anyone finds it helpful.
I can make use of a CASE statement in SQL. Also by using Javascript beforehand to build my SQL query I can change multiple records.
This builds my SQL query:
var sql;
var incrementDirection = (startPos > endPos)? 1 : -1;
sql = "UPDATE mytable SET position = CASE WHEN position = "+startPos+" THEN "+endPos;
for(var i=endPos; i!=startPos; i+=incrementDirection){
sql += " WHEN position = "+i+" THEN "+(i+incrementDirection);
}
sql += " ELSE position END WHERE listID = "+listID;
If I want to move Pears to before Chips. I can set:
startPos = 4;
endPos = 1;
listID = 1;
My code will produce an SQL statement that looks like:
UPDATE mytable
SET position = CASE
WHEN position = 4 THEN 1
WHEN position = 1 THEN 2
WHEN position = 2 THEN 3
WHEN position = 3 THEN 4
ELSE position
END
WHERE listID = 1
I run that code and my final table will look like:
+--id--+--listID--+---name---+--position--+
| 1 | 1 | cheese | 0 |
| 2 | 1 | chips | 2 |
| 3 | 1 | bacon | 3 |
| 4 | 1 | apples | 4 |
| 5 | 1 | pears | 1 |
| 6 | 1 | pie | 5 |
| 7 | 2 | carrots | 0 |
| 8,9+ | 3,4+ | ... | ... |
+------+----------+----------+------------+
After that, all I have to do is run SELECT name FROM mytable WHERE listID = 1 ORDER BY position and the output will be as follows::
cheese
pears
chips
bacon
apples
pie

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

How to handle 2 dimensional array, sent from angular to php, for database query [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have created a 2 dimensional array order_details in angular that has the following structure:
| order_id | product_id |
+==========+============+
| 1 | 2 |
+----------+------------+
| 1 | 3 |
+----------+------------+
| 2 | 4 |
+----------+------------+
| 3 | 2 |
+----------+------------+
I used post method to send this array to a php file.
In php file I use the following code to store the array:
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
$array = $request;
I want to execute an update query in mysql using the array like this:
UPDATE table_ex SET status='completed' WHERE order_id IN array.order_id AND product_id IN array.product_id
Table_ex before the query looks like:
| order_id | product_id | status |
+==========+============+=========+
+----------+------------+---------+
| 5 | 4 | nothing |
+----------+------------+---------+
| 6 | 2 | nothing |
+----------+------------+---------+
| 1 | 2 | nothing |
+----------+------------+---------|
| 1 | 3 | nothing |
+----------+------------+---------+
| 2 | 4 | nothing |
+----------+------------+---------+
| 3 | 2 | nothing |
+----------+------------+---------+
After the update the table_ex should look like this:
Table_ex before the query looks like:
| order_id | product_id | status |
+==========+============+===========+
| 5 | 4 | nothing |
+----------+------------+-----------+
| 6 | 2 | nothing |
+----------+------------+-----------+
| 1 | 2 | completed |
+----------+------------+-----------+
| 1 | 3 | completed |
+----------+------------+-----------+
| 2 | 4 | completed |
+----------+------------+-----------+
| 3 | 2 | completed |
+----------+------------+-----------+
Could you help me!
Thanks in advance,
Giannis
Your query would set order_id=6, product_id=2 to 'completed' as well, because the 2 is in the product_id array. Solve it with OR-joined AND-subconditions like this:
$cond = array();
foreach ($array as $part) {
$cond[] = sprintf('(order_id="%s" AND product_id="%s")',
$part['order_id'], $part['product_id']);
}
$sql = 'UPDATE table_ex SET status='completed' WHERE '.join(' OR ', $cond);
(Hope I got the structure of your array correctly.)
That will generate a query which looks like
UPDATE table_ex SET status='completed'
WHERE (order_id="1" AND product_id="2")
OR (order_id="1" AND product_id="3")
OR (order_id="2" AND product_id="4")
OR (order_id="3" AND product_id="2")

best way to display value from mysql inner join

I haven't been coding for a while, and i started a new project lately.
In that project, i need to make a very simple inner join to associate values from 2 tables:
table questions:
id | question | order
1 | how? | 1
2 | what? | 2
3 | when? | 3
table answers:
id_question | answer | order
1 | this way | 1
1 | that way | 2
2 | this | 1
2 | that | 2
3 | now | 1
3 | later | 2
How can I correctly get the questions and related answers, and display them, ordered by order?
I did this:
SELECT id, question, Q.order as qorder, id_question, answer, A.order as aorder FROM questions as Q INNER JOIN answers as A ON Q.id = A.id_question ORDER BY qorder
which result in this:
id | question | qorder | id_question | answer | aorder
1 | how? | 1 | 1 | this way | 1
1 | how? | 1 | 1 | that way | 2
2 | what? | 2 | 2 | this | 1
2 | what? | 2 | 2 | that | 2
3 | when? | 3 | 3 | now | 1
3 | when? | 3 | 3 | later | 2
DISPLAYING RESULTS:
$same_id = -1;
while ( $poll = $qa -> fetch() ) {
if ($poll['id'] == $same_id ) {
echo '<li>'.$poll['answer'].'</li>';
}
else {
if ( $poll['id'] == $same_id+1 ) { echo '</ul>'; }
echo '<ul>'.$poll['question'];
echo '<li>'.$poll['answer'].'</li>';
$same_id = $poll['id'];
}
echo '</ul>';
}
which display:
<ul>How?
<li>this way</li>
<li>that way</li>
</ul>
<ul>What?
<li>this</li>
<li>that</li>
</ul>
<ul>When?
<li>now</li>
<li>later</li>
</ul>
it all works out, but it doesn't feel right.
First, I have the answers ordered by "luck", without specifying it in the request.
And then, the code feels too "complicated" for what it is.
I feel there is a better and cleaner way to do this kind of work.
You can simply use the aorder to order explicitly:
SELECT ...
FROM ...
INNER JOIN ...
ORDER BY
qorder ASC,
aorder ASC
Your code to display is alright. It could be improved by using PDOStatement::fetchAll() and foreach, but this is personal taste/preference.
$polls = $qa->fetchAll();
foreach($polls as $poll) {
// output question and answers
}

MySQL: Link answers to comments, grouped and limited

I got the following MySQL table:
+----+--------+------+
| id | answer | type |
+----+--------+------+
>| 1 | -1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
>| 4 | -1 | 2 |
| 5 | 4 | 2 |
| 6 | 4 | 1 |
>| 7 | -1 | 1 |
| 8 | 7 | 2 |
>| 9 | -1 | 2 |
>| 10 | -1 | 1 |
>| 11 | -1 | 2 |
+----+--------+------+
> = original comment
The entries with answer = -1 are the original comments.
The entries with answer != -1 are answers to the comment with the respective id.
Furthermore there are types of comments (in this case 1 or 2).
Now I want to retrieve the original comments (for a specified type and a specified limit) and their answers (type and limit do not matter). Further it would be great to group the result by the two types (again, only the original comment's type matters for grouping).
A query result for type=1 and limit=2 should look like that (not grouped yet):
+----+--------+------+
| id | answer | type |
+----+--------+------+
>| 1 | -1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
>| 7 | -1 | 1 |
| 8 | 7 | 2 |
+----+--------+------+
I have tried several kinds of queries for hours now, can I implement it without a procedure? What would the procedure look like?
I would appreciate your help a lot.
Use a subquery to get 2 original comments of type-1 first, then join the table again to get both original comments and responses.
select b.*
from (
select id
from answers
where type = 1 and answer = -1
limit 2) a
join answers b on a.id = b.id or a.id = b.answer;
fiddle
To select 2 original comments of each type, you'll need to use user-defined-variable to index each original comment. The following code indexes the first original comment as 1, the second one as 2, and so on, then resets to 1 when the type changes. Finally in the final where statement filter out indices greater than 2.
select b.*, a.idx
from (
select id, #idx:=if(#type=a.type,#idx+1,1) idx, #type:=a.type
from (select id, type from answers2 where answer is null order by type) a
join (select #type:=null, #idx:=null) b) a
join answers2 b on a.id = b.id or a.id = b.answer
where a.idx <= 2;
fiddle
Store it as a separate column or even a different table if you are worried about too much data duplication. You are overthinking it.

Categories