I have the following SQL statement:
$query = "SELECT item, COUNT(*) as number FROM shop GROUP BY item";
This will give me the following result:
item number
item1 23
item2 15
item3 4
I want to use this to make menu items, so normally the menu would look:
item1
item2
item3
But I want to do a check if an item has less than 10 records, that I don't want to display this item.
So in this example, the menu would be like:
item1
item2
Any idea how to achieve this?
I would like to do this in PHP because I need all the items in the query but will only want to show them which are greater then 10 and need the other items later on.
If you want to do this in PHP then you can do like this
function filterArray($value){
return ($value.number > 10);
}
$filteredArray = array_filter($yourDBArray, 'filterArray');
foreach($filteredArray as $k => $v){
//your desired array
}
In terms of speed Mysql option is good as suggested above.
Just change your query from
SELECT item, COUNT(*) as number FROM shop GROUP BY item
to
SELECT item, COUNT(*) as number FROM shop GROUP BY item HAVING number>=10
As you really need to perform this in PHP you could use array_filter() which, using a closure, will remove items which number is less than 10:
$more_than_ten = array_filter($items, function ($i) { return $i['number'] >= 10; });
Doing it with SQL would be a better solution (about performances). In case you'd need it, you could use the HAVING clause (you can't perform a WHERE number >= 10):
SELECT
item,
COUNT(*) as number
FROM shop
GROUP BY item
HAVING number >= 10
I noticed php is tagged. For the sake of options, here's how I'd go about separating the unneeded data in php if you were to get it from the database as-is:
foreach ($data as $item) {
$num = (int) $item['number']; // force of habit
if ($num >= 10) {
// display it
}
}
I'd probably separate the data at the database step, but this works if it's the route you want to take.
There is two options to filter the data so only the rows with more then 10 will appear.
At the SQL query
__
SELECT item, COUNT(*) as number FROM shop GROUP BY item HAVING number > 9
This will cause you to recieve only the requested rows from the database
Filter with PHP - every time you want to print the menu or testing it out, just can the value of 'number' in the array reutrned from the query. You can also allocate new array and insert all the values that contains 'number' that bigger then 10.
Related
I am writing some code to supply the Google certified shop data which I have nearly finished. I only need to supply the ship and delivery dates. I have written code to supply this information at the product level. However when there is more than one product in an order I need to select the largest ship date.
For example;
Order has two products.
Producta with $ship_date = 2 and porductb with $ship_date = 5
I need to collect all the $ship_dates (2 and 5) and return the highest one (5).
My question is simply how do I write the php to collect all the $ship_dates correctly - should I create an array and if so how?
Put all the required variables into an array, then use max.
$ship_date1 = 2;
$ship_date2 = 5;
$shipDates = [$ship_date1, $ship_date2];
// other dates as needed
// OR, a much cleaner solution, append to the array
$shipDates = [];
$shipDates[] = 2;
$shipDates[] = 5;
//No matter how you fill up the array, this is how you get its maximum value
$maxShipDate = max($shipDates);
max actually accepts individual variables instead (eg. max($ship_date1, $ship_date2);) but the array solution is easier to maintain.
OK before my foreach product loop I added this;
$deliverydatearray = array();
which creates a new (empty) array which I called $deliverydatearray
Within my foreach product loop I added this;
$deliverydatearray[] = $delivery_datep;
which adds my product specific delivery date ($delivery_datep) to my array.
After the foreach product loop has closed I can access the variables in my array. For example just printing the contents of the array is done like this;
print_r($deliverydatearray);
which looks like this;
Array
(
[0] => 2017-01-28
[1] => 2017-01-23
)
NOTE:
I'm new to php and mysql.
Background info:
I have +/- 30,000 products and they are from 7 different supplier and they have a lot of the same products
let's say i have 1 product and three of the suppliers have the it, i need to publish the product with the lowest price and the other two product stay unpublished
that is the basic idea and this must run through the 30,000 products and check and see if there are any matches and run the publishing function
SQL setup:
There are two tables xxxx_virtuemart_product and xxxx_virtuemart_product_prices
There are three rows in xxxx_virtuemart_product ▬▬▬ product_id,product_sku,published ▬▬▬
There are two rows in xxxx_virtuemart_product_prices ▬▬▬ product_id,product_price ▬▬▬
My little bit of code:
I have this little code because i'm stuck, how can i make a check to see if there are any matches and then run a query to change the published value of the product with the lowest price?
i know there is a way to use the query to check for matches, but do not understand how to do is
$query = "SELECT `product_sku` FROM `xxxx_virtuemart_product`";
$query_run = mysql_query($query) or die (mysql_error());
while($row = mysql_fetch_assoc($query_run)){
foreach ($row as $key => $ps){
}
}
The below code is to check the price (not query optimize just a rough draft)
$z = //products price;
$x = //products price;
$c = //products price;
if ($z >= $x && $c >= $x) {
//the this products published value to 1
}else if ($x >= $z && $c >= $z) {
//the this products published value to 1
}else if ($z >= $c && $x >= $c) {
//the this products published value to 1
}
Can anyone please help me with this?
Thanks for reading
any questions are welcome.
Your problem is not about to compare arrays but more algorithm.
I will try this way.
1)SQL query to retrieve all the products : sql_products
2)construct a hashmap those key is product SKU (see : PHP Array)
To construct PHP hashmap : use arrays of arrays.
Example :
product_map[] = array();
foreach sql_product of sql_products :
- product_map[sql_product[SKU]][] = array(sql_product[supplier], sql_product[price], sql_product[information])
end of loop
Then loop again over the map of products constructed and sort each product record by price : that means you have to write a function to sort array (supplier, price, information).
Now you have a map of product : SKU => array(of array (supplier, price, information))
I've got a website on which I want to display items. These items are stored in a database in the following format:
ID Item Active
1 My item 0
2 My item 1
7 My item 1
8 My item 1
10 My item 0
Note here that the IDs are not necessarily evenly spaced. Each item is either active(1) or inactive(0). I want 3 items to be active at a time and every time my script is called I want the next item to become active and the oldest item to become inactive like so:
ID Item Active
1 My item 0
2 My item 0
7 My item 1
8 My item 1
10 My item 1
and so:
ID Item Active
1 My item 1
2 My item 0
7 My item 0
8 My item 1
10 My item 1
I'm currently struggling with the algorithm to consider the third case above. I can't just pick the highest ID that's active and move to the next item and set that active and at the same time pick the lowest one that's active and make it inactive.
Here's my code so far:
{
for ($i=0;$i<sizeof($videos);$i++)
{
echo $i."]";
if ($videos[$i]->active == 1)
{
if (!isset($first_active))
{
echo "mooh";
echo "[";
echo $first_active = $i;
echo "]";
}
if ( ($i < (sizeof($videos)-1)) && ($videos[$i+1]->active == 0) )
{
$videos[$i+1]->active = 1;
$videos[$i+1]->update();
echo "#".$first_active."|".$videos[$first_active]->id()."#";
$videos[$first_active]->active = 0;
$videos[$first_active]->update();
$first_active = null;
echo "|".$videos[$i+1]->id();
break;
}
elseif ($i == (sizeof($videos)-1))
{
$videos[0]->active = 1;
$videos[0]->update();
$videos[$first_active]->active = 0;
$videos[$first_active]->update();
$first_active = null;
echo "|".$videos[0]->id();
break;
}
}
}
}
This works until I get to the end, e.g. ID 10. It then correctly makes ID 1 active. In the next call, it makes ID 7 active and ID 1 inactive.
Any idea how I can 1) fix my code, 2) tackle this problem smarter?
Sounds to me like you actually need to store the last activation date instead of a simple on/off flag.
You can use two database queries, one to get the full list in order of ID, and another that specifically only gets the first 3 entries sorted by active date. Loop through your full list to get all the entries in order, then test the ID of each one with the ID of your 3 active to test if it is currently active. Then, setting a new item active is as simple as just updating the date/time of the active column on the item you want.
If you really want to keep the active on/off flag, then do so, just make another column with a last active date/time.
Current situation
I have two tables in my database, one for posts, and one for ratings. These are linked with a relation in the MySQL so that one post may have 0, 1 or multiple ratings, but one rating can only be applied to one post.
When I fetch a list of posts, I also want to get ratings, but without having to make a separate call to the database for each post in the foreach loop.
To do this I have attempted to use an SQL query to fetch all posts with a LEFT JOIN on ratings so that it will return a result like this:
statusId|statusBody|rating
-----------------------------
1, post1, 0
1, post1, 1
2, post2, 0
3, post3, 1
3, post3, 1
The SQL works fine, and I get the data I ask for.
Ideally what I am trying to achieve now is to turn this table into a collection of objects, with each object storing the post information as well as a value depending on it's total ratings.
After using PDO to return the data result, this is the code I am using to map the data:
Code Logic
The logic of my code goes like this:
Get all statuses joined with ratings table
Create empty output array
Loop through PDO result
{
Create loop specific temp array
Push first row of result into temp array
Remove row from PDO result
Loop through PDO result for objects with matching statusId
{
If row matches statusId, add to temp buffer and remove from PDO result
}
Take first row of buffer and create status object
Loop through objects in temp array to calculate ratings and add onto above status object
Clear temp buffer
Add status object to output array
}
return output array
Actual Code
try
{
$result = $pdo->query($sql);
//if($result == false) return false;
$statuses = $result->fetchAll(PDO::FETCH_CLASS, 'status');
}
catch (PDOException $e)
{
return FALSE;
}
if (!$result) {
return FALSE;
}
//create empty output array to be filled up
$status_output = array();
//loop through all status
foreach($statuses as $s1key => $s1value)
{
//initialise temporary array;
$status_temp_buffer = array();
//create temp array for storing status with same ID in and add first row
array_push($status_temp_buffer, $s1value);
//remove from primary array
unset($statuses[$s1key]);
//loop through array for matching entries
foreach($statuses as $s2key => $s2value)
{
//if statusId matches original, add to array;
if($s2value->statusId == $s1value->statusId)
{
//add status to temp array
array_push($status_temp_buffer, $s2value);
//remove from primary array
unset($statuses[$s2key]);
}
//stop foreach if statusId can no longer be found
break;
}
//create new status object from data;
$statObj = $status_temp_buffer[0];
//loop through temp array to get all ratings
foreach($status_temp_buffer as $sr)
{
//check if status has a rating
if($sr->rating != NULL)
{
//if rating is positive...
if($sr->rating == 1)
{
//add one point to positive ratings
$statObj->totalPositiveRatings++;
}
//regardless add one point to total ratings
$statObj->totalAllRatings++;
}
}
//clear temporary array
$status_temp_buffer = NULL;
//add object to output array
array_push($status_output, $statObj);
}
Problem
The problem I am coming up against with this code is that although the ratings are fine, and it correctly calculates the ratings total for each post, it still shows duplicates where a post has more than one rating.
Any help with this would be greatly appreciated,
Thanks
As i understood it, the goal is to get the total rating of each Post entry. Instead of manually looping over each and every rating, there are two other path you could take:
compute the total in the query:
SELECT SUM(rating) AS total , .. FROM Posts LEFT JOIN .... GROUP BY statusID
You will receive a list of Post entries, each already with total rating calculated. This is a very good solution if you have a lot of writes to to the Ratings table, and much less reads.
the other way is to break the table normalization, but to increase read performance. What you would have to do is to add another column in the Posts table: total_rating. And have an TRIGGER on INSERT in the Ratings table, which changes the Posts.total_rating accordingly.
This way has a benefit of simplifying the request of Posts. At the same time Ratings table can now be use to ensure that total_rating has been calculated correctly, or to recalculate the value, if there are some large changes in the ratings: like banning of user, which results in removing all ratings made by this user.
... It's not as silly as it sounds...
I have the following code, which is used by my ajax table script to display database stuff on the page in a table.
foreach($ct->data as $key => $value){
$ct->data[$key][2]=''.$ct->data[$key][2].'';
$ct->data[$key][3]=''.$ct->data[$key][3].'';
if($ct->data[$key][4] == "" || $ct->data[$key][4] == null)
$ct->data[$key][4]='Edit Charge.';
else
$ct->data[$key][4]=''.$ct->data[$key][4].'';
$Total =$Total+ $ct->data[$key][3];
$freight =$freight+ $ct->data[$key][4];
}
And as you can see, in the foreach loop, I am trying to add up the contents of 2 columns.
The $Total column or, $ct->data[$key][3] lists the Prices for each row of products, and the $freight column does the same for each row of Freight charges.
And inside the foreach loop, I am trying to add together the total amount of prices, and Freight charges.
I'm not sure if I'm doing it the right way, because when I check the database, it just adds '0' (without the quotes). So it's not adding up!
For example, if there are a total of 3 rows in the table, and each product is 1 (dollar), it should add up to 3, right? And same goes for the $freight ones.
Can someone please tell me what I'm doing wrong here?
You are setting data[$key][3] equal to some HTML hyper link. Its not something that can be "totalled"
Is line 3 not setting the value you're adding to $Total to a string?
$ct->data[$key][3]=''.$ct->data[$key][3].'';
and then
$Total =$Total+ $ct->data[$key][3];
If you remove the first one, the second might work better.