php: looping thru results from mysql query to increment counter (associative array) - php

I'm retrieving data from a MySQL db and creating reports from it. I need to get counts when certain conditions are met, and since db queries are rather expensive (and I will have a lot of traffic), I'm looping thru the results from a single query in order to increment a counter.
It seems like it's working (the counter is incrementing) and the results are somewhat close, but the counters are not correct.
At the moment, there are 411 records in the table, but I'm getting numbers like 934 from a ['total'] counter and 927 for ['males'], and that definitely can't be right. However, I get 4 from ['females'], which is correct…
I'm pretty sure it was working last night, but now it's not—I'm quite baffled. (there are still just 411 records)
$surveydata = mysql_query("SELECT `age`,`e_part`,`gender` FROM $db_surveydata;") or die(mysql_error());
$rowcount = mysql_num_rows($surveydata);
$age=array('18+'=>0,'<18'=>0,'total'=>0);
$e_part=array('yes'=>0,'no'=>0,'total'=>0);
$genders=array('male'=>0,'female'=>0,'trans'=>0,'don\'t know'=>0,'total'=>0);
while ($responses = mysql_fetch_assoc($surveydata)) {
foreach ($responses as $response){
switch ($response){
case $responses['age']:
if ($responses['age'] > 18) {$age['18+']++;$age['total']++;}
// i tried putting the ['total'] incrementer in the if/else
// just in case, but same result
else {$age['<18']++;$age['total']++;}
break;
case $responses['e_part']:
if ($responses['e_part']) {$e_part['yes']++;}
else {$e_part['no']++;}
$e_part['total']++;
break;
case $responses['gender']:
switch ($responses['gender']){
case 1:$genders['male']++;break;
case 2:$genders['female']++;break;
case 3:$genders['trans']++;break;
case 9:$genders['don\'t know']++;break;
default:break;
}
$genders['total']++;
break;
default:break;
} // end switch
} //end for
} // end while
thanks!

this is the problem:
foreach ($responses as $response){
switch ($response){
case $responses['age']:
switch $responses looks for match
foreach ($responses as $k=>$v){
switch ($k){
case 'age':
if ($v > 18) ....

mysql_fetch_assoc() retrieves a single row from the table. You then loop over that row, processing each individual field. Then the long set of if() checks to determine which field you're on. That entire structure could be changed to:
while($response = mysql_fetch_assoc($surveydata)) {
if ($responses['age'] > 18) {
$age['18+']++;
} else {
$age['<18']++;
$age['total']++;}
if ($responses['e_part']) {
$e_part['yes']++;
} else {
$e_part['no']++;
}
$e_part['total']++;
switch ($responses['gender']){
case 1:$genders['male']++;break;
case 2:$genders['female']++;break;
case 3:$genders['trans']++;break;
case 9:$genders['don\'t know']++;break;
default:break;
}
$genders['total']++;
}

There's no need for the switch ($response); you can't really switch on an array like that. And even if you could, the 'values' you get wouldn't make any sense -- i'm thinking if it works at all, the value you're switching on would be either 'Array' or the length of the array. (I forget how PHP handles arrays-as-scalars.)
You'll want something like this...
$total = 0;
while ($response = mysql_fetch_assoc($surveydata))
{
if (isset($response['age']))
{
++$age[($response['age'] < 18) ? '<18' : '18+'];
++$age['total'];
}
if (isset($response['e_part']))
{
++$e_part[($responses['e_part']) ? 'yes' : 'no'];
++$e_part['total'];
}
if (isset($response['gender']))
{
switch ($response['gender'])
{
case 1: ++$genders['male']; break;
case 2: ++$genders['female']; break;
case 3: ++$genders['trans']; break;
case 9: ++$genders["don't know"]; break;
}
++$genders['total'];
}
++$total;
}
The benefit of the if (isset(...)) is that if 'age', 'e_part', or 'gender' is null, the corresponding code to count it won't get activated. It does about the same thing as your code, minus the embarrassing loop -- and minus the counting of the field even though it is null, because every row will have the same fields.

Related

if statement multiple conditions for id

I have a database table that is called roles. and it contains 5 roles and has id from 1 to 5, I have gotten the code below to work with 1 id only but want to add more without re using the entire block. so if id equals 3,4,5 show the link. can I add multiple id's in the if?
while ($row = mysqli_fetch_assoc($result)) {
$RoleID = $row['RoleID'];
if ($RoleID == 3) {
echo '<li><span>Admin Area</span></li>';
}
}
I guess you can use in_array:
$admin_array = [3,4,5];
while ($row = mysqli_fetch_assoc($result)) {
if (in_array($row['RoleID'], $admin_array) {
echo '<li><span>Admin Area</span></li>';
}
}
Hope below code will help you
I have used in_array() function
while ($row = mysqli_fetch_assoc($result)) {
$RoleID = $row['RoleID'];
if (in_array($RoleID,array(3,4,5))) {
echo '<li><span>Admin Area</span></li>';
}
}
Something that will give some added flexibility when say you want an id to do something similar but maybe end in the same way is to use a switch case.
while ($row = mysqli_fetch_assoc($result)) {
switch($row['RoleID']) {
case 1:
//Id 1 logic only
break;
case 2:
//Id 2 logic only
break;
case 3:
//Without a break it will fall through.
//Nice because if for some reason you need
//custom for individual id do it with no break
case 4:
case 5:
echo '<li><span>Admin Area</span></li>';
break;
default:
//Do something here for instances when a ROLE ID is not found
}
}

PHP Multidimensional Array Value Replacement

I have been working on a project recently for fun.
It retrieves JSON from a game server, decodes it into an array, and then saves the array values into a SQLite DB (for display / manipulation later). I am new to programming in general, and have never touched PHP prior to this.
My question: Is there a better, more efficient way to handle this?
Basically, this section of code, loops through the large multidimensional array, and replaces values that are equal to a string. It does this prior to insertion into the DB so that I can have fields formatted to be more readable.
The problem is that in the actual script I have a huge list of defined variables now, and like 3 foreach loops with a combined 15 or so if/else if/else statements.
$sr = "Summoners Rift";
$rs = "Ranked Solo";
$rt = "Ranked Team";
$nr = "Normal";
foreach ($history['games'] as &$typeMode)
{
if ($typeMode['subType'] == 'RANKED_SOLO_5x5')
{
$typeMode['gameMode'] = $sr;
$typeMode['subType'] = $rs;
}
elseif ($typeMode['subType'] == 'RANKED_TEAM_5x5')
{
$typeMode['gameMode'] = $sr;
$typeMode['subType'] = $rt;
}
elseif ($typeMode['subType'] == 'NORMAL')
{
$typeMode['gameMode'] = $sr;
$typeMode['subType'] = $nr;
}
}
The problem is that in the actual script I have a huge list of defined
variables now, and like 3 foreach loops with a combined 15 or so IF /
ELSEIF / ELSE statements.
The best solution I can recommend based on the data your are showing is to just create a basic array of structures connected to the data you have and then just use the foreach loop to assign values based on that initial array structure:
// Set structured array values.
$array_values = array();
$array_values['RANKED_SOLO_5x5']['gameMode'] = "Summoners Rift";
$array_values['RANKED_SOLO_5x5']['subType'] = "Ranked Solo";
$array_values['RANKED_TEAM_5x5']['gameMode'] = "Summoners Rift";
$array_values['RANKED_TEAM_5x5']['subType'] = "Ranked Team";
$array_values['NORMAL']['gameMode'] = "Summoners Rift";
$array_values['NORMAL']['subType'] = "Normal";
// Set structured array values based on the sub type.
foreach ($history['games'] as &$typeMode) {
$typeMode['gameMode'] = $array_values[$typeMode['subType']]['gameMode'];
$typeMode['subType'] = $array_values[$typeMode['subType']]['subType'];
}
That way $array_values always has the preset values in place to begin with. And the assignment just happens via an array key access of $typeMode['subType'] in the foreach loop.
For things like this I prefer to use the switch control structure instead of if/elseif/else, although your approach is perfectly fine, if a little verbose maybe:
foreach ($history['games'] as &$typeMode)
{
$typeMode['gameMode'] = $sr;
switch($typeMode['subType'])
{
case 'RANKED_SOLO_5x5':
$typeMode['subType'] = $rs;
break;
case 'RANKED_TEAM_5x5':
$typeMode['subType'] = $rt;
break;
case 'NORMAL':
$typeMode['subType'] = $nr;
break;
}
}
Also if $typeMode['gameMode'] always equals $sr; then you only need that line once.

Logical clean up

I am currently having logical structure errors and I can't seem to think of a proper way of writing it out so it looks clean. Currently, I have a table in my database named USER. User has 6 fields out of the many, named: first, second, third, fourth, fifth, sixth.
What my code does is switch the data with two of the fields. So for example: the data in first is changed with the data in sixth.
Before: First - 1, Sixth - 6
After: First - 6, Sixth - 1
Currently, what I have is something that looks very messy, and I'm not sure how I can clean it up.
if($switch == true){ /* $switch just indicates if the numbers being switched is one of the fields i.e. first, second, etc.. */
if($slot == 1){ // The number is being switched into the first slot
if($first == $number){
return 1; // error, can't switch with itself
} else if ($second == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE SECOND
// 2nd QUERY TO UPDATE THE DATA IN SECOND, WITH THE INFO STORED IN VARIABLE $temp
} else if ($third == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE THIRD
// 2nd QUERY TO UPDATE THE DATA IN THIRD, WITH THE INFO STORED IN VARIABLE $temp
} // ... continues to check for 4, 5, 6...
} else if($slot == 2){ /* Then checks to see if it was slot 2, i.e. Second */
// ....
} else if($slot == 3){ /* Then checks to see if it was slot 3, i.e. Third */
// ....
} else if($slot == 4){ /* Then checks to see if it was slot 4, i.e. Fourth */
// ....
} else if($slot == 5){ /* Then checks to see if it was slot 5, i.e. Fifth */
// ....
} else if($slot == 6){ /* Then checks to see if it was slot 6, i.e. Sixth */
// ....
}
}
It continues for each slot, , 6 times each... I know it's bad programming but I have just started learning PHP (it's my first language, so bear with me). Any suggestions on what I can do to make this cleaner? Or even a better way of writing it? If anyone cares to explain to me over Skype or anything, I would be really grateful. Thank you.
Use a switch statement:
if($switch == true){
switch($slot) {
case 1 :
if($first == $number){
return 1; // error, can't switch with itself
} else if ($second == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE SECOND
// 2nd QUERY TO UPDATE THE DATA IN SECOND, WITH THE INFO STORED IN VARIABLE $temp
} else if ($third == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE THIRD
// 2nd QUERY TO UPDATE THE DATA IN THIRD, WITH THE INFO STORED IN VARIABLE $temp
}
break;
case 2 :
// ....
break;
case 3 :
// ....
break;
case 4 :
// ....
break;
case 5 :
// ....
break;
case 6 :
// ....
break;
default:
// ...
}
}
You will notice a default at the bottom. It's always good to have one in place in case none of your conditions match.
Also notice the break keyword. Without it the code block does not stop at the end and will "fall through" to the next block. This can be handy sometimes but not in your case.
You could do something like this:
// This function returns the column name for the specified slot
function getSlotColumn($slotNum)
{
switch($slotNum)
{
case 1:
retrun "first";
case 2:
return "second";
......
}
}
then in the switching function
// This function swaps the values of the two specified slots
function swapValues($slot1Num, $slot2Num)
{
if($slot1Num == $slot2Num) return;
if($slot1Num < 1 || $slot1Num > 6) return;
if($slot2Num < 1 || $slot2Num > 6) return;
$slot1Col = getSlotColumn($slot1Num);
$slot2Col = getSlotColumn($slot2Num);
//get value of the first slot
$slot1Val = //SELECT $slot1Col FROM ... WHERE ... slot
// Now since we have the value of the first slot, we can update it from the second slot with this pseudo query
//UPDATE ... SET $slot1Col = $slot2Col WHERE ...
// Then update second slot from the value in $slot1Val
//UPDATE ... SET $slot2Col = $slot1Val WHERE ...
}
Then use it like this:
if(switch == true)
{
swapValues(1, 6);
}

Stop Fetching data from a database after some point

I want to fetch data from a database until a certain condition is satisfied. If this condition is satisfied I want to stop fetching after that point.
while($row=mysql_fetch_array($result1)){
$a1=$row['Count']
if($a1<100){
$w1=$a1
//Now I want to stop fetching data after this point and take the variable "$w1" out
}
You can use break:
while ($row = mysql_fetch_array($result1)) {
$a1 = $row['Count'];
if ($a1 < 100) {
$w1 = $a1;
break;
}
}
Or return it out of a function.
Best option is to give limits and where condition in your query
So that the query execution will be fast (You need to fetch less data).
Instead of fetching whole the data first and filtering it, Filter the data first and fetch it.
In your case : if you want to fetch first 100 records :
$sql = "SELECT * FROM table LIMIT 0,100";
And if you have any condition then,
$sql = "SELECT * FROM table WHERE field = '".$var."' LIMIT 0,100";
Use break; or better you can use limit & where condition in your query
while($row=mysql_fetch_array($result1))
{
$a1=$row['Count'];
if($a1<100)
{
$w1=$a1; break;
}
}

problems with infinite loop

function addAds($n) {
for ($i=0;$i<=$n;$i++) {
while($row=mysql_fetch_array(mysql_query("SELECT * FROM users"))) {
$aut[]=$row['name'];
}
$author=$aut[rand(0,mysql_num_rows(mysql_query("SELECT * FROM users")))];
$name="pavadinimas".rand(0,3600);
$rnd=rand(0,1);
if($rnd==0) {
$type="siulo";
} else {
$type="iesko";
}
$text="tekstas".md5("tekstas".rand(0,8000));
$time=time()-rand(3600,86400);
$catid=rand(1,9);
switch ($catid) {
case 1:
$subid=rand(1,8);
break;
case 2:
$subid=rand(9,16);
break;
case 3:
$subid=rand(17,24);
break;
case 4:
$subid=rand(25,32);
break;
case 5:
$subid=rand(33,41);
break;
case 6:
$subid=rand(42,49);
break;
case 7:
$subid=rand(50,56);
break;
case 8:
$subid=rand(57,64);
break;
case 9:
$subid=rand(65,70);
break;
}
mysql_query("INSERT INTO advert(author,name,type,text,time,catid,subid) VALUES('$author','$name','$type','$text','$time','$catid','$subid')") or die(mysql_error());
}
echo "$n adverts successfully added.";
}
The problem with this function, is that it never loads. As I noticed, my while loop causes it. If i comment it, everything is ok. It has to get random user from my db and set it to variable $author.
The problem is that the query is in the loop, so it gets run every time (so you start from the beginning every time). Just move the mysql_query() part to right before the while loop and store it in a variable:
$query = mysql_query("SELECT * FROM users");
while($row=mysql_fetch_array($query))
You can replace this mega switch with one line:
$subid = rand(($catid * 8) - 7, min($catid * 8, 70));
The condition of a while loop is executed and evaluated with each iteration. So mysql_query is called with every iteration and retunrs true.
Just execute your database query once and cache the result:
function addAds($n) {
$result = mysql_query("SELECT * FROM users");
$aut = array();
while ($row = mysql_fetch_array($result)) {
$aut[]=$row['name'];
}
$rowCount = count($aut);
for ($i=0; $i<=$n; $i++) {
$author=$aut[rand(0,$rowCount)];
// …
mysql_query("INSERT INTO advert(author,name,type,text,time,catid,subid) VALUES('$author','$name','$type','$text','$time','$catid','$subid')") or die(mysql_error());
}
echo "$n adverts successfully added.";
}
I also think the problem is your functions are way too big to understand(quickly). You should make them smaller and test them with a unit testing framework like phpunit.
It's a lot of time that I don't use PHP but I think that the assignment
$row=mysql_fetch_array(mysql_query("SELECT * FROM users"))
should always returns true, it executes the query again and again on every iteration..
You're starting a new query each time you run the loop.

Categories