php mysqli object search and sort - php

Using php 5.3 and mysqli I return a result set from a query that just has usernames, something like
$query_username = "SELECT username FROM some_table WHERE param = 1";
$username = $mysqliObject->query($query_username);
while($row_username = $username->fetch_object()){
print "<br>Username: $row_username->username";
}
All fine, but here is my problem, there are repeated usernames, and I don't know which names are going to be in the query before hand, could be bob, sue, james. Or it could be tom, dick, harry, tom. What I need to do is print out each username and how many times it shows up in this object. For very strange reasons I CANNOT use neat stuff like group by and count(*) in the query(don't ask it is truly weird). So my question is, what is the fastest way to loop through the returned object(or associative array if need be) to get each unique name and how many times it appears. Thanks for your help and I apologize if this is a freshman CS question, I'm self taught and always filling in the gaps!

If you really must do it on the PHP side instead of using a GROUP BY clause:
while($row_username = $username->fetch_object())
{
if(isset($usernames[$row_username['username']]))
{
$usernames[$row_username['username']]++;
}
else
{
$usernames[$row_username['username']] = 1;
}
}
asort($usernames);
// use ksort() to sort by username instead of the count
// print out the usernames
foreach($usernames as $username => $count)
{
echo $username . ", count: " . $count;
}

e.g.
$users = array();
while( false!==($row=$result->fetch_array()) ){
if ( isset($users[$row['username']]) ) {
$users[$row['username']] += 1;
}
else {
$users[$row['username']] = 1;
}
}
asort($users);

Related

PHP - Count how many results are displayed in foreach

With the foreach loop, I wanna count how many results are displayed. For example, if it's displaying
Jack Ane
Steve Jobs
Sara Bill
I want to echo that there are 3 results.
Likewise, if it's like
Marc Kil
Bill Smith
I want to echo that there are 2 results.
It's a bit tricky for me becasue this is my code:
<div>
<?php
$container = array();
if (is_array($row))
{
foreach ($row as $data) {
if(!isset($container[$data->first_name . $data->last_name])) {
$container[$data->first_name . $data->last_name] = $data;
echo $data->first_name . " " .$data->last_name . "</div>";
}
}
}
?>
</p>
</div>
How exactly would I be able to do that? Since these values are coming straight from the database, I was thinking of doing a database count but there are duplicate values in the database since I'm logging the views of users with the first and the last name. So when I try to do it, say for example there are 20 Jack Ane in my database. Then it shows me all of the 20 Jack Ane's instead of just one because I just want it once.
Sorry if it's confusing.
Thanks.
I traditional use the count() to do that if you dont use any :
foreach ($row as $data) {
if(!isset($container[$data->first_name . $data->last_name])) {
$container[$data->first_name . $data->last_name] = $data;
echo $data->first_name . " " .$data->last_name . "</div>";
}
}
echo "Results: " . count($row);
Hope that help you.
I suggest you to rewrite your query. If you will do this in right way, you will get faster solution, with no needs to new array and unnecessary "isset" checks.
The reason you get duplicated data from query may be:
1 - Wrong query logic
2 - Query is OK, but you need to use DISTINCT or GROUP BY to remove duplicates
If you use PDO, you can then get number of returned rows just by using rowCount() method
$sql="SELECT * from table WHERE blablabla";
$result = $this->db->query($sql);
$result->rowCount(); // here
Then you can fetch $result->fetchAll(); and print data.
You can to do a SELECT DISTINCT or a GROUP BY across the two columns to have the database do the work and eliminate the duplicate checking in your PHP. To do this you can use something like the following:
SELECT DISTINCT first_name, last_name FROM users;
SELECT first_name, last_name FROM users GROUP BY first_name, last_name;
DISTINCT is more succinct while GROUP BY supports more flexibility.
In your example, since you are building an associative array, you can just do a count() after the loop, but you will have cleaner code if you have the database do it:
$count = count($container);
You could do an easy variable that increments inside your foreach that gives you the exact count, then use the variable to create actions depending on it's value. Because if you count the container and you wish to filter out the results inside the container, you won't get the filtered amount.
<?php
$container = array();
if (is_array($row))
{
$count = 0;
foreach ($row as $data) {
if(!isset($container[$data->first_name . $data->last_name])) {
$container[$data->first_name . $data->last_name] = $data;
echo $data->first_name . " " .$data->last_name . "</div>";
$count++;
}
}
}
if ($count > 0) {
echo "There were $count results.";
}
?>
use:
echo "Results: " . count($container);

as of now it just ignores the if statement and gives them a ticket everytime.php, mysql, If else

Alright so i'm trying to put value in an array and shuffle them to be random, then have it use that random value in a query. I know my code is bad and not to use mysql anymore lets stay off that topic please.
I don't understand why this isn't working I have other things like it that work just fine.
right now it ignores the if statement and gives them a ticket each time.
if(isset($_POST['Submit'])) {
$ticket = array("0","0","0","0","0","0","0","1");
shuffle($ticket);
if ($ticket >= 1) {
echo "You have Found a Shop Ticket!" ;
mysql_query("UPDATE users SET ticket=ticket+1 WHERE username = '".$_SESSION['username']."'")
or die(mysql_error());
} else {
echo "";
}
}
You're checking if the entire array is >= 1, which is obviously TRUE all the time.
Pick a value instead:
$ticket = array_shift($ticket); // do this after you shuffle
try
if (current(shuffle($ticket)) >= 1) {
# yay
} else {
# ney
}
$ticket is an array, not a number.
u could use foreach or array_map to do this.
example:
function foo($n){
if($n >= 1){//do something}
}
$ticket = array("0","0","0","0","0","0","0","1");
shuffle($ticket);
array_map('foo', $ticket);

Storing mysql result in array (without echoing) and then using that array to set another variable

I've tried looking for a solution in other questions asked before (as always), but I can't seem to wrap my head around this.
See, I want to get a number of unique IDs (in random order) from one table and store them in an array without echoing them. Then I want to use that array variable in a loop, so that I can increment the key with every pass, and set another variable to that array variable. Confusing? I think looking at the code will make it more clear.
The problem is I can't seem to store the values that I've queried into an array for later use in the code. I pasted the pertinent part of the code with my spots of trouble indicated by comment /* */ tags.
Any help is appreciated.
<?php
include ('parse_functions.php');
if ($fetch['use_rand']=='yes')
{ $loop = 5;
$concept = $fetch['concept'];
$countRandom = "SELECT exID FROM examples WHERE concept='$concept' ORDER BY RAND()";
$askForRandom = mysql_query($countRandom) or die(mysql_error());
/* HERE I NEED TO STORE RANDOM KEYS (exID) INTO AN ARRAY */ }
else
{ if (!empty($fetch['ex5'])) { $loop = 5; }
elseif (!empty($fetch['ex4'])) { $loop = 4; }
elseif (!empty($fetch['ex3'])) { $loop = 3; }
elseif (!empty($fetch['ex2'])) { $loop = 2; }
elseif (!empty($fetch['ex1'])) { $loop = 1; }
else { $loop = 0; }
}
if ($loop!==0)
{
echo '<div id="examples">' . "\n";
echo '<table class="showExample" cellspacing="0" cellpadding="0" border="0" align="center">' . "\n";
$turns = 1;
do {
if ($fetch['use_rand']=='no')
{ $exID = $fetch['ex'.$turns.'']; }
else
{ $exID = /* THIS IS WHERE I WILL USE "RANDOM VARIABLE" */; }
$askExamples = "SELECT * FROM examples WHERE exID='$exID'";
$getExamples = mysql_query($askExamples) or die(mysql_error());
$sortExamples = mysql_fetch_assoc($getExamples);
echo '<tr>' . "\n";
// ...and so on
If all you need to do is store the info in an array, here's an easy way about it.
/* code
to open
db here
*/
/* assuming you have a value for $concept */
$countRandom = "SELECT exID FROM examples WHERE concept='$concept' ORDER BY RAND()";
$askForRandom = mysql_query($countRandom) or die(mysql_error());
$Element = 0; //Array elements start at ZERO. So this is to intialise it.
while ($Fields = mysql_fetch_array($askforRandom)) //As long as there are records, get them.
{
//Records are retrieved one at a time. So store each one's exID in the array element
$Data[$Element] = $Fields["exID"];
//Soon after storing one, increment the value of the $Element variable so it is ready for the next one.
$Element++
}
/* now you have the data in the array. So you can do what you like with it. */
hope it helps
NOTE: when reading the array, make sure you put the condition to check that your counter is LESS than $Element. This is because after reading the last record, $Element is incremented by one. Hope this is clear.
Why not just grab all the right information in one query from the start along the lines of something like this:
select
a.exID,
examples.someField,
examples.someOtherField
from
examples
join
(
SELECT
exID
FROM
examples
WHERE
concept='$concept'
ORDER BY
RAND()
limit 5
) a
on a.exID=examples.exID
Then you just just pop them into an array (or better yet object) that has all the pertinent information in one row each time.

How can I copy a database table to an array while accounting for skipped IDs?

I previously designed the website I'm working on so that I'd just query the database for the information I needed per-page, but after implementing a feature that required every cell from every table on every page (oh boy), I realized for optimization purposes I should combine it into a single large database query and throw each table into an array, thus cutting down on SQL calls.
The problem comes in where I want this array to include skipped IDs (primary key) in the database. I'll try and avoid having missing rows/IDs of course, but I won't be managing this data and I want the system to be smart enough to account for any problems like this.
My method starts off simple enough:
//Run query
$localityResult = mysql_query("SELECT id,name FROM localities");
$localityMax = mysql_fetch_array(mysql_query("SELECT max(id) FROM localities"));
$localityMax = $localityMax[0];
//Assign table to array
for ($i=1;$i<$localityMax+1;$i++)
{
$row = mysql_fetch_assoc($localityResult);
$localityData["id"][$i] = $row["id"];
$localityData["name"][$i] = $row["name"];
}
//Output
for ($i=1;$i<$localityMax+1;$i++)
{
echo $i.". ";
echo $localityData["id"][$i]." - ";
echo $localityData["name"][$i];
echo "<br />\n";
}
Two notes:
Yes, I should probably move that $localityMax check to a PHP loop.
I'm intentionally skipping the first array key.
The problem here is that any missed key in the database isn't accounted for, so it ends up outputting like this (sample table):
1 - Tok
2 - Juneau
3 - Anchorage
4 - Nashville
7 - Chattanooga
8 - Memphis
-
-
I want to write "Error" or NULL or something when the row isn't found, then continue on without interrupting things. I've found I can check if $i is less than $row[$i] to see if the row was skipped, but I'm not sure how to correct it at that point.
I can provide more information or a sample database dump if needed. I've just been stuck on this problem for hours and hours, nothing I've tried is working. I would really appreciate your assistance, and general feedback if I'm making any terrible mistakes. Thank you!
Edit: I've solved it! First, iterate through the array to set a NULL value or "Error" message. Then, in the assignations, set $i to $row["id"] right after the mysql_fetch_assoc() call. The full code looks like this:
//Run query
$localityResult = mysql_query("SELECT id,name FROM localities");
$localityMax = mysql_fetch_array(mysql_query("SELECT max(id) FROM localities"));
$localityMax = $localityMax[0];
//Reset
for ($i=1;$i<$localityMax+1;$i++)
{
$localityData["id"][$i] = NULL;
$localityData["name"][$i] = "Error";
}
//Assign table to array
for ($i=1;$i<$localityMax+1;$i++)
{
$row = mysql_fetch_assoc($localityResult);
$i = $row["id"];
$localityData["id"][$i] = $row["id"];
$localityData["name"][$i] = $row["name"];
}
//Output
for ($i=1;$i<$localityMax+1;$i++)
{
echo $i.". ";
echo $localityData["id"][$i]." - ";
echo $localityData["name"][$i];
echo "<br />\n";
}
Thanks for the help all!
Primary keys must be unique in MySQL, so you would get a maximum of one possible blank ID since MySQL would not allow duplicate data to be inserted.
If you were working with a column that is not a primary or unique key, your query would need to be the only thing that would change:
SELECT id, name FROM localities WHERE id != "";
or
SELECT id, name FROM localities WHERE NOT ISNULL(id);
EDIT: Created a new answer based on clarification from OP.
If you have a numeric sequence that you want to keep unbroken, and there may be missing rows from the database table, you can use the following (simple) code to give you what you need. Using the same method, your $i = ... could actually be set to the first ID in the sequence from the DB if you don't want to start at ID: 1.
$result = mysql_query('SELECT id, name FROM localities ORDER BY id');
$data = array();
while ($row = mysql_fetch_assoc($result)) {
$data[(int) $row['id']] = array(
'id' => $row['id'],
'name' => $row['name'],
);
}
// This saves a query to the database and a second for loop.
end($data); // move the internal pointer to the end of the array
$max = key($data); // fetch the key of the item the internal pointer is set to
for ($i = 1; $i < $max + 1; $i++) {
if (!isset($data[$i])) {
$data[$i] = array(
'id' => NULL,
'name' => 'Erorr: Missing',
);
}
echo "$i. {$data[$id]['id']} - {$data[$id]['name']}<br />\n";
}
After you've gotten your $localityResult, you could put all of the id's in an array, then before you echo $localityDataStuff, check to see
if(in_array($i, $your_locality_id_array)) {
// do your echoing
} else {
// echo your not found message
}
To make $your_locality_id_array:
$locality_id_array = array();
foreach($localityResult as $locality) {
$locality_id_array[] = $locality['id'];
}

How to make a "distinct" detection on a foreach loop

At this time I have this very complex query that I loop through and I get something like this:
List of Challenges:
TEAM A
- Challenge 1
TEAM A
- Challenge 4
TEAM A
- Challege 6
And I want to change to something like:
TEAM A
- Challenge 1
- Challenge 4
- Challenge 6
My question is, since the query is a very complex one, maybe I could do this inside the loop but, if that's the case, how can we achieve something like that?
Can I ask an example case so that I can use, in order to solve this issue?
Thanks a lot,
MEM
UPDATE:
The query is something like this:
Translated:
public function listachallengesPendentes()
{
$select = $this->getAdapter()->select();
$select->from(array("e"=>"teams"),array('name'));
$select->join(array("de"=>"challengeperteam"),"e.cod_team = de.cod_teamFk",array());
$select->join(array("d"=>"challenges"),"d.cod_challenge = de.cod_challengeFk",array('title'));
$select->columns(array("e.cod_team"
,"name_team"=>"e.name"
,"d.cod_challenge"
,"name_challenge"=>"d.title"
,"d.details"
,"d.score"
,"category"=>"d.cod_categoryFk"
,"de.proof"
,"de.date_concluded"
,"de.cod_challenge_team"
));
$select->where("de.status = 0");
$select->order(array('e.cod_team DESC', 'de.cod_challenge_team DESC'));
return $this->getAdapter()->fetchAll($select);
}
So I need to add a distinct some part :s :D ?
The foreach actually is pretty basic:
foreach ($challenges as $d){
//display the name:
echo $d['name_team'];
...
}
UPDATE 2
The clean query (not tested):
SELECT e.name
,d.cod_team
,d.cod_challenge
,d.title
,d.details
,d.score
,de.proof
,de.date_concluded
,de.cod_challenge_team
FROM teams e
INNER JOIN challengeperteam de ON de.cod_teamFk = e.cod_team
INNER JOIN challenges d ON d.cod_challenge = de.cod_challengeFk
WHERE de.status = 0
ORDER BY e.cod_team DESC, de.cod_challenge_team DESC;
Something along the lines of:
$current_team = null;
foreach($challenges as $challenge){
if($current_team != $challenge->team){
$current_team = $challenge->team;
echo $current_team, "\n";
}
echo $challenge->challenge_name, "\n";
}
At a very basic level, ie in the loop, you can just detect if the TEAM A variable is equal to the current (previous) value, and if so, don't print it a second time. This relies on the result set being sorted on the TEAM A column.
However, you can also do this in the SQL query, so if you can provide the current SQL Query, I can explain how you'd update it.
you could store the array results in a multi-dimensional array like so:
$query_Challenges = "SELECT `Team`,`Challenges` FROM YourTable";
$Challenges = mysql_query($query_Challenges, $dbconnection) or die(mysql_error());
$row_Challenges = mysql_fetch_assoc($Challenges);
$challengeResults = array();
do{
if(!array_key_exists($row_Challenges['cod_team'])){
$challengeResults[$row_Challenges['cod_team']] = array();
}
$challengeResults[$row_Challenges['cod_team']][] = $row_Challenges['cod_challenge_team'];
}while($row_Challenges = mysql_fetch_assoc($Challenges));
EDIT
looking at your query statement, the data should be already sorted properly by your ORDER clause, so if you just need not repeatedly print the team as shown in codeblock 2, then something like:
$team = '';
do {
if($team != $row_Challenges['cod_team']){
echo "TEAM $row_Challenges['cod_team']<br/>";
$team = $row_Challenges['cod_team'];
}
echo " - $row_Challenges['cod_challenge_team']<br />";
}while($row_Challenges = mysql_fetch_assoc($Challenges));
you could easily substitute a foreach for the do loop, as long as there is a variable used as the "current team" and an if statement used to say "dont print the next team name unless its different than the current team name"

Categories