Finding nearest value in a mysqli array php - php

In my app, the user can enter a number for pricing and based on the input, the database will return a plan with the same price. If there is no number/price corresponding to the user input, I would like the program to find the plan with the nearest value. How can I find the "nearest" value in a haystack?
Examples :
User inputs : $14, Returns the 15$ plan
User inputs : $20, Returns the 15$ plan
User inputs : 25$. Returns the 30$ plan
Etc...
This is what I have :
//Create pricing for each plan
$getplansql = "SELECT SUM(`Distributor Net Price`) AS dnetprice FROM `services` wspn
WHERE wspn.planName = '$planname_num[$pn]' AND wspn.planLevel = '$planlevels_num[$pl]'";
$resultplans = $conn->query($getplansql);
while($plan = mysqli_fetch_assoc($resultplans)) {// output data of each row
$inhousepricing = ($plan['dnetprice'] * 0.15) + ($plan['dnetprice']);
$finalpricing = round($inhousepricing);
if($planprice == $finalpricing) {//found matching row// there's a plan with that price
//put plan info in array
$planArray = array(
'planName' => $plan['name'],
'planPrice' => $finalpricing,
'planDescription' => $plan['description']
);
break;//stop statement and only get the first plan//row found
}else{//get the plan with the nearest value
//put plan info in array
}

Add 15% and find the closest price in the SQL query itself.
$getplansql = "name, description, dnetprice
FROM (
SELECT planName AS name, planDescription AS description, ROUND(SUM(`Distributor Net Price`) * 1.15) AS dnetprice
FROM `services` wspn
WHERE wspn.planName = '$planname_num[$pn]' AND wspn.planLevel = '$planlevels_num[$pl]'
) AS x
ORDER BY ABS(dnetprice - $planprice)
LIMIT 1";
$resultplans = $conn->query($getplansql);
$planArray = mysqli_fetch_assoc($resultplans);
This will just return the one row that you want, so you don't need a while loop.

Related

Sorting a NON-SQL table column in a table containing data from SQL query

Below I have stripped down my code to a simplified version. I am storing SQL SELECT results for:
last name (dlname)
category (category)
date this data was added to database (date_added)
clients name (client)
I have appended an additional field outside the SQL SELECT called 'days_on_list'. This field shows the number of days since the data was added to the database, making the table output 5 columns of user data. ALL 5 COLUMNS ARE TO BE SORTABLE.
I am using server-side JSON and have successfully been able to display this to the table and perform sorting on 4 of the 5 columns. The problem is that I am unable to sort the 'days_on_list' field as the PHP file containing the SQL code only allows me to sort the 4 fields from the select query. Is there a way I can make 'days_on_list' column be sortable in the table? I know I can add this field to the sql table, but I would have to run a scheduled event on the server to update this daily (which I am not comfortable with).
Is there another way to allow for this kind of flexible table sorting?
Sorry about the question title (may be confusing), I was having trouble putting this into a question.
/*SQL CODE ABOVE HERE STORES SELECT RETURNS IN $result*/
$cart = array();
$i = 0; //index the entries
// get variables from sql result.
if ($num_rows > 0) { //if table is populated...
while ($row = mysqli_fetch_assoc($result)) {
//calculate days on list by getting the number of days from
//the 'date_added' to today
$date1 = date_create($row['date_added']);
$today = date_create(date("d-m-Y"));
$interval = date_diff($date1, $today);
$doty = $interval - > format("%a");
$cart[$i] = array(
"dlname" => htmlspecialchars($row['dlname']),
"category" => htmlspecialchars($row['category']),
"date_added" => htmlspecialchars($row['date_added']),
"client" => htmlspecialchars($row['client']),
"days_on_list" => $doty, //date_added to now
);
$i = $i + 1; //add next row
}
//encoding the PHP array
$json_server_pagination_data = array(
"total" => intval($num_rows),
"rows" => $cart, //array data
);
}
echo json_encode($json_server_pagination_data);
Because days_on_list is calculated by simply comparing date_added to the current date, sorting by days_on_list should have exactly the reverse effect as sorting by date_added.
In other words, you don't actually need to sort by days_on_list. If the user selects days_on_list as the sort column, just use ORDER BY date_added (in the opposite direction ASC/DESC).

ORM Mapping two tables with PHP

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.

cakephp price check

I have a matrix of inputs boxes which contain prices for dates. If there is no price in the database for a particular date the input box displays 0. I have the following code which saves into the database the prices typed into the input boxes. It does not save all the 0 values only the new prices.
Which is fine. However I have now discovered an issue. If one of the inputs dislays a value from the database, say $10 and I want to set it now to 0, the code will not do it.
It will only save if the values and above 0. I have not been able to do this final check.
The conditions for saving are
1. If the value is numeric
2. If it is 0 and already has an entry in the database then save
3. If it has no value in the database and is greater than 0
4. If it is 0 and has no value in the database then do not save
if (isset($this->data['Rate'])){
// for each rate
foreach($this->data['Rate'] as $rate_id => $room){
// for each room type
foreach($room as $room_id => $room){
$price_for_today = isset($room['Price'][$key]) ? $room['Price'][$key] : 0;
// get existing availabilities is num (get this from previous date loop)
$today = ''.$date.' 00:00:00';
$conditions = array('Availability.date' => $today,'Availability.room_id'=>$room_id);
$this->Availability->contain();
$result = $this->Availability->find('all',array('order'=>'Availability.room_id ASC', 'conditions'=>$conditions));
$avail_id = $result[0]['Availability']['id'];
// check prices
$check_prices = "SELECT * FROM prices
WHERE rate_id = '".$rate_id."' AND availability_id = '".$avail_id."'";
$prices_result = $this->Availability->query($check_prices);
// if new prices > 0.00
if($price_for_today>0 && is_numeric($price_for_today)){
// better checking needed!
if($prices_result){
$setprices = "UPDATE prices SET price = '".$price_for_today."'
WHERE rate_id = '".$rate_id."' AND availability_id = '".$avail_id."'";
$update = $this->Availability->query($setprices);
} else {
$setprices = "INSERT INTO prices (price, availability_id, rate_id)
VALUES ('".$price_for_today."', '".$avail_id."', '".$rate_id."')";
$insert = $this->Availability->query($setprices);
}
}
//$errors[] = $setprices;
} // end rooms loop
} // end Rates loop
Your problem is in
> // if new prices > 0.00
> if($price_for_today>0 &&
> is_numeric($price_for_today)){
here you specify that $prices_for_today have to be >0, so if you had a price and want to put it 0 today then you will not do anything... You should use
if(($price_for_today>0 && is_numeric($price_for_today)) || (!empty($prices_result) && $price_for_today==0 && is_numeric($price_for_today))){
if you change it it will now enter in the if and do the change.
I sugest that you do NOT use the query function unless is extremely necesary. you should create a model for price (if you haven't done that already) and then use the associations (hasMany, HasOne, HABTM) or load the model directly in the controller with $this->loadModel('Price'). Then use a find 'all' as always with conditions and fields. This recomendation is to use cake as it was intended, not indispensable. Also the save, updatefield, read can be done if you do this... leaving the checks and everything to cake.

Google analytics api. To sort result while in the loop

i need help with google analytics gapi class with php. (http://code.google.com/p/gapi-google-analytics-php-interface)
I want to output how many times each item in catalog was viewed. The page for the item generates with id for example:
/item.php?id=1
/item.php?id=2
ect.
So everything goes right with my code until i want to order by the most viewed item, since i am using loop, to generate random filters:
$filter = "pagePath == /item.php?id=".$i++."";
I am not able to use sort in gapi "requestReportData".
With the code shown below everyting outputs right, but i don't know how to sort everything so it will shown results from the most viewed item till least.
The code:
$ga = new gapi(ga_email,ga_password);
$dimensions = array('pagePath');
$metrics = array('pageviews');
$termFrom = 2011-06-01;
$termUntil = 2011-06-30;
echo '<strong>ITEMS VIEW STATISTIC</strong><br />';
for ( $i='1'; $i<'20';)
{
$filter = "pagePath == /item.php?id=".$i++."";
$ga->requestReportData(table_id,$dimensions,$metrics,'-pageviews',$filter, $termFrom, $termUntil);
foreach($ga->getResults() as $result)
{ $j= $i-1; $b=$j-1;
echo $z++.') Items which ID is:'.$j++.' and NAME is: '.$ItemsNamesArray[$b]['item_name'].' was viewed: '.$result->getpageviews() . ' times<br />';
}
}
It outputs:
ITEMS VIEW STATISTIC
1) Items which ID is:1 and NAME is:
Book was viewed: 9 times
2) Items which ID is:2 and NAME is:
Box: 1 times
3) Items which ID is:3 and NAME is:
Table: 3 times
4) Items which ID is:4 and NAME is:
House: 27 times
I want it to output:
ITEMS VIEW STATISTIC
1) Items which ID is:4 and NAME is:
House was viewed: 27 times
2) Items which ID is:1 and NAME is:
Book was viewed: 9 times
3) Items which ID is:3 and NAME is:
Table was viewed: 3 times
4) Items which ID is:2 and NAME is:
Box was viewed: 1 times
You can use regular expressions for filters to get all your twenty items at once and have Google Analytics sort them:
$ga = new gapi(ga_email,ga_password);
$dimensions = array('pagePath');
$metrics = array('pageviews');
$termFrom = '2011-06-01';
$termUntil = '2011-06-30';
$filter = 'pagePath=~/item\.php\?id=[0-9]*' // Matches all item URLs
$sort = '-pageviews'; // Sorted by desc. pageview count
$maxResults = 20; // First 20 entries
$ga->requestReportData(table_id, $dimensions, $metrics, $sort, $filter, $termFrom, $termUntil, 1, $maxResults);
foreach($ga->getResults as $i => $result){
// Do your magic for each item
}
This is untested, the regular expression in the filter should match correctly, though.
I assumed you want the twenty most-viewed item URLs.

How to create php array from mysql result, perform calculation, resort array, present results

I have a photo website on which I am trying to perform a query against a MySQL database. The query is against a concatenated field of 'title' and 'keyword' called 'title_keyword'.
I want to take the search results and sort them by a newly formed variable called 'sort_priority' which is checking to see if the search word is in the 'title' field. If it is in the 'title' field then I want to assign a value of 1 and if not in the title field then a value of 2. The resulting array will be sorted by 'sort_priority' and output to the screen.
Here is the logic I am using with PHP and MySQL:
1) Query the MySQL database and assign variables. (This works just fine)
2) Take the results, assign each field to a variable, create a new variable that performs a calculation on one of the variables returned
$data_array=array();
// get each row
while($row = mysql_fetch_array($result))
{
//get data
$image_id = "{$row['image_id']}";
$title = "{$row['title']}";
$imageurl = "{$row['imageurl']}";
// Create sort_priority to identify if search word is in title field.
//If it is then set to 1 to force this higher in the result list after sorting
$sort_priority = 2;
if(stristr($title,$search))
{ $sort_priority = 1;}
Everything above this point works. Now for the part I'm stumped on. How to create and add data to the array and then sort on my new $sort_priority variable.
Here is what I've written but it just doesn't work**
// Create array and sort by title then keyword (tk_sort)
$data_array = array(
'image_id' => $image_id,
'title' => $title,
'imageurl' => $imageurl,
'sort_priority' => $sort_priority);
// Obtain a list of columns
foreach ($data_array as $key => $row) {
$image_id[$key] = $row['image_id'];
$title[$key] = $row['atitle'];
$imageurl[$key] = $row['imageurl'];
$sort_priority[$key] = $row['sort_priority'];
}
// Sort the data with volume descending, edition ascending
// Add $data as the last parameter, to sort by the common key
array_multisort($sort_priority, SORT_ASC);
// end of array creation and sort
3) Output the newly sorted array to a table
Not sure how to get the data out of it. Do I have to use a loop or something?
You could just let MySQL do the majority of the work. This should work (haven't tried it myself):
SELECT CONCAT_WS('-', `title`, `keyword`) AS search_term,
IF( INSTR(`search_term`, 'your_search_value_here') > 0, 1, 2 ) AS priority_key,
`image_id`, `imageurl`
FROM table_name_here
ORDER BY `priority_key`;
HTH.

Categories