While inside a while - php

I'm trying to count how many times a hashtag is mentioned in the database. So first while is getting all the hashtags, and the second is inside the other while to count how many times the hashtag is mentioned. But the problem is that the numbers isn't getting along correct, it is just showing 1,2,3,4,5.. etc, and when there is a hashtag mentioned two times it's showing i.e. 3+4.
How can I solve this?
$i = 0;
$popular_hashtags_query = mysql_query("SELECT * FROM " . $dbPrefix . "hashtags WHERE status=1");
while ($popular_hashtags = mysql_fetch_array($popular_hashtags_query)) {
echo "<div class='hashtag_label'><a data-hover='";
$count_hashtags_query = mysql_query("SELECT * FROM " . $dbPrefix . "hashtags WHERE status=1 AND hashtag='" . $popular_hashtags['hashtag'] . "'");
while ($count_hashtags = mysql_fetch_array($count_hashtags_query)) {
$i++;
echo $i;
}
echo "'><span>#".$popular_hashtags['hashtag'] . "</span></a></div>";
}

I suggest to use mysqli or PDO. in this case group by hashtag in the query is better way and not need to extra query and loop so.
$popular_hashtags_query = mysql_query("
SELECT
`hashtag`, count(*) AS `count`
FROM `" . $dbPrefix . "hashtags` WHERE `status` = 1 GROUP BY `hashtag`
");
while ($popular_hashtags = mysql_fetch_array($popular_hashtags_query)) {
echo "<div class='hashtag_label'><a data-hover='";
echo $popular_hashtags['count'];
echo "'><span>#" . $popular_hashtags['hashtag'] . "</span></a></div>";
}

There are a bunch of problems with your code. First, the mysql_ functions are deprecated and will eventually be removed from php entirely, so you should move over to mysqli_ functions or a PDO.
Second, your actions on $i are in the wrong place. You should be resetting $i = 0 as the first action inside the first loop, or else it's just going to count up the total number of times ANY hashtag is used.
Third, you're echoing $i inside the second while loop, which means every time the loop runs, you're going to be forever echoing increasing numbers. The echo should be outside the inner loop, after you've counted up the instances of the hashtag.
And finally, you can actually accomplish all of this with one loop by executing "SELECT hashtag, count(*) FROM " . $dbPrefix . "hashtags WHERE status=1 group by hashtag"

There's no need to loop over all records in a table to do the same thing again.
What you want is to use an aggregate function in you SQL query.
Something like the following:
SELECT hashtag, COUNT(hashtag)
FROM hashtags
GROUP BY hashtag

Related

Getting Count on Number of Instances in Array (subtracting after continue; statement in loop)

I have a 'Pricing History Table' based off MySQL table.
Because we have a lot of alike listings, a lot of these entries appear as duplicates, aside from of course the ItemID.
Here's how I'm currently weeding out duplicates (not really duplicates, but similar listings that have the same SKUs, Y-m-d Date, Previous Price, New Price and Sales Channels. -- and also trying to get a count (see $count logic below) of how many alike/"duplicate" rows were found)
$inventoryhistoryrows = array();
$skuarray = array();
foreach ($pricehistoryarray as $ph_key => $ph_values) {
// defining variables, etc.
. . . . .
$ph_sku_timestamp = $inventoryskus . ' ' . $ph_timestamp . ' ' . $ph_previousprice . ' ' . $ph_newprice . ' ' . $ph_channel;
if (in_array($ph_sku_timestamp, $skuarray)) { continue; }
$skuarray[] = $ph_sku_timestamp;
if(isset($prev)) {
$newcount = $count - $prev;
$prev = $count;
}
else {
$prev = $count;
$newcount = $count;
}
$inventoryhistoryrows[] = array($newcount, $ph_itemid, $inventoryskus, $ph_previousprice, $ph_newprice, $ph_channel, $ph_timestamp);
This is working.... but my $newcount is always one row ahead!
Here's an illustration of output in table:
Note the arrows on the far left side. The $newcount variables are correct but the entire first column needs to moved up by one row.
Meaning, 1 should be removed from the first row. 3 Should be in the first row. 17 Should be in the second row.
I can of course see that the reason why 1 is showing up in the first row is due to this statement
else {
$newcount = $count;
}
Meaning it will always return 1 for the first row, as prev does not exist. But I simply put this there as I was unsure of a proper way to get the data as I wanted.
Anyone have any ideas on how I can do this? In the initial foreach loop for $pricehistoryarray (I suppose this would be the better solution), or a relatively simply method for shifting up only the first column once the $inventoryhistoryrows array is constructed?
Apparently this might be better off in the MySQL Query (see comments)
This seems to be working
SELECT COUNT(*) as count
, itemid
, previousprice
, newprice
, channel
, timestamp
FROM listing_price_history
WHERE listing_price_history.timestamp > DATE_SUB(now(), INTERVAL 30 DAY)
GROUP
BY previousprice
, newprice
, channel
, DATE(timestamp)
ORDER
BY listing_price_history.timestamp DESC
Big thanks to #Cid for the guidance

Looping user based filters to pull out products MYSQL

Currently, i have a system set that displays products from a database based on what filters are set in a control panel.
It loops like this:
1. Begin loop
2. Pick Filter
3. Search product database for product matching the filter AND search term
4. Return a table row of products matching these terms
5. End Loop
This works fine except for the load times. Because it has to loop through all the products for each filter with search term the time involved only gets higher with each filter added on the back end.
My question: Is there a smaller way to write in say.. any array of the filters into one mysql statement? like this:
SELECT FROM products Where A line matches one of the array of filters AND search term?
The other reason i need this is because currently it's pullin gout duplicate product rows. While i've nastily hidden the doubles with javascript, it's not exactly good to keep it like this.
Currently, this is the code being used. If anyone can offer any suggestions as to how the best way to do this is, i'm all ears.
//connect and fetch all entries from the filter table
$filterproducts = $dbh->prepare("SELECT * FROM table_filter_selection ORDER BY filter ASC");
$filterproducts->execute();
$filterselect = $filterproducts->fetchAll();
//for each entry found loop through a second loop
foreach($filterselect as $rows){
$wildcard = "%" . $rows['filter'] . "%";
//make a variable into a regex of the row
$query = "PRODUCT_NAME LIKE '%" . implode("%' AND PRODUCT_NAME LIKE '%", $breakdown) . "%'";
$sqlstring= "SELECT * FROM product_list WHERE PRODUCT_NAME LIKE :filterfind AND " . $query;
$searchproducts = $dbh->prepare($sqlstring);
$searchproducts->bindParam(":filterfind", $wildcard, PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$searchproducts->execute();
//search for all products that match the wildcard AND the current filter
foreach($searchproducts as $rows2){
//for every one found, make a row.
echo "<tr><td>" . $rows2['SKU'] ." <strong style='font-style: italic;'>". $rows2['COMMENTS'] . "</strong><td/><td>". $rows2['PRODUCT_NAME'] ."</td><td>". $rows2['QTY'] . "</td></tr>";
}
}
I have editted to include a very quick mock-up of the code I'm using.
save the filters in an array. then use a loop to make a sql stament. like this:
$query= "SELECT * FROM products ";
$filters= 'Where '; //Sets a varible for fileters.
foreach($filters as $key=$value) //Loop threw each filter
{
$filters.= $key . '= ' . $value . 'AND ';
}
rtrim('AND '); //Remove extra 'AND' from end of filters string
$query.= $filters;
Now you will have to adjust the code depending on how your filters a stored. and the rtrim() may need tweeking.

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);

Displaying a multi-table mysql query

This is going to be really hard to explain but I'll attempt to do my best without confusing you all. I have the following table design;
Here is my mysqlFiddle to demonstrate the issue: http://sqlfiddle.com/#!2/1363c/1
As you can see, the tables work fine and the query is displaying what shelter has what service but my issue comes when I attempt to display this information on my web. I'm currently using the following code;
<?php
echo '<p>', "<strong>Shelter id</strong>: " . $query['shelter_id'].'</p>';
echo '<p>', "<strong>Shelter name</strong>: " . $query['shelter_name'].'</p>';
echo '<p>', "<strong>Street</strong>: " . $query['street'].'</p>';
echo '<p>', "<strong>City</strong>: " . $query['city'].'</p>';
echo '<p>', "<strong>Postcode</strong>: " . $query['postcode'].'</p>';
echo '<p>', "<strong>Contact Number</strong>: " . $query['phone_number'].'</p>';
echo '<p>', "<strong>Location</strong> : " . $query['location_name'].'</p>';
?>
but with the query I'm using, Its not going going to dupe all the information into one row it is, its going to create multiple row's for the service_name, I think.
Is it possible for me to create a query that will return all service's the shelter can do on one row?
Edit: Will i have to do 2 separate query's? One to get the generic shelter information and then another query to return the services into an array and then just run through them on the page?
how about using GROUP_CONCAT? What it does is it combines the values into comma separated value. And you can later use Explode() in PHP.
SELECT shelter_name,
GROUP_CONCAT(services.service_name) service_name
FROM shelter
INNER JOIN shelter_service
ON shelter.shelter_id= shelter_service.shelter_id
INNER JOIN services
ON shelter_service.service_id = services.service_id
GROUP BY shelter.shelter_id, shelter_name
ORDER BY shelter_name
SQLFiddle Demo
GROUP_CONCAT() use only if you have a limited number of rows (10-100), if the data is larger will slow your query a lot.
2 queries (one for types one for data)
keep this query and modify the result (my favorite way).
On server or JS loop trough your data and restructure it (add 1 extra dimension)
var new_data = {};
for(var i in data)//data is your $query
{
var row = data[i];
//create another layer of the array (make it in 2 dimensions)
if (typeof(new_data[row['Service_name']) == 'undefined)
new_data['Service_name'] = [];
//add only this kind of type data
new_data['Service_name'].push(data);
}
//now you can remove the data and use new_data
.4. Make sure the query is primarly sorted by Service name, and when you loop at display (echo) you show the current service name.
$current_name = '';
for(...)
//if we passed to a new service in the loop
if ($query['service_name'] != $current_name) {
echo '<h3>'.$query['service_name'].'</h3>;//display the new service
$current_name = $query['service_name'];
}

Sql query only printing first row

I am coding in php and the code takes data from an array to fetch additional data from a mysql db. Because I need data from two different tables, I use nested while loops. But the code below always only prints out (echo "a: " . $data3[2]; or echo "b: " . $data3[2];) one time:
foreach($stuff as $key)
{
$query3 = "SELECT * FROM foobar WHERE id='$key'";
$result3 = MySQL_query($query3, $link_id);
while ($data3 = mysql_fetch_array($result3))
{
$query4 = "SELECT * FROM foobar_img WHERE id='$data3[0]'";
$result4 = MySQL_query($query4, $link_id);
while ($data4 = mysql_fetch_array($result4))
{
$x += 1;
if ($x % 3 == 0)
{
echo "a: " . $data3[2];
}
else
{
echo "b: " . $data3[2];
}
}
}
}
First and foremost, improve your SQL:
SELECT
img.*
FROM
foobar foo
INNER JOIN foobar_img img ON
foo.id = img.id
WHERE
foo.id = $key
You will only have to iterate through one array.
Also, it appears that you're actually only selecting one row, so spitting out one row is expected behavior.
Additionally, please prevent yourself from SQL injection by using mysql_real_escape_string():
$query3 = "SELECT * FROM foobar WHERE id='" .
mysql_real_escape_string($key) . "'";
Update: As Dan as intimated, please run this query in your MySQL console to get the result set back, so you know what you're playing with. When you limit the query to one ID, you're probably only pulling back one row. That being said, I have no idea how many $keys are in $stuff, but if it spins over once, then it will be one.
You may be better off iterating through $stuff and building out an IN clause for your SQL:
$key_array = "";
foreach($stuff as $key)
{
$key_array .= ",'" . mysql_real_escape_string($key) . "'";
}
$key_array = substr($key_array, 1);
...
WHERE foo.id IN ($key_array)
This will give you a result set with your complete list back, instead of sending a bunch of SELECT queries to the DB. Be kind to your DB and please use set-based operations when possible. MySQL will appreciate it.
I will also point out that it appears as if you're using text primary keys. Integer, incremental keys work best as PK's, and I highly suggest you use them!
You should use a JOIN between these two tables. It the correct way to use SQL, and it will work much faster. Doing an extra query inside the loop is bad practice, like putting loop-invariant code inside a loop.

Categories